parent
b582f6c118
commit
b47cfb8916
@ -1,63 +1,112 @@ |
|||||||
import t, { type Test } from "tap"; |
import t, { type Test } from "tap"; |
||||||
|
|
||||||
import { Board } from "./board.ts"; |
import { Board } from "./board.ts"; |
||||||
import { SquareState } from "./types.js"; |
import { SquareState } from "./types.ts"; |
||||||
|
|
||||||
const createAndCheckBoard = (t: Test, serialized: string) => { |
|
||||||
const board = new Board(serialized); |
|
||||||
t.equal(board.serialize(), serialized); |
|
||||||
return board; |
|
||||||
}; |
|
||||||
|
|
||||||
void t.test("0x0 board", async (t) => { |
|
||||||
const board = createAndCheckBoard(t, ""); |
|
||||||
t.throws(() => board.get(0, 0), { message: "Out of bounds: 0:0" }); |
|
||||||
t.throws(() => board.get(0, 1), { message: "Out of bounds: 0:1" }); |
|
||||||
t.throws(() => board.get(1, 0), { message: "Out of bounds: 1:0" }); |
|
||||||
t.throws(() => board.get(1, 1), { message: "Out of bounds: 1:1" }); |
|
||||||
}); |
|
||||||
|
|
||||||
void t.test("Empty 1x1 board", async (t) => { |
void t.test("Serialize / deserialize", async (t) => { |
||||||
const board = createAndCheckBoard(t, "_"); |
const createAndCheckBoard = (t: Test, serialized: string) => { |
||||||
t.equal(board.get(0, 0), SquareState.Unoccupied); |
const board = Board.fromSerialized(serialized); |
||||||
t.throws(() => board.get(0, 1), { message: "Out of bounds: 0:1" }); |
t.equal(board.serialize(), serialized); |
||||||
t.throws(() => board.get(1, 0), { message: "Out of bounds: 1:0" }); |
return board; |
||||||
t.throws(() => board.get(1, 1), { message: "Out of bounds: 1:1" }); |
}; |
||||||
}); |
|
||||||
|
|
||||||
void t.test("1x1 board with X", async (t) => { |
void t.test("0x0 board", async (t) => { |
||||||
const board = createAndCheckBoard(t, "X"); |
const board = createAndCheckBoard(t, ""); |
||||||
t.equal(board.get(0, 0), SquareState.X); |
t.throws(() => board.get(0, 0), { message: "Out of bounds: 0:0" }); |
||||||
t.throws(() => board.get(0, 1), { message: "Out of bounds: 0:1" }); |
t.throws(() => board.get(0, 1), { message: "Out of bounds: 0:1" }); |
||||||
t.throws(() => board.get(1, 0), { message: "Out of bounds: 1:0" }); |
t.throws(() => board.get(1, 0), { message: "Out of bounds: 1:0" }); |
||||||
t.throws(() => board.get(1, 1), { message: "Out of bounds: 1:1" }); |
t.throws(() => board.get(1, 1), { message: "Out of bounds: 1:1" }); |
||||||
}); |
}); |
||||||
|
|
||||||
|
void t.test("Empty 1x1 board", async (t) => { |
||||||
|
const board = createAndCheckBoard(t, "_"); |
||||||
|
t.equal(board.get(0, 0), SquareState.Unoccupied); |
||||||
|
t.throws(() => board.get(0, 1), { message: "Out of bounds: 0:1" }); |
||||||
|
t.throws(() => board.get(1, 0), { message: "Out of bounds: 1:0" }); |
||||||
|
t.throws(() => board.get(1, 1), { message: "Out of bounds: 1:1" }); |
||||||
|
}); |
||||||
|
|
||||||
|
void t.test("1x1 board with X", async (t) => { |
||||||
|
const board = createAndCheckBoard(t, "X"); |
||||||
|
t.equal(board.get(0, 0), SquareState.X); |
||||||
|
t.throws(() => board.get(0, 1), { message: "Out of bounds: 0:1" }); |
||||||
|
t.throws(() => board.get(1, 0), { message: "Out of bounds: 1:0" }); |
||||||
|
t.throws(() => board.get(1, 1), { message: "Out of bounds: 1:1" }); |
||||||
|
}); |
||||||
|
|
||||||
|
void t.test("Half-full 3x4 board", async (t) => { |
||||||
|
const board = createAndCheckBoard(t, "XO_|O_X|OX_|_XO"); |
||||||
|
t.equal(board.get(0, 0), SquareState.X); |
||||||
|
t.equal(board.get(0, 1), SquareState.O); |
||||||
|
t.equal(board.get(0, 2), SquareState.Unoccupied); |
||||||
|
t.throws(() => board.get(0, 3), { message: "Out of bounds: 0:3" }); |
||||||
|
t.equal(board.get(1, 0), SquareState.O); |
||||||
|
t.equal(board.get(1, 1), SquareState.Unoccupied); |
||||||
|
t.equal(board.get(1, 2), SquareState.X); |
||||||
|
t.throws(() => board.get(1, 3), { message: "Out of bounds: 1:3" }); |
||||||
|
t.equal(board.get(2, 0), SquareState.O); |
||||||
|
t.equal(board.get(2, 1), SquareState.X); |
||||||
|
t.equal(board.get(2, 2), SquareState.Unoccupied); |
||||||
|
t.throws(() => board.get(2, 3), { message: "Out of bounds: 2:3" }); |
||||||
|
t.equal(board.get(3, 0), SquareState.Unoccupied); |
||||||
|
t.equal(board.get(3, 1), SquareState.X); |
||||||
|
t.equal(board.get(3, 2), SquareState.O); |
||||||
|
t.throws(() => board.get(3, 3), { message: "Out of bounds: 3:3" }); |
||||||
|
t.throws(() => board.get(4, 0), { message: "Out of bounds: 4:0" }); |
||||||
|
t.throws(() => board.get(4, 1), { message: "Out of bounds: 4:1" }); |
||||||
|
t.throws(() => board.get(4, 2), { message: "Out of bounds: 4:2" }); |
||||||
|
t.throws(() => board.get(4, 3), { message: "Out of bounds: 4:3" }); |
||||||
|
}); |
||||||
|
|
||||||
void t.test("Half-full 3x4 board", async (t) => { |
void t.test("Validation", async (t) => { |
||||||
const board = createAndCheckBoard(t, "XO_|O_X|OX_|_XO"); |
t.throws(() => Board.fromSerialized("abc"), { |
||||||
t.equal(board.get(0, 0), SquareState.X); |
message: "Unsupported square character: a", |
||||||
t.equal(board.get(0, 1), SquareState.O); |
}); |
||||||
t.equal(board.get(0, 2), SquareState.Unoccupied); |
|
||||||
t.throws(() => board.get(0, 3), { message: "Out of bounds: 0:3" }); |
{ |
||||||
t.equal(board.get(1, 0), SquareState.O); |
const board = new Board([[undefined as unknown as SquareState]]); |
||||||
t.equal(board.get(1, 1), SquareState.Unoccupied); |
t.throws(() => board.serialize(), { |
||||||
t.equal(board.get(1, 2), SquareState.X); |
message: "Unsupported square state: undefined", |
||||||
t.throws(() => board.get(1, 3), { message: "Out of bounds: 1:3" }); |
}); |
||||||
t.equal(board.get(2, 0), SquareState.O); |
} |
||||||
t.equal(board.get(2, 1), SquareState.X); |
|
||||||
t.equal(board.get(2, 2), SquareState.Unoccupied); |
{ |
||||||
t.throws(() => board.get(2, 3), { message: "Out of bounds: 2:3" }); |
const board = new Board([["test" as unknown as SquareState]]); |
||||||
t.equal(board.get(3, 0), SquareState.Unoccupied); |
t.throws(() => board.serialize(), { |
||||||
t.equal(board.get(3, 1), SquareState.X); |
message: "Unsupported square state: test", |
||||||
t.equal(board.get(3, 2), SquareState.O); |
}); |
||||||
t.throws(() => board.get(3, 3), { message: "Out of bounds: 3:3" }); |
} |
||||||
t.throws(() => board.get(4, 0), { message: "Out of bounds: 4:0" }); |
}); |
||||||
t.throws(() => board.get(4, 1), { message: "Out of bounds: 4:1" }); |
|
||||||
t.throws(() => board.get(4, 2), { message: "Out of bounds: 4:2" }); |
|
||||||
t.throws(() => board.get(4, 3), { message: "Out of bounds: 4:3" }); |
|
||||||
}); |
}); |
||||||
|
|
||||||
void t.test("Throws error on incorrect serialized value", async (t) => { |
void t.test("Derived boards creation", async (t) => { |
||||||
t.throws(() => new Board("abc"), { |
const board = Board.fromSerialized("_X|O_|_O"); |
||||||
message: "Unsupported square character: a", |
|
||||||
|
t.equal(board.with(0, 0, SquareState.Unoccupied).serialize(), "_X|O_|_O"); |
||||||
|
t.equal(board.with(0, 0, SquareState.O).serialize(), "OX|O_|_O"); |
||||||
|
t.equal(board.with(0, 0, SquareState.X).serialize(), "XX|O_|_O"); |
||||||
|
|
||||||
|
t.throws(() => board.with(0, 1, SquareState.X), { |
||||||
|
message: "Cannot update occupied square: 0:1", |
||||||
|
}); |
||||||
|
t.throws(() => board.with(0, 2, SquareState.X), { |
||||||
|
message: "Out of bounds: 0:2", |
||||||
|
}); |
||||||
|
t.throws(() => board.with(1, 0, SquareState.X), { |
||||||
|
message: "Cannot update occupied square: 1:0", |
||||||
|
}); |
||||||
|
t.equal(board.with(1, 1, SquareState.X).serialize(), "_X|OX|_O"); |
||||||
|
t.throws(() => board.with(1, 2, SquareState.X), { |
||||||
|
message: "Out of bounds: 1:2", |
||||||
|
}); |
||||||
|
t.equal(board.with(2, 0, SquareState.X).serialize(), "_X|O_|XX"); |
||||||
|
t.throws(() => board.with(2, 1, SquareState.X), { |
||||||
|
message: "Cannot update occupied square: 2:1", |
||||||
|
}); |
||||||
|
t.throws(() => board.with(2, 2, SquareState.X), { |
||||||
|
message: "Out of bounds: 2:2", |
||||||
|
}); |
||||||
|
t.throws(() => board.with(3, 0, SquareState.X), { |
||||||
|
message: "Out of bounds: 3:0", |
||||||
}); |
}); |
||||||
}); |
}); |
||||||
|
Loading…
Reference in new issue