sendou.ink/app/modules/brackets-manager/test/single-elimination.test.ts

343 lines
9.0 KiB
TypeScript

import { InMemoryDatabase } from "~/modules/brackets-memory-db";
import { BracketsManager } from "../manager";
import { suite } from "uvu";
import * as assert from "uvu/assert";
import { Status } from "~/db/types";
const storage = new InMemoryDatabase();
const manager = new BracketsManager(storage);
const CreateSingleEliminationStage = suite("Create single elimination stage");
CreateSingleEliminationStage.before.each(() => {
storage.reset();
});
CreateSingleEliminationStage("should create a single elimination stage", () => {
const example = {
name: "Example",
tournamentId: 0,
type: "single_elimination",
seeding: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
settings: { seedOrdering: ["natural"] },
} as any;
manager.create(example);
const stage = storage.select<any>("stage", 0);
assert.equal(stage.name, example.name);
assert.equal(stage.type, example.type);
assert.equal(storage.select<any>("group")!.length, 1);
assert.equal(storage.select<any>("round")!.length, 4);
assert.equal(storage.select<any>("match")!.length, 15);
});
CreateSingleEliminationStage(
"should create a single elimination stage with BYEs",
() => {
manager.create({
name: "Example with BYEs",
tournamentId: 0,
type: "single_elimination",
seeding: [1, null, 3, 4, null, null, 7, 8],
settings: { seedOrdering: ["natural"] },
});
assert.equal(storage.select<any>("match", 4).opponent1.id, 1); // Determined because of opponent's BYE.
assert.equal(storage.select<any>("match", 4).opponent2.id, null); // To be determined.
assert.equal(storage.select<any>("match", 5).opponent1, null); // BYE propagated.
assert.equal(storage.select<any>("match", 5).opponent2.id, null); // To be determined.
},
);
CreateSingleEliminationStage(
"should create a single elimination stage with consolation final",
() => {
manager.create({
name: "Example with consolation final",
tournamentId: 0,
type: "single_elimination",
seeding: [1, 2, 3, 4, 5, 6, 7, 8],
settings: { consolationFinal: true, seedOrdering: ["natural"] },
});
assert.equal(storage.select<any>("group")!.length, 2);
assert.equal(storage.select<any>("round")!.length, 4);
assert.equal(storage.select<any>("match")!.length, 8);
},
);
CreateSingleEliminationStage(
"should create a single elimination stage with consolation final and BYEs",
() => {
manager.create({
name: "Example with consolation final and BYEs",
tournamentId: 0,
type: "single_elimination",
seeding: [null, null, null, 4, 5, 6, 7, 8],
settings: { consolationFinal: true, seedOrdering: ["natural"] },
});
assert.equal(storage.select<any>("match", 4).opponent1, null);
assert.equal(storage.select<any>("match", 4).opponent2.id, 4);
// Consolation final
assert.equal(storage.select<any>("match", 7).opponent1, null);
assert.equal(storage.select<any>("match", 7).opponent2.id, null);
},
);
CreateSingleEliminationStage(
"should create a single elimination stage with Bo3 matches",
() => {
manager.create({
name: "Example with Bo3 matches",
tournamentId: 0,
type: "single_elimination",
seeding: [1, 2, 3, 4, 5, 6, 7, 8],
settings: { seedOrdering: ["natural"] },
});
assert.equal(storage.select<any>("group")!.length, 1);
assert.equal(storage.select<any>("round")!.length, 3);
assert.equal(storage.select<any>("match")!.length, 7);
},
);
CreateSingleEliminationStage(
"should determine the number property of created stages",
() => {
manager.create({
name: "Stage 1",
tournamentId: 0,
type: "single_elimination",
settings: { size: 2 },
});
assert.equal(storage.select<any>("stage", 0).number, 1);
manager.create({
name: "Stage 2",
tournamentId: 0,
type: "single_elimination",
settings: { size: 2 },
});
assert.equal(storage.select<any>("stage", 1).number, 2);
manager.delete.stage(0);
manager.create({
name: "Stage 3",
tournamentId: 0,
type: "single_elimination",
settings: { size: 2 },
});
assert.equal(storage.select<any>("stage", 2).number, 3);
},
);
CreateSingleEliminationStage(
"should create a stage with the given number property",
() => {
manager.create({
name: "Stage 1",
tournamentId: 0,
type: "single_elimination",
settings: { size: 2 },
});
manager.create({
name: "Stage 2",
tournamentId: 0,
type: "single_elimination",
settings: { size: 2 },
});
manager.delete.stage(0);
manager.create({
name: "Stage 1 (new)",
tournamentId: 0,
type: "single_elimination",
number: 1,
settings: { size: 2 },
});
assert.equal(storage.select<any>("stage", 2).number, 1);
},
);
CreateSingleEliminationStage(
"should throw if the given number property already exists",
() => {
manager.create({
name: "Stage 1",
tournamentId: 0,
type: "single_elimination",
number: 1,
settings: { size: 2 },
});
assert.throws(
() =>
manager.create({
name: "Stage 1",
tournamentId: 0,
type: "single_elimination",
number: 1, // Duplicate
settings: { size: 2 },
}),
"The given stage number already exists.",
);
},
);
CreateSingleEliminationStage(
"should throw if the seeding has duplicate participants",
() => {
assert.throws(
() =>
manager.create({
name: "Example",
tournamentId: 0,
type: "single_elimination",
seeding: [
1,
1, // Duplicate
3,
4,
],
}),
"The seeding has a duplicate participant.",
);
},
);
CreateSingleEliminationStage(
"should throw if trying to set a draw as a result",
() => {
manager.create({
name: "Example",
tournamentId: 0,
type: "single_elimination",
seeding: [1, 2, 3, 4],
});
assert.throws(
() =>
manager.update.match({
id: 0,
opponent1: { result: "draw" },
}),
"Having a draw is forbidden in an elimination tournament.",
);
},
);
const PreviousAndNextMatchUpdate = suite("Previous and next match update");
PreviousAndNextMatchUpdate.before.each(() => {
storage.reset();
});
PreviousAndNextMatchUpdate(
"should determine matches in consolation final",
() => {
manager.create({
name: "Example",
tournamentId: 0,
type: "single_elimination",
seeding: [1, 2, 3, 4],
settings: { consolationFinal: true },
});
manager.update.match({
id: 0, // First match of round 1
opponent1: { score: 16, result: "win" },
opponent2: { score: 12 },
});
manager.update.match({
id: 1, // Second match of round 1
opponent1: { score: 13 },
opponent2: { score: 16, result: "win" },
});
assert.equal(
storage.select<any>("match", 3).opponent1.id, // Determined opponent for the consolation final
storage.select<any>("match", 0).opponent2.id, // Loser of Semi 1
);
assert.equal(
storage.select<any>("match", 3).opponent2.id, // Determined opponent for the consolation final
storage.select<any>("match", 1).opponent1.id, // Loser of Semi 2
);
assert.equal(storage.select<any>("match", 2).status, Status.Ready);
assert.equal(storage.select<any>("match", 3).status, Status.Ready);
},
);
PreviousAndNextMatchUpdate(
"should play both the final and consolation final in parallel",
() => {
manager.create({
name: "Example",
tournamentId: 0,
type: "single_elimination",
seeding: [1, 2, 3, 4],
settings: { consolationFinal: true },
});
manager.update.match({
id: 0, // First match of round 1
opponent1: { score: 16, result: "win" },
opponent2: { score: 12 },
});
manager.update.match({
id: 1, // Second match of round 1
opponent1: { score: 13 },
opponent2: { score: 16, result: "win" },
});
manager.update.match({
id: 2, // Final
opponent1: { score: 12 },
opponent2: { score: 9 },
});
assert.equal(storage.select<any>("match", 2).status, Status.Running);
assert.equal(storage.select<any>("match", 3).status, Status.Ready);
manager.update.match({
id: 3, // Consolation final
opponent1: { score: 12 },
opponent2: { score: 9 },
});
assert.equal(storage.select<any>("match", 2).status, Status.Running);
assert.equal(storage.select<any>("match", 3).status, Status.Running);
manager.update.match({
id: 3, // Consolation final
opponent1: { score: 16, result: "win" },
opponent2: { score: 9 },
});
assert.equal(storage.select<any>("match", 2).status, Status.Running);
manager.update.match({
id: 2, // Final
opponent1: { score: 16, result: "win" },
opponent2: { score: 9 },
});
},
);
CreateSingleEliminationStage.run();
PreviousAndNextMatchUpdate.run();