parent
b582f6c118
commit
b47cfb8916
@ -1,63 +1,112 @@ |
||||
import t, { type Test } from "tap"; |
||||
|
||||
import { Board } from "./board.ts"; |
||||
import { SquareState } from "./types.js"; |
||||
|
||||
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" }); |
||||
}); |
||||
import { SquareState } from "./types.ts"; |
||||
|
||||
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("Serialize / deserialize", async (t) => { |
||||
const createAndCheckBoard = (t: Test, serialized: string) => { |
||||
const board = Board.fromSerialized(serialized); |
||||
t.equal(board.serialize(), serialized); |
||||
return board; |
||||
}; |
||||
|
||||
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("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) => { |
||||
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) => { |
||||
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("Validation", async (t) => { |
||||
t.throws(() => Board.fromSerialized("abc"), { |
||||
message: "Unsupported square character: a", |
||||
}); |
||||
|
||||
{ |
||||
const board = new Board([[undefined as unknown as SquareState]]); |
||||
t.throws(() => board.serialize(), { |
||||
message: "Unsupported square state: undefined", |
||||
}); |
||||
} |
||||
|
||||
{ |
||||
const board = new Board([["test" as unknown as SquareState]]); |
||||
t.throws(() => board.serialize(), { |
||||
message: "Unsupported square state: test", |
||||
}); |
||||
} |
||||
}); |
||||
}); |
||||
|
||||
void t.test("Throws error on incorrect serialized value", async (t) => { |
||||
t.throws(() => new Board("abc"), { |
||||
message: "Unsupported square character: a", |
||||
void t.test("Derived boards creation", async (t) => { |
||||
const board = Board.fromSerialized("_X|O_|_O"); |
||||
|
||||
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