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 00000000..c5d46fa7 Binary files /dev/null and b/test/game_record_snapshot_tests/fixtures/tygem_19x19.gib differ diff --git a/test/game_record_snapshot_tests/game_record_snapshot_test.dart b/test/game_record_snapshot_tests/game_record_snapshot_test.dart new file mode 100644 index 00000000..68c45b6d --- /dev/null +++ b/test/game_record_snapshot_tests/game_record_snapshot_test.dart @@ -0,0 +1,88 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as path; +import 'package:wqhub/game_client/game_record.dart'; +import 'snapshot_utils.dart'; + +void main() { + _testFileType( + fixturesDir: fixturesDir, + extension: '.sgf', + groupName: 'GameRecord.fromSgf snapshots', + expectedType: GameRecordType.sgf, + parseFile: (file) async { + final content = await file.readAsString(); + return GameRecord.fromSgf(content); + }, + ); + + _testFileType( + fixturesDir: fixturesDir, + extension: '.gib', + groupName: 'GameRecord.fromGib snapshots', + expectedType: GameRecordType.gib, + parseFile: (file) async { + final content = await file.readAsBytes(); + return GameRecord.fromGib(content); + }, + ); +} + +void _testFileType({ + required String fixturesDir, + required String extension, + required String groupName, + required GameRecordType expectedType, + required Future 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); +}