From 299aa09bf3761256b8ccc2d03d011a4d6375bca8 Mon Sep 17 00:00:00 2001 From: "Benjamin P. Jones" Date: Sat, 8 Nov 2025 21:38:57 -0500 Subject: [PATCH] Add infra for SGF/GIB snapshot tests --- .../fixtures/README.md | 64 + .../fixtures/fox_9x9.sgf | 10 + .../fixtures/ogs_9x9.sgf | 38 + .../fixtures/snapshots/fox_9x9_sgf.json | 185 +++ .../fixtures/snapshots/ogs_9x9_sgf.json | 115 ++ .../fixtures/snapshots/tygem_19x19_gib.json | 1450 +++++++++++++++++ .../fixtures/tygem_19x19.gib | Bin 0 -> 5382 bytes .../game_record_snapshot_test.dart | 88 + .../generate_snapshots.dart | 62 + .../snapshot_utils.dart | 32 + 10 files changed, 2044 insertions(+) create mode 100644 test/game_record_snapshot_tests/fixtures/README.md create mode 100644 test/game_record_snapshot_tests/fixtures/fox_9x9.sgf create mode 100644 test/game_record_snapshot_tests/fixtures/ogs_9x9.sgf create mode 100644 test/game_record_snapshot_tests/fixtures/snapshots/fox_9x9_sgf.json create mode 100644 test/game_record_snapshot_tests/fixtures/snapshots/ogs_9x9_sgf.json create mode 100644 test/game_record_snapshot_tests/fixtures/snapshots/tygem_19x19_gib.json create mode 100644 test/game_record_snapshot_tests/fixtures/tygem_19x19.gib create mode 100644 test/game_record_snapshot_tests/game_record_snapshot_test.dart create mode 100644 test/game_record_snapshot_tests/generate_snapshots.dart create mode 100644 test/game_record_snapshot_tests/snapshot_utils.dart diff --git a/test/game_record_snapshot_tests/fixtures/README.md b/test/game_record_snapshot_tests/fixtures/README.md new file mode 100644 index 00000000..5308f33b --- /dev/null +++ b/test/game_record_snapshot_tests/fixtures/README.md @@ -0,0 +1,64 @@ +# GameRecord Snapshot Tests + +This directory contains snapshot tests for `GameRecord.fromSgf` and `GameRecord.fromGib` methods. + +## How It Works + +The tests automatically discover all `.sgf` and `.gib` files in the `fixtures/` directory and validate them against their corresponding snapshot JSON files. **No need to write new test cases** - just add your file and regenerate snapshots! + +## Structure + +- `fixtures/` - Test data files + - `*.sgf` - Sample SGF game files + - `*.gib` - Sample GIB game files + - `snapshots/` - Expected output JSON files for comparison + +## Running Tests + +Run all snapshot tests: +```bash +flutter test test/game_record_snapshot_tests/ +``` + +Or run all tests: +```bash +flutter test +``` + +## Regenerating Snapshots + +If you modify the `GameRecord` parsing logic or want to update the expected outputs: + +```bash +dart run test/game_record_snapshot_tests/generate_snapshots.dart +``` + +The generator automatically discovers all `.sgf` and `.gib` files in the fixtures directory. + +This will regenerate all snapshot JSON files in `fixtures/snapshots/`. + +## Snapshot Format + +Each snapshot is a JSON file containing: +```json +{ + "type": "GameRecordType.sgf", + "moveCount": 14, + "moves": [ + { + "color": "B", // "B" for black, "W" for white + "row": 4, + "col": 4 + }, + ... + ] +} +``` + +## Adding New Test Cases + +1. Add a new `.sgf` or `.gib` file to `test/game_record_snapshot_tests/fixtures/` +2. Run the generator: `dart run test/game_record_snapshot_tests/generate_snapshots.dart` +3. Run tests to verify: `flutter test test/game_record_snapshot_tests/` + +**That's it!** The test framework automatically discovers and tests your new file. diff --git a/test/game_record_snapshot_tests/fixtures/fox_9x9.sgf b/test/game_record_snapshot_tests/fixtures/fox_9x9.sgf new file mode 100644 index 00000000..868d4dad --- /dev/null +++ b/test/game_record_snapshot_tests/fixtures/fox_9x9.sgf @@ -0,0 +1,10 @@ +(;GM[1]FF[4] +SZ[9] +GN[] +DT[2025-09-16] +PB[benjito] +PW[V291851863] +BR[1级] +WR[1级] +KM[375]HA[0]RU[Chinese]AP[GNU Go:3.8]RN[12]RE[W+4.25]TM[60]TC[3]TT[20]AP[foxwq]RL[0] +;B[ge];W[de];B[ef];W[df];B[dg];W[ee];B[ff];W[cg];B[fc];W[dh];B[eh];W[eg];B[fg];W[dc];B[eb];W[db];B[da];W[ec];B[fb];W[ca];B[dg];W[fd];B[gd];W[eg];B[cb];W[ea];B[dg];W[ch];B[fa];W[da];B[fe];W[ed];B[eg];W[ei];B[fi];W[di]) \ No newline at end of file diff --git a/test/game_record_snapshot_tests/fixtures/ogs_9x9.sgf b/test/game_record_snapshot_tests/fixtures/ogs_9x9.sgf new file mode 100644 index 00000000..40989607 --- /dev/null +++ b/test/game_record_snapshot_tests/fixtures/ogs_9x9.sgf @@ -0,0 +1,38 @@ +(;FF[4] +CA[UTF-8] +GM[1] +DT[2025-11-08] +PC[OGS: https://online-go.com/game/19728] +GN[asdfg vs. asdf] +PB[asdfg] +PW[asdf] +BR[9k] +WR[10k] +TM[120]OT[5x30 byo-yomi] +RE[B+2.5] +SZ[9] +KM[6.5] +RU[Japanese] +;B[ea] +(;W[fa] +(;B[eb] +(;W[fb] +(;B[ec] +(;W[fc] +(;B[ed] +(;W[fd] +(;B[ee] +(;W[fe] +(;B[ef] +(;W[ff] +(;B[eg] +(;W[fg] +(;B[eh] +(;W[fh] +(;B[ei] +(;W[fi] +(;B[hh] +(;W[hf] +(;B[] +(;W[] +)))))))))))))))))))))) \ No newline at end of file diff --git a/test/game_record_snapshot_tests/fixtures/snapshots/fox_9x9_sgf.json b/test/game_record_snapshot_tests/fixtures/snapshots/fox_9x9_sgf.json new file mode 100644 index 00000000..c4233576 --- /dev/null +++ b/test/game_record_snapshot_tests/fixtures/snapshots/fox_9x9_sgf.json @@ -0,0 +1,185 @@ +{ + "type": "GameRecordType.sgf", + "moves": [ + { + "color": "B", + "row": 4, + "col": 6 + }, + { + "color": "W", + "row": 4, + "col": 3 + }, + { + "color": "B", + "row": 5, + "col": 4 + }, + { + "color": "W", + "row": 5, + "col": 3 + }, + { + "color": "B", + "row": 6, + "col": 3 + }, + { + "color": "W", + "row": 4, + "col": 4 + }, + { + "color": "B", + "row": 5, + "col": 5 + }, + { + "color": "W", + "row": 6, + "col": 2 + }, + { + "color": "B", + "row": 2, + "col": 5 + }, + { + "color": "W", + "row": 7, + "col": 3 + }, + { + "color": "B", + "row": 7, + "col": 4 + }, + { + "color": "W", + "row": 6, + "col": 4 + }, + { + "color": "B", + "row": 6, + "col": 5 + }, + { + "color": "W", + "row": 2, + "col": 3 + }, + { + "color": "B", + "row": 1, + "col": 4 + }, + { + "color": "W", + "row": 1, + "col": 3 + }, + { + "color": "B", + "row": 0, + "col": 3 + }, + { + "color": "W", + "row": 2, + "col": 4 + }, + { + "color": "B", + "row": 1, + "col": 5 + }, + { + "color": "W", + "row": 0, + "col": 2 + }, + { + "color": "B", + "row": 6, + "col": 3 + }, + { + "color": "W", + "row": 3, + "col": 5 + }, + { + "color": "B", + "row": 3, + "col": 6 + }, + { + "color": "W", + "row": 6, + "col": 4 + }, + { + "color": "B", + "row": 1, + "col": 2 + }, + { + "color": "W", + "row": 0, + "col": 4 + }, + { + "color": "B", + "row": 6, + "col": 3 + }, + { + "color": "W", + "row": 7, + "col": 2 + }, + { + "color": "B", + "row": 0, + "col": 5 + }, + { + "color": "W", + "row": 0, + "col": 3 + }, + { + "color": "B", + "row": 4, + "col": 5 + }, + { + "color": "W", + "row": 3, + "col": 4 + }, + { + "color": "B", + "row": 6, + "col": 4 + }, + { + "color": "W", + "row": 8, + "col": 4 + }, + { + "color": "B", + "row": 8, + "col": 5 + }, + { + "color": "W", + "row": 8, + "col": 3 + } + ] +} \ No newline at end of file diff --git a/test/game_record_snapshot_tests/fixtures/snapshots/ogs_9x9_sgf.json b/test/game_record_snapshot_tests/fixtures/snapshots/ogs_9x9_sgf.json new file mode 100644 index 00000000..d7fc7623 --- /dev/null +++ b/test/game_record_snapshot_tests/fixtures/snapshots/ogs_9x9_sgf.json @@ -0,0 +1,115 @@ +{ + "type": "GameRecordType.sgf", + "moves": [ + { + "color": "B", + "row": 0, + "col": 4 + }, + { + "color": "W", + "row": 0, + "col": 5 + }, + { + "color": "B", + "row": 1, + "col": 4 + }, + { + "color": "W", + "row": 1, + "col": 5 + }, + { + "color": "B", + "row": 2, + "col": 4 + }, + { + "color": "W", + "row": 2, + "col": 5 + }, + { + "color": "B", + "row": 3, + "col": 4 + }, + { + "color": "W", + "row": 3, + "col": 5 + }, + { + "color": "B", + "row": 4, + "col": 4 + }, + { + "color": "W", + "row": 4, + "col": 5 + }, + { + "color": "B", + "row": 5, + "col": 4 + }, + { + "color": "W", + "row": 5, + "col": 5 + }, + { + "color": "B", + "row": 6, + "col": 4 + }, + { + "color": "W", + "row": 6, + "col": 5 + }, + { + "color": "B", + "row": 7, + "col": 4 + }, + { + "color": "W", + "row": 7, + "col": 5 + }, + { + "color": "B", + "row": 8, + "col": 4 + }, + { + "color": "W", + "row": 8, + "col": 5 + }, + { + "color": "B", + "row": 7, + "col": 7 + }, + { + "color": "W", + "row": 5, + "col": 7 + }, + { + "color": "B", + "row": -1, + "col": -1 + }, + { + "color": "W", + "row": -1, + "col": -1 + } + ] +} \ No newline at end of file diff --git a/test/game_record_snapshot_tests/fixtures/snapshots/tygem_19x19_gib.json b/test/game_record_snapshot_tests/fixtures/snapshots/tygem_19x19_gib.json new file mode 100644 index 00000000..dda6dd93 --- /dev/null +++ b/test/game_record_snapshot_tests/fixtures/snapshots/tygem_19x19_gib.json @@ -0,0 +1,1450 @@ +{ + "type": "GameRecordType.gib", + "moves": [ + { + "color": "B", + "row": 15, + "col": 15 + }, + { + "color": "W", + "row": 15, + "col": 3 + }, + { + "color": "B", + "row": 3, + "col": 15 + }, + { + "color": "W", + "row": 3, + "col": 3 + }, + { + "color": "B", + "row": 16, + "col": 5 + }, + { + "color": "W", + "row": 16, + "col": 4 + }, + { + "color": "B", + "row": 15, + "col": 5 + }, + { + "color": "W", + "row": 13, + "col": 3 + }, + { + "color": "B", + "row": 15, + "col": 9 + }, + { + "color": "W", + "row": 16, + "col": 13 + }, + { + "color": "B", + "row": 13, + "col": 16 + }, + { + "color": "W", + "row": 15, + "col": 11 + }, + { + "color": "B", + "row": 16, + "col": 14 + }, + { + "color": "W", + "row": 17, + "col": 14 + }, + { + "color": "B", + "row": 17, + "col": 15 + }, + { + "color": "W", + "row": 15, + "col": 14 + }, + { + "color": "B", + "row": 16, + "col": 15 + }, + { + "color": "W", + "row": 17, + "col": 13 + }, + { + "color": "B", + "row": 2, + "col": 2 + }, + { + "color": "W", + "row": 3, + "col": 2 + }, + { + "color": "B", + "row": 2, + "col": 3 + }, + { + "color": "W", + "row": 5, + "col": 3 + }, + { + "color": "B", + "row": 2, + "col": 5 + }, + { + "color": "W", + "row": 9, + "col": 3 + }, + { + "color": "B", + "row": 2, + "col": 13 + }, + { + "color": "W", + "row": 5, + "col": 16 + }, + { + "color": "B", + "row": 4, + "col": 16 + }, + { + "color": "W", + "row": 7, + "col": 15 + }, + { + "color": "B", + "row": 9, + "col": 16 + }, + { + "color": "W", + "row": 9, + "col": 15 + }, + { + "color": "B", + "row": 10, + "col": 15 + }, + { + "color": "W", + "row": 8, + "col": 16 + }, + { + "color": "B", + "row": 9, + "col": 14 + }, + { + "color": "W", + "row": 9, + "col": 17 + }, + { + "color": "B", + "row": 8, + "col": 15 + }, + { + "color": "W", + "row": 10, + "col": 16 + }, + { + "color": "B", + "row": 9, + "col": 15 + }, + { + "color": "W", + "row": 7, + "col": 17 + }, + { + "color": "B", + "row": 10, + "col": 17 + }, + { + "color": "W", + "row": 11, + "col": 16 + }, + { + "color": "B", + "row": 11, + "col": 17 + }, + { + "color": "W", + "row": 12, + "col": 16 + }, + { + "color": "B", + "row": 12, + "col": 17 + }, + { + "color": "W", + "row": 12, + "col": 15 + }, + { + "color": "B", + "row": 13, + "col": 15 + }, + { + "color": "W", + "row": 12, + "col": 14 + }, + { + "color": "B", + "row": 7, + "col": 14 + }, + { + "color": "W", + "row": 6, + "col": 15 + }, + { + "color": "B", + "row": 6, + "col": 14 + }, + { + "color": "W", + "row": 5, + "col": 14 + }, + { + "color": "B", + "row": 13, + "col": 14 + }, + { + "color": "W", + "row": 12, + "col": 13 + }, + { + "color": "B", + "row": 13, + "col": 13 + }, + { + "color": "W", + "row": 12, + "col": 12 + }, + { + "color": "B", + "row": 13, + "col": 12 + }, + { + "color": "W", + "row": 13, + "col": 11 + }, + { + "color": "B", + "row": 12, + "col": 11 + }, + { + "color": "W", + "row": 11, + "col": 11 + }, + { + "color": "B", + "row": 12, + "col": 10 + }, + { + "color": "W", + "row": 10, + "col": 12 + }, + { + "color": "B", + "row": 6, + "col": 11 + }, + { + "color": "W", + "row": 15, + "col": 10 + }, + { + "color": "B", + "row": 13, + "col": 10 + }, + { + "color": "W", + "row": 14, + "col": 11 + }, + { + "color": "B", + "row": 16, + "col": 9 + }, + { + "color": "W", + "row": 16, + "col": 10 + }, + { + "color": "B", + "row": 14, + "col": 9 + }, + { + "color": "W", + "row": 11, + "col": 10 + }, + { + "color": "B", + "row": 9, + "col": 10 + }, + { + "color": "W", + "row": 9, + "col": 11 + }, + { + "color": "B", + "row": 8, + "col": 11 + }, + { + "color": "W", + "row": 8, + "col": 13 + }, + { + "color": "B", + "row": 8, + "col": 14 + }, + { + "color": "W", + "row": 8, + "col": 12 + }, + { + "color": "B", + "row": 7, + "col": 12 + }, + { + "color": "W", + "row": 8, + "col": 10 + }, + { + "color": "B", + "row": 7, + "col": 11 + }, + { + "color": "W", + "row": 9, + "col": 9 + }, + { + "color": "B", + "row": 5, + "col": 13 + }, + { + "color": "W", + "row": 4, + "col": 14 + }, + { + "color": "B", + "row": 9, + "col": 18 + }, + { + "color": "W", + "row": 8, + "col": 17 + }, + { + "color": "B", + "row": 4, + "col": 15 + }, + { + "color": "W", + "row": 5, + "col": 15 + }, + { + "color": "B", + "row": 6, + "col": 17 + }, + { + "color": "W", + "row": 5, + "col": 17 + }, + { + "color": "B", + "row": 7, + "col": 18 + }, + { + "color": "W", + "row": 4, + "col": 13 + }, + { + "color": "B", + "row": 5, + "col": 12 + }, + { + "color": "W", + "row": 4, + "col": 12 + }, + { + "color": "B", + "row": 4, + "col": 11 + }, + { + "color": "W", + "row": 3, + "col": 12 + }, + { + "color": "B", + "row": 2, + "col": 12 + }, + { + "color": "W", + "row": 3, + "col": 11 + }, + { + "color": "B", + "row": 4, + "col": 10 + }, + { + "color": "W", + "row": 3, + "col": 10 + }, + { + "color": "B", + "row": 1, + "col": 10 + }, + { + "color": "W", + "row": 2, + "col": 9 + }, + { + "color": "B", + "row": 4, + "col": 8 + }, + { + "color": "W", + "row": 4, + "col": 9 + }, + { + "color": "B", + "row": 5, + "col": 9 + }, + { + "color": "W", + "row": 3, + "col": 8 + }, + { + "color": "B", + "row": 3, + "col": 9 + }, + { + "color": "W", + "row": 3, + "col": 7 + }, + { + "color": "B", + "row": 4, + "col": 9 + }, + { + "color": "W", + "row": 2, + "col": 10 + }, + { + "color": "B", + "row": 1, + "col": 11 + }, + { + "color": "W", + "row": 4, + "col": 7 + }, + { + "color": "B", + "row": 8, + "col": 18 + }, + { + "color": "W", + "row": 7, + "col": 16 + }, + { + "color": "B", + "row": 4, + "col": 17 + }, + { + "color": "W", + "row": 4, + "col": 18 + }, + { + "color": "B", + "row": 4, + "col": 5 + }, + { + "color": "W", + "row": 5, + "col": 5 + }, + { + "color": "B", + "row": 5, + "col": 6 + }, + { + "color": "W", + "row": 3, + "col": 5 + }, + { + "color": "B", + "row": 3, + "col": 4 + }, + { + "color": "W", + "row": 4, + "col": 6 + }, + { + "color": "B", + "row": 3, + "col": 6 + }, + { + "color": "W", + "row": 5, + "col": 7 + }, + { + "color": "B", + "row": 6, + "col": 6 + }, + { + "color": "W", + "row": 6, + "col": 7 + }, + { + "color": "B", + "row": 7, + "col": 6 + }, + { + "color": "W", + "row": 7, + "col": 7 + }, + { + "color": "B", + "row": 5, + "col": 4 + }, + { + "color": "W", + "row": 6, + "col": 5 + }, + { + "color": "B", + "row": 6, + "col": 4 + }, + { + "color": "W", + "row": 7, + "col": 5 + }, + { + "color": "B", + "row": 8, + "col": 6 + }, + { + "color": "W", + "row": 8, + "col": 7 + }, + { + "color": "B", + "row": 9, + "col": 6 + }, + { + "color": "W", + "row": 8, + "col": 4 + }, + { + "color": "B", + "row": 9, + "col": 7 + }, + { + "color": "W", + "row": 8, + "col": 8 + }, + { + "color": "B", + "row": 12, + "col": 7 + }, + { + "color": "W", + "row": 11, + "col": 4 + }, + { + "color": "B", + "row": 7, + "col": 2 + }, + { + "color": "W", + "row": 7, + "col": 3 + }, + { + "color": "B", + "row": 6, + "col": 3 + }, + { + "color": "W", + "row": 8, + "col": 2 + }, + { + "color": "B", + "row": 7, + "col": 1 + }, + { + "color": "W", + "row": 8, + "col": 1 + }, + { + "color": "B", + "row": 5, + "col": 2 + }, + { + "color": "W", + "row": 4, + "col": 3 + }, + { + "color": "B", + "row": 4, + "col": 4 + }, + { + "color": "W", + "row": 2, + "col": 1 + }, + { + "color": "B", + "row": 1, + "col": 1 + }, + { + "color": "W", + "row": 4, + "col": 1 + }, + { + "color": "B", + "row": 5, + "col": 1 + }, + { + "color": "W", + "row": 7, + "col": 0 + }, + { + "color": "B", + "row": 6, + "col": 0 + }, + { + "color": "W", + "row": 8, + "col": 0 + }, + { + "color": "B", + "row": 7, + "col": 10 + }, + { + "color": "W", + "row": 10, + "col": 10 + }, + { + "color": "B", + "row": 17, + "col": 9 + }, + { + "color": "W", + "row": 17, + "col": 10 + }, + { + "color": "B", + "row": 15, + "col": 13 + }, + { + "color": "W", + "row": 15, + "col": 12 + }, + { + "color": "B", + "row": 14, + "col": 13 + }, + { + "color": "W", + "row": 17, + "col": 12 + }, + { + "color": "B", + "row": 3, + "col": 18 + }, + { + "color": "W", + "row": 5, + "col": 18 + }, + { + "color": "B", + "row": 2, + "col": 17 + }, + { + "color": "W", + "row": 3, + "col": 14 + }, + { + "color": "B", + "row": 2, + "col": 14 + }, + { + "color": "W", + "row": 2, + "col": 6 + }, + { + "color": "B", + "row": 3, + "col": 5 + }, + { + "color": "W", + "row": 1, + "col": 6 + }, + { + "color": "B", + "row": 1, + "col": 5 + }, + { + "color": "W", + "row": 0, + "col": 5 + }, + { + "color": "B", + "row": 0, + "col": 4 + }, + { + "color": "W", + "row": 1, + "col": 4 + }, + { + "color": "B", + "row": 0, + "col": 6 + }, + { + "color": "W", + "row": 0, + "col": 7 + }, + { + "color": "B", + "row": 0, + "col": 5 + }, + { + "color": "W", + "row": 1, + "col": 8 + }, + { + "color": "B", + "row": 16, + "col": 2 + }, + { + "color": "W", + "row": 16, + "col": 3 + }, + { + "color": "B", + "row": 17, + "col": 5 + }, + { + "color": "W", + "row": 17, + "col": 4 + }, + { + "color": "B", + "row": 8, + "col": 5 + }, + { + "color": "W", + "row": 7, + "col": 4 + }, + { + "color": "B", + "row": 9, + "col": 4 + }, + { + "color": "W", + "row": 8, + "col": 3 + }, + { + "color": "B", + "row": 10, + "col": 4 + }, + { + "color": "W", + "row": 10, + "col": 3 + }, + { + "color": "B", + "row": 11, + "col": 5 + }, + { + "color": "W", + "row": 12, + "col": 5 + }, + { + "color": "B", + "row": 11, + "col": 6 + }, + { + "color": "W", + "row": 12, + "col": 6 + }, + { + "color": "B", + "row": 11, + "col": 3 + }, + { + "color": "W", + "row": 12, + "col": 4 + }, + { + "color": "B", + "row": 11, + "col": 2 + }, + { + "color": "W", + "row": 11, + "col": 0 + }, + { + "color": "B", + "row": 12, + "col": 1 + }, + { + "color": "W", + "row": 11, + "col": 7 + }, + { + "color": "B", + "row": 10, + "col": 6 + }, + { + "color": "W", + "row": 12, + "col": 8 + }, + { + "color": "B", + "row": 13, + "col": 7 + }, + { + "color": "W", + "row": 10, + "col": 8 + }, + { + "color": "B", + "row": 10, + "col": 2 + }, + { + "color": "W", + "row": 10, + "col": 5 + }, + { + "color": "B", + "row": 9, + "col": 5 + }, + { + "color": "W", + "row": 10, + "col": 7 + }, + { + "color": "B", + "row": 9, + "col": 1 + }, + { + "color": "W", + "row": 9, + "col": 8 + }, + { + "color": "B", + "row": 9, + "col": 0 + }, + { + "color": "W", + "row": 10, + "col": 5 + }, + { + "color": "B", + "row": 15, + "col": 1 + }, + { + "color": "W", + "row": 9, + "col": 2 + }, + { + "color": "B", + "row": 10, + "col": 1 + }, + { + "color": "W", + "row": 13, + "col": 1 + }, + { + "color": "B", + "row": 14, + "col": 1 + }, + { + "color": "W", + "row": 12, + "col": 0 + }, + { + "color": "B", + "row": 13, + "col": 2 + }, + { + "color": "W", + "row": 13, + "col": 0 + }, + { + "color": "B", + "row": 14, + "col": 2 + }, + { + "color": "W", + "row": 13, + "col": 8 + }, + { + "color": "B", + "row": 14, + "col": 7 + }, + { + "color": "W", + "row": 14, + "col": 8 + }, + { + "color": "B", + "row": 15, + "col": 7 + }, + { + "color": "W", + "row": 15, + "col": 8 + }, + { + "color": "B", + "row": 16, + "col": 8 + }, + { + "color": "W", + "row": 14, + "col": 3 + }, + { + "color": "B", + "row": 14, + "col": 6 + }, + { + "color": "W", + "row": 17, + "col": 2 + }, + { + "color": "B", + "row": 17, + "col": 1 + }, + { + "color": "W", + "row": 15, + "col": 2 + }, + { + "color": "B", + "row": 16, + "col": 1 + }, + { + "color": "W", + "row": 18, + "col": 1 + }, + { + "color": "B", + "row": 17, + "col": 0 + }, + { + "color": "W", + "row": 18, + "col": 2 + }, + { + "color": "B", + "row": 12, + "col": 3 + }, + { + "color": "W", + "row": 13, + "col": 4 + }, + { + "color": "B", + "row": 18, + "col": 4 + }, + { + "color": "W", + "row": 18, + "col": 3 + }, + { + "color": "B", + "row": 18, + "col": 5 + }, + { + "color": "W", + "row": 14, + "col": 5 + }, + { + "color": "B", + "row": 18, + "col": 14 + }, + { + "color": "W", + "row": 18, + "col": 13 + }, + { + "color": "B", + "row": 18, + "col": 15 + }, + { + "color": "W", + "row": 18, + "col": 10 + }, + { + "color": "B", + "row": 18, + "col": 9 + }, + { + "color": "W", + "row": 13, + "col": 6 + }, + { + "color": "B", + "row": 16, + "col": 6 + }, + { + "color": "W", + "row": 17, + "col": 7 + }, + { + "color": "B", + "row": 16, + "col": 7 + }, + { + "color": "W", + "row": 18, + "col": 7 + }, + { + "color": "B", + "row": 12, + "col": 9 + }, + { + "color": "W", + "row": 11, + "col": 9 + }, + { + "color": "B", + "row": 11, + "col": 13 + }, + { + "color": "W", + "row": 10, + "col": 13 + }, + { + "color": "B", + "row": 11, + "col": 14 + }, + { + "color": "W", + "row": 11, + "col": 12 + }, + { + "color": "B", + "row": 9, + "col": 13 + }, + { + "color": "W", + "row": 9, + "col": 12 + }, + { + "color": "B", + "row": 1, + "col": 9 + }, + { + "color": "W", + "row": 0, + "col": 9 + }, + { + "color": "B", + "row": 0, + "col": 10 + }, + { + "color": "W", + "row": 0, + "col": 8 + }, + { + "color": "B", + "row": 2, + "col": 7 + }, + { + "color": "W", + "row": 2, + "col": 8 + }, + { + "color": "B", + "row": 1, + "col": 7 + }, + { + "color": "W", + "row": 2, + "col": 11 + }, + { + "color": "B", + "row": 1, + "col": 13 + }, + { + "color": "W", + "row": 2, + "col": 16 + }, + { + "color": "B", + "row": 2, + "col": 15 + }, + { + "color": "W", + "row": 1, + "col": 17 + }, + { + "color": "B", + "row": 1, + "col": 16 + }, + { + "color": "W", + "row": 7, + "col": 9 + }, + { + "color": "B", + "row": 6, + "col": 9 + }, + { + "color": "W", + "row": 6, + "col": 8 + }, + { + "color": "B", + "row": 7, + "col": 13 + }, + { + "color": "W", + "row": 11, + "col": 8 + }, + { + "color": "B", + "row": 6, + "col": 18 + }, + { + "color": "W", + "row": 17, + "col": 3 + }, + { + "color": "B", + "row": 10, + "col": 18 + }, + { + "color": "W", + "row": 15, + "col": 4 + }, + { + "color": "W", + "row": 18, + "col": 0 + }, + { + "color": "W", + "row": 14, + "col": 0 + }, + { + "color": "B", + "row": 15, + "col": 0 + }, + { + "color": "W", + "row": 4, + "col": 0 + }, + { + "color": "B", + "row": 4, + "col": 2 + }, + { + "color": "W", + "row": 3, + "col": 1 + }, + { + "color": "B", + "row": 2, + "col": 0 + }, + { + "color": "W", + "row": 6, + "col": 2 + }, + { + "color": "B", + "row": 6, + "col": 1 + }, + { + "color": "W", + "row": 1, + "col": 3 + }, + { + "color": "B", + "row": 1, + "col": 2 + } + ] +} \ No newline at end of file diff --git a/test/game_record_snapshot_tests/fixtures/tygem_19x19.gib b/test/game_record_snapshot_tests/fixtures/tygem_19x19.gib new file mode 100644 index 0000000000000000000000000000000000000000..c5d46fa74cc6a28abaf814207d2a0822d6370b1a GIT binary patch literal 5382 zcmZvgOOI4H5QVcIDgU8YS#_gZzV9o|VjfM?Fx{Z(o{T~!iXcKLi2&sxA^v?%9lNT$ zh(OG^TrPhumwm2zdU3jV`gwPC*zS+dUmvda$IIRItNrnIY1g~+Pj9wMv)MPc>f^glAJ)6utMhhAP3kv|Y-HNVuxY1F zn>b?m`t|Fxf4_bF@af~1XTN><1m44W$Re`KDT_2b=-i^%%% zxW9R|JpS4=^ZR~4^X7I*>&Gj2ilDte>`Itx4|9#q_a8q0@%z7D()v2bxn`WOYMgd` z%{U2O5l8cUzS>=$n)Q9NzQu}>r$;1F^LN&?Zjj&g&HpWR@A!8Le+Z1Dwy$C#*U|M7 z3wpJ*Ova1t#nbL|kyf&5F50G9HLD-Gi~VtrUtrS4>HHeMsE73UTiPuwZ8W>w-Im^- zz1AAgiJ?R39MK7XYfib>0?#?HjTPmXV_3&wxQ#ou%QqZ(YC1he_Wl#yu$d~u#^jY+zgn+WKIeoJ=NmmUf z+_3V|WE)n#RYdDoM%F4BmT2)>rm&B;vgz8IGGWUM4y(!9iid1?0OoIuc1fT67r+Qu zvgZLvI67fR!Z8RsA|k95gpQ2xa6@4fOIk-rc({R-Se6@Xmu*uz+hzA4XBS*0leXzS zIlGm&iP`y1^rQrc&Crt)Rbn&rq=dmeNQrUoK}s0hgOu0+H;@trA3{tREI9)?@sD{7 z1VvEW;(?^%D;Wri5mrt(eGew$jWHkbCa=bc`D;DiOupp)bJ=9$n@jqw!K4tqcOnwYPo&-=*-2#c4~XEi5K6Io3@TpHz@tG4pZjxUY!O^zpx^37FS`Npc9 z3(%G)P2mfGvcCo>jS`MQKyksBFp1Tws4lU|LUHM1Rn(TatVNWv zk5y1vx~i>=ahVHsWr%(XOB9JvSq3j6NeUQ6CDfK`MJZ>|YF?6NF|II4na>WfBu!#m zd6JYb#6_qsp%p@Pi9;Z*?sABaP+a27N~^mZS|Y9TRa??3Uv;fZtAH5fyV@!t)?CU^ zS|x0wO?7D_LlhUxVg6ZLDt~Tq)vttc%%oGoIEK>Y40;`AS#dR&j%Db_L^|a|PHq0I zDp4`L&ejAERiz1jib@lFSySo(3aGVhx4rcFsQAZ<^yREn7E(f)?0S-(oQUL>tSj(w zb{7`UepZ(17-wmjVtrX!0ALBo(o&rPN(&BFcqr~rwH3BHM1!JYjTVv00_pcQHxQq= z`D0e7EM3*sEyp%{zi#268+Q7qx;Q5p}!l0yB zZ5Wg^zKc_ncfE4Rp!R)|s5tQfkQ&8|@0mossb|Q76DKNBaG;8%a8lNriV05)<&Jex zZ(y(^m?$_%r>BC7gF&7ON)9~2pq%iC7$u$VLDfMz-Gj1&VPQ}#c-ZBTC_L~8gQgP( zI|PZ+Q{5hk+Jl@%P~CV0wjxhdAFMVEN(v93CBJT}S@QE{C3e3jDiD_MF(^TZ5gtkk zFi#;x2u9BbRS1R{qNErS2F)qa_S)YnNvr}T2zPWSOCEHz9h zFouWjKTcYBD5IW5kD(dG(eoksxr0FF!S~MWLZ7HgvkQIVduOWJN{I`>caaYs%o`Dj zSq~{?8bgSQe>_)|CPc=GdZqvElORn-NKwkQSNc-)>1LzP>znT#82o5bk>dT3_~3!g zdUWQ{KW!8B2ms!n&$`!We(*#-C`PC@^QRUe=eCf!1#ITVTj%0_d(h?KnX?i73)C Function(File) parseFile, +}) { + group(groupName, () { + final dir = Directory(fixturesDir); + final files = dir + .listSync() + .whereType() + .where((f) => f.path.endsWith(extension)) + .toList(); + + for (final file in files) { + final filename = path.basename(file.path); + + test(filename, () async { + final record = await parseFile(file); + + expect(record.type, expectedType); + + // Verify against snapshot + final snapshot = createSnapshot(record); + final baseName = path.basenameWithoutExtension(filename); + final snapshotFilePath = snapshotPath(baseName, extension); + final expectedSnapshot = await _loadSnapshot(snapshotFilePath); + + // Decode both to compare as structured data + final expected = jsonDecode(expectedSnapshot); + final actual = jsonDecode(snapshot); + + expect( + actual, + equals(expected), + reason: 'Snapshot mismatch for $filename\n' + 'To update: dart run test/game_record_snapshot_tests/generate_snapshots.dart', + ); + }); + } + }); +} + +/// Loads an expected snapshot from the snapshots directory +Future _loadSnapshot(String filePath) async { + final file = File(filePath); + + if (!await file.exists()) { + // If snapshot doesn't exist, create it for the first time + // This helps with initial test creation + throw TestFailure('Snapshot file not found: ${file.path}\n' + 'Run: dart run test/game_record_snapshot_tests/generate_snapshots.dart'); + } + + return await file.readAsString(); +} diff --git a/test/game_record_snapshot_tests/generate_snapshots.dart b/test/game_record_snapshot_tests/generate_snapshots.dart new file mode 100644 index 00000000..be1dacb9 --- /dev/null +++ b/test/game_record_snapshot_tests/generate_snapshots.dart @@ -0,0 +1,62 @@ +import 'dart:io'; +import 'package:path/path.dart' as path; +import 'package:wqhub/game_client/game_record.dart'; +import 'snapshot_utils.dart'; + +/// Script to generate snapshot files for GameRecord tests +/// Automatically discovers all .sgf and .gib files in fixtures directory +void main() async { + // Ensure snapshots directory exists + await Directory(snapshotsDir).create(recursive: true); + + final fixturesDirectory = Directory(fixturesDir); + final files = fixturesDirectory.listSync().whereType(); + + int sgfCount = 0; + int gibCount = 0; + + for (final file in files) { + final filename = path.basename(file.path); + final extension = path.extension(filename); + + if (extension == '.sgf') { + final baseName = path.basenameWithoutExtension(filename); + await generateSnapshot( + file.path, + snapshotPath(baseName, extension), + isSgf: true, + ); + sgfCount++; + } else if (extension == '.gib') { + final baseName = path.basenameWithoutExtension(filename); + await generateSnapshot( + file.path, + snapshotPath(baseName, extension), + isSgf: false, + ); + gibCount++; + } + } + + print('\n✅ Generated $sgfCount SGF snapshots and $gibCount GIB snapshots'); +} + +Future generateSnapshot(String inputPath, String outputPath, + {required bool isSgf}) async { + print('Generating $outputPath...'); + + final GameRecord record; + + if (isSgf) { + final content = await File(inputPath).readAsString(); + record = GameRecord.fromSgf(content); + } else { + final content = await File(inputPath).readAsBytes(); + record = GameRecord.fromGib(content); + } + + final snapshot = createSnapshot(record); + await File(outputPath).writeAsString(snapshot); + + print(' Created with ${record.moves.length} moves'); +} diff --git a/test/game_record_snapshot_tests/snapshot_utils.dart b/test/game_record_snapshot_tests/snapshot_utils.dart new file mode 100644 index 00000000..e7fa9506 --- /dev/null +++ b/test/game_record_snapshot_tests/snapshot_utils.dart @@ -0,0 +1,32 @@ +import 'dart:convert'; +import 'package:wqhub/game_client/game_record.dart'; + +/// Directory containing fixture files (.sgf, .gib) +const fixturesDir = 'test/game_record_snapshot_tests/fixtures'; + +/// Directory containing snapshot JSON files +const snapshotsDir = 'test/game_record_snapshot_tests/fixtures/snapshots'; + +/// Returns the path to a snapshot file for the given base name and extension +String snapshotPath(String baseName, String extension) { + final ext = extension.replaceAll('.', '_'); + return '$snapshotsDir/${baseName}$ext.json'; +} + +/// Creates a JSON snapshot of a GameRecord for comparison +String createSnapshot(GameRecord record) { + final data = { + 'type': record.type.toString(), + 'moves': record.moves + .map((move) => { + 'color': move.col.toString(), + 'row': move.p.$1, + 'col': move.p.$2, + }) + .toList(), + }; + + // Pretty print JSON for readability + const encoder = JsonEncoder.withIndent(' '); + return encoder.convert(data); +}