diff --git a/test-kit/src/test/scala/format/pgn/BinaryTest.scala b/test-kit/src/test/scala/format/pgn/BinaryTest.scala index 620c7a8a4..c461fb753 100644 --- a/test-kit/src/test/scala/format/pgn/BinaryTest.scala +++ b/test-kit/src/test/scala/format/pgn/BinaryTest.scala @@ -4,164 +4,159 @@ package format.pgn import chess.format.pgn.SanStr import scala.language.implicitConversions -class BinaryTest extends ChessSpecs: +class BinaryTest extends ChessTest: import BinaryTestData.* import BinaryTestUtils.* given Conversion[String, SanStr] = SanStr(_) - def compareStrAndBin(pgn: String) = + def compareStrAndBin(pgn: String)(using munit.Location) = val bin = (Binary writeMoves SanStr.from(pgn.split(' ').toList)).get.toList - ((Binary readMoves bin).get mkString " ") must_== pgn - bin.size must be_<=(pgn.length) + assertEquals(((Binary readMoves bin).get mkString " "), pgn) + assert(bin.size <= pgn.length) - "binary encoding" should: - "util test" in: - showByte(parseBinary("00000101")) must_== "00000101" - showByte(parseBinary("10100000")) must_== "10100000" - "write single move" in: - "simple pawn" in: - writeMove("a1") must_== "00000000" - writeMove("a2") must_== "00000001" - writeMove("a3") must_== "00000010" - writeMove("h4") must_== "00111011" - "simple piece" in: - writeMove("Ka1") must_== "01000000,00100000" - writeMove("Qa2") must_== "01000001,01000000" - writeMove("Rh4") must_== "01111011,01100000" - "simple piece with capture" in: - writeMove("Kxa1") must_== "01000000,00100100" - writeMove("Qxa2") must_== "01000001,01000100" - writeMove("Rxh4") must_== "01111011,01100100" - "simple piece with check" in: - writeMove("Ka1+") must_== "01000000,00101000" - writeMove("Qa2#") must_== "01000001,01010000" - writeMove("Rxh4+") must_== "01111011,01101100" - "pawn capture" in: - writeMove("bxa1") must_== "10000000,10000000" - writeMove("gxh4") must_== "10111011,01000000" - "pawn capture with check" in: - writeMove("bxa1+") must_== "10000000,10010000" - writeMove("gxh4#") must_== "10111011,01100000" - "pawn promotion" in: - writeMove("a1=Q") must_== "10000000,00000010" - writeMove("h8=B") must_== "10111111,00001000" - writeMove("h8=R") must_== "10111111,00000100" - "pawn promotion with check" in: - writeMove("a1=Q+") must_== "10000000,00010010" - writeMove("h8=B#") must_== "10111111,00101000" - "pawn promotion with capture" in: - writeMove("bxa1=Q") must_== "10000000,10000010" - writeMove("gxh8=B") must_== "10111111,01001000" - "pawn promotion with capture and check" in: - writeMove("bxa1=Q+") must_== "10000000,10010010" - writeMove("gxh8=B#") must_== "10111111,01101000" - "castling" in: - writeMove("O-O") must_== "01000000,11000000" - writeMove("O-O-O") must_== "01000000,11100000" - "castling with check" in: - writeMove("O-O+") must_== "01000000,11001000" - writeMove("O-O-O#") must_== "01000000,11110000" - "drop" in: - writeMove("N@a1") must_== "01000000,10000010" - "drop with check" in: - writeMove("N@a1+") must_== "01000000,10001010" - "drop with checkmate" in: - writeMove("N@a1#") must_== "01000000,10010010" - "disambiguated by file" in: - writeMove("Kfa1") must_== "11000000,00100000,00000101" - "disambiguated by file on h8" in: - writeMove("Kfh8") must_== "11111111,00100000,00000101" - "disambiguated by rank" in: - writeMove("K8a1") must_== "11000000,00100000,01000111" - "disambiguated fully" in: - writeMove("Kf4a1") must_== "11000000,00100000,10101011" - "disambiguated fully with capture" in: - writeMove("Kf4xa1") must_== "11000000,00100100,10101011" - "disambiguated fully with check" in: - writeMove("Kf4a1+") must_== "11000000,00101000,10101011" - writeMove("Kf4a1#") must_== "11000000,00110000,10101011" - "disambiguated fully with capture and check" in: - writeMove("Kf4xa1+") must_== "11000000,00101100,10101011" - writeMove("Kf4xa1#") must_== "11000000,00110100,10101011" - "disambiguated by rank with capture and check" in: - writeMove("K8xa1+") must_== "11000000,00101100,01000111" - "write many moves" in: - "all games" in: - forall(pgn200) { pgn => - val bin = (Binary writeMoves SanStr.from(pgn.split(' ').toList)).get - bin.length must be_<=(pgn.length) - } - "read single move" in: - "simple pawn" in: - readMove("00000000") must_== "a1" - readMove("00000001") must_== "a2" - readMove("00000010") must_== "a3" - readMove("00111011") must_== "h4" - "simple piece" in: - readMove("01000000,00100000") must_== "Ka1" - readMove("01000001,01000000") must_== "Qa2" - readMove("01111011,01100000") must_== "Rh4" - "simple piece with capture" in: - readMove("01000000,00100100") must_== "Kxa1" - readMove("01000001,01000100") must_== "Qxa2" - readMove("01111011,01100100") must_== "Rxh4" - "simple piece with check" in: - readMove("01000000,00101000") must_== "Ka1+" - readMove("01000001,01010000") must_== "Qa2#" - readMove("01111011,01101100") must_== "Rxh4+" - "pawn capture" in: - readMove("10000000,10000000") must_== "bxa1" - readMove("10111011,01000000") must_== "gxh4" - "pawn capture with check" in: - readMove("10000000,10010000") must_== "bxa1+" - readMove("10111011,01100000") must_== "gxh4#" - "pawn promotion" in: - readMove("10000000,00000010") must_== "a1=Q" - readMove("10111111,00001000") must_== "h8=B" - readMove("10111111,00000100") must_== "h8=R" - "pawn promotion with check" in: - readMove("10000000,00010010") must_== "a1=Q+" - readMove("10111111,00101000") must_== "h8=B#" - "pawn promotion with capture" in: - readMove("10000000,10000010") must_== "bxa1=Q" - readMove("10111111,01001000") must_== "gxh8=B" - "pawn promotion with capture and check" in: - readMove("10000000,10010010") must_== "bxa1=Q+" - readMove("10111111,01101000") must_== "gxh8=B#" - "castling" in: - readMove("01000000,11000000") must_== "O-O" - readMove("01000000,11100000") must_== "O-O-O" - "castling with check" in: - readMove("01000000,11001000") must_== "O-O+" - readMove("01000000,11110000") must_== "O-O-O#" - "drop" in: - readMove("01000000,10000010") must_== "N@a1" - "drop with check" in: - readMove("01000000,10001010") must_== "N@a1+" - "drop with checkmate" in: - readMove("01000000,10010010") must_== "N@a1#" - "disambiguated by file" in: - readMove("11000000,00100000,00000101") must_== "Kfa1" - "disambiguated by rank" in: - readMove("11000000,00100000,01000111") must_== "K8a1" - "disambiguated fully" in: - readMove("11000000,00100000,10101011") must_== "Kf4a1" - "disambiguated fully with capture" in: - readMove("11000000,00100100,10101011") must_== "Kf4xa1" - "disambiguated fully with check" in: - readMove("11000000,00101000,10101011") must_== "Kf4a1+" - readMove("11000000,00110000,10101011") must_== "Kf4a1#" - "disambiguated fully with capture and check" in: - readMove("11000000,00101100,10101011") must_== "Kf4xa1+" - readMove("11000000,00110100,10101011") must_== "Kf4xa1#" - "disambiguated by rank with capture and check" in: - readMove("11000000,00101100,01000111") must_== "K8xa1+" - "be isomorphic" in: - "for one" in: - compareStrAndBin(pgn200.head) - "for all" in: - forall(pgn200)(compareStrAndBin) + test("util test"): + assertEquals(showByte(parseBinary("00000101")), "00000101") + assertEquals(showByte(parseBinary("10100000")), "10100000") + test("simple pawn"): + assertEquals(writeMove("a1"), "00000000") + assertEquals(writeMove("a2"), "00000001") + assertEquals(writeMove("a3"), "00000010") + assertEquals(writeMove("h4"), "00111011") + test("simple piece"): + assertEquals(writeMove("Ka1"), "01000000,00100000") + assertEquals(writeMove("Qa2"), "01000001,01000000") + assertEquals(writeMove("Rh4"), "01111011,01100000") + test("simple piece with capture"): + assertEquals(writeMove("Kxa1"), "01000000,00100100") + assertEquals(writeMove("Qxa2"), "01000001,01000100") + assertEquals(writeMove("Rxh4"), "01111011,01100100") + test("simple piece with check"): + assertEquals(writeMove("Ka1+"), "01000000,00101000") + assertEquals(writeMove("Qa2#"), "01000001,01010000") + assertEquals(writeMove("Rxh4+"), "01111011,01101100") + test("pawn capture"): + assertEquals(writeMove("bxa1"), "10000000,10000000") + assertEquals(writeMove("gxh4"), "10111011,01000000") + test("pawn capture with check"): + assertEquals(writeMove("bxa1+"), "10000000,10010000") + assertEquals(writeMove("gxh4#"), "10111011,01100000") + test("pawn promotion"): + assertEquals(writeMove("a1=Q"), "10000000,00000010") + assertEquals(writeMove("h8=B"), "10111111,00001000") + assertEquals(writeMove("h8=R"), "10111111,00000100") + test("pawn promotion with check"): + assertEquals(writeMove("a1=Q+"), "10000000,00010010") + assertEquals(writeMove("h8=B#"), "10111111,00101000") + test("pawn promotion with capture"): + assertEquals(writeMove("bxa1=Q"), "10000000,10000010") + assertEquals(writeMove("gxh8=B"), "10111111,01001000") + test("pawn promotion with capture and check"): + assertEquals(writeMove("bxa1=Q+"), "10000000,10010010") + assertEquals(writeMove("gxh8=B#"), "10111111,01101000") + test("castling"): + assertEquals(writeMove("O-O"), "01000000,11000000") + assertEquals(writeMove("O-O-O"), "01000000,11100000") + test("castling with check"): + assertEquals(writeMove("O-O+"), "01000000,11001000") + assertEquals(writeMove("O-O-O#"), "01000000,11110000") + test("drop"): + assertEquals(writeMove("N@a1"), "01000000,10000010") + test("drop with check"): + assertEquals(writeMove("N@a1+"), "01000000,10001010") + test("drop with checkmate"): + assertEquals(writeMove("N@a1#"), "01000000,10010010") + test("disambiguated by file"): + assertEquals(writeMove("Kfa1"), "11000000,00100000,00000101") + test("disambiguated by file on h8"): + assertEquals(writeMove("Kfh8"), "11111111,00100000,00000101") + test("disambiguated by rank"): + assertEquals(writeMove("K8a1"), "11000000,00100000,01000111") + test("disambiguated fully"): + assertEquals(writeMove("Kf4a1"), "11000000,00100000,10101011") + test("disambiguated fully with capture"): + assertEquals(writeMove("Kf4xa1"), "11000000,00100100,10101011") + test("disambiguated fully with check"): + assertEquals(writeMove("Kf4a1+"), "11000000,00101000,10101011") + assertEquals(writeMove("Kf4a1#"), "11000000,00110000,10101011") + test("disambiguated fully with capture and check"): + assertEquals(writeMove("Kf4xa1+"), "11000000,00101100,10101011") + assertEquals(writeMove("Kf4xa1#"), "11000000,00110100,10101011") + test("disambiguated by rank with capture and check"): + assertEquals(writeMove("K8xa1+"), "11000000,00101100,01000111") + test("write many moves"): + pgn200.foreach: pgn => + val bin = (Binary writeMoves SanStr.from(pgn.split(' ').toList)).get + assert(bin.length <= pgn.length) + test("simple pawn"): + assertEquals(readMove("00000000"), "a1") + assertEquals(readMove("00000001"), "a2") + assertEquals(readMove("00000010"), "a3") + assertEquals(readMove("00111011"), "h4") + test("simple piece"): + assertEquals(readMove("01000000,00100000"), "Ka1") + assertEquals(readMove("01000001,01000000"), "Qa2") + assertEquals(readMove("01111011,01100000"), "Rh4") + test("simple piece with capture"): + assertEquals(readMove("01000000,00100100"), "Kxa1") + assertEquals(readMove("01000001,01000100"), "Qxa2") + assertEquals(readMove("01111011,01100100"), "Rxh4") + test("simple piece with check"): + assertEquals(readMove("01000000,00101000"), "Ka1+") + assertEquals(readMove("01000001,01010000"), "Qa2#") + assertEquals(readMove("01111011,01101100"), "Rxh4+") + test("pawn capture"): + assertEquals(readMove("10000000,10000000"), "bxa1") + assertEquals(readMove("10111011,01000000"), "gxh4") + test("pawn capture with check"): + assertEquals(readMove("10000000,10010000"), "bxa1+") + assertEquals(readMove("10111011,01100000"), "gxh4#") + test("pawn promotion"): + assertEquals(readMove("10000000,00000010"), "a1=Q") + assertEquals(readMove("10111111,00001000"), "h8=B") + assertEquals(readMove("10111111,00000100"), "h8=R") + test("pawn promotion with check"): + assertEquals(readMove("10000000,00010010"), "a1=Q+") + assertEquals(readMove("10111111,00101000"), "h8=B#") + test("pawn promotion with capture"): + assertEquals(readMove("10000000,10000010"), "bxa1=Q") + assertEquals(readMove("10111111,01001000"), "gxh8=B") + test("pawn promotion with capture and check"): + assertEquals(readMove("10000000,10010010"), "bxa1=Q+") + assertEquals(readMove("10111111,01101000"), "gxh8=B#") + test("castling"): + assertEquals(readMove("01000000,11000000"), "O-O") + assertEquals(readMove("01000000,11100000"), "O-O-O") + test("castling with check"): + assertEquals(readMove("01000000,11001000"), "O-O+") + assertEquals(readMove("01000000,11110000"), "O-O-O#") + test("drop"): + assertEquals(readMove("01000000,10000010"), "N@a1") + test("drop with check"): + assertEquals(readMove("01000000,10001010"), "N@a1+") + test("drop with checkmate"): + assertEquals(readMove("01000000,10010010"), "N@a1#") + test("disambiguated by file"): + assertEquals(readMove("11000000,00100000,00000101"), "Kfa1") + test("disambiguated by rank"): + assertEquals(readMove("11000000,00100000,01000111"), "K8a1") + test("disambiguated fully"): + assertEquals(readMove("11000000,00100000,10101011"), "Kf4a1") + test("disambiguated fully with capture"): + assertEquals(readMove("11000000,00100100,10101011"), "Kf4xa1") + test("disambiguated fully with check"): + assertEquals(readMove("11000000,00101000,10101011"), "Kf4a1+") + assertEquals(readMove("11000000,00110000,10101011"), "Kf4a1#") + test("disambiguated fully with capture and check"): + assertEquals(readMove("11000000,00101100,10101011"), "Kf4xa1+") + assertEquals(readMove("11000000,00110100,10101011"), "Kf4xa1#") + test("disambiguated by rank with capture and check"): + assertEquals(readMove("11000000,00101100,01000111"), "K8xa1+") + test("be isomorphic"): + // "for one" in: + compareStrAndBin(pgn200.head) + // "for all" in: + pgn200 foreach compareStrAndBin object BinaryTestUtils: diff --git a/test-kit/src/test/scala/format/pgn/DumperTest.scala b/test-kit/src/test/scala/format/pgn/DumperTest.scala index 0408e4ce6..9b98fa7e2 100644 --- a/test-kit/src/test/scala/format/pgn/DumperTest.scala +++ b/test-kit/src/test/scala/format/pgn/DumperTest.scala @@ -7,16 +7,15 @@ import Square.* import chess.variant.ThreeCheck -class DumperTest extends ChessSpecs: +class DumperTest extends ChessTest: given Conversion[String, SanStr] = SanStr(_) - "Check with pawn" should: - "not be checkmate if pawn can be taken en passant" in: - val game = Fen.readWithMoveNumber(EpdFen("8/3b4/6R1/1P2kp2/6pp/2N1P3/4KPPP/8 w - -")).get match - case s: Situation.AndFullMoveNumber => Game(s.situation, ply = s.ply) - val move = game(Square.F2, Square.F4).toOption.get._2 - Dumper(move) must_== "f4+" + test("Check with pawn not be checkmate if pawn can be taken en passant"): + val game = Fen.readWithMoveNumber(EpdFen("8/3b4/6R1/1P2kp2/6pp/2N1P3/4KPPP/8 w - -")).get match + case s: Situation.AndFullMoveNumber => Game(s.situation, ply = s.ply) + val move = game(Square.F2, Square.F4).toOption.get._2 + assertEquals(Dumper(move), "f4+") val gioachineGreco = makeGame.playMoves( D2 -> D4, @@ -74,30 +73,29 @@ class DumperTest extends ChessSpecs: H5 -> G6 ) - "standard game" should: - "move list" in: - "Gioachine Greco" in: - gioachineGreco map (_.sans) must beRight.like { case ms => - ms must_== "d4 d5 c4 dxc4 e3 b5 a4 c6 axb5 cxb5 Qf3".split(' ').toList - } - "Peruvian Immortal" in: - peruvianImmortal map (_.sans) must beRight.like { case ms => - ms must_== "e4 d5 exd5 Qxd5 Nc3 Qa5 d4 c6 Nf3 Bg4 Bf4 e6 h3 Bxf3 Qxf3 Bb4 Be2 Nd7 a3 O-O-O axb4 Qxa1+ Kd2 Qxh1 Qxc6+ bxc6 Ba6#" + test("standard game"): + gioachineGreco + .map(_.sans) + .assertRight: ms => + assertEquals(ms, SanStr from "d4 d5 c4 dxc4 e3 b5 a4 c6 axb5 cxb5 Qf3".split(' ').toVector) + peruvianImmortal + .map(_.sans) + .assertRight: ms => + assertEquals( + ms, + SanStr from "e4 d5 exd5 Qxd5 Nc3 Qa5 d4 c6 Nf3 Bg4 Bf4 e6 h3 Bxf3 Qxf3 Bb4 Be2 Nd7 a3 O-O-O axb4 Qxa1+ Kd2 Qxh1 Qxc6+ bxc6 Ba6#" .split(' ') - .toList - } + .toVector + ) - "three check variant" should: - "move list" in: - threeCheck map (_.sans) must beRight.like { case ms => - ms must_== "e4 c5 Bc4 Nc6 Bxf7+ Kxf7 Qh5+ g6 Qxg6#" - .split(' ') - .toList - } + test("three check variant"): + threeCheck + .map(_.sans) + .assertRight: ms => + assertEquals(ms, SanStr from "e4 c5 Bc4 Nc6 Bxf7+ Kxf7 Qh5+ g6 Qxg6#".split(' ').toVector) - "dump a promotion move" should: - "without check" in: - val game = Game(""" + test("without check"): + val game = Game(""" P k @@ -107,12 +105,14 @@ P k PP PPP KNBQ BNR """) - game.playMoves(A7 -> A8) map (_.sans) must beRight.like { case ms => - ms must_== List("a8=Q") - } - "with check" in: - val game = Game(""" - k + game + .playMoves(A7 -> A8) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("a8=Q"))) + test("with check"): + val game = Game(""" + k P @@ -121,11 +121,13 @@ P PP PPP KNBQ BNR """) - game.playMoves(A7 -> A8) map (_.sans) must beRight.like { case ms => - ms must_== List("a8=Q+") - } - "with checkmate" in: - val game = Game(""" + game + .playMoves(A7 -> A8) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("a8=Q+"))) + test("with checkmate"): + val game = Game(""" k P ppp @@ -135,27 +137,30 @@ P ppp PP PPP KNBQ BNR """) - game.playMoves(A7 -> A8) map (_.sans) must beRight.like { case ms => - ms must_== List("a8=Q#") - } - "castle kingside" in: - Game(""" + game + .playMoves(A7 -> A8) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("a8=Q#"))) + test("castle kingside"): + Game(""" PP PPP R K R -""").playMoves(E1 -> G1) map (_.sans) must beRight.like { case ms => - ms must_== List("O-O") - } - "castle queenside" in: - Game(""" +""").playMoves(E1 -> G1) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("O-O"))) + test("castle queenside"): + Game(""" PP PPP R K R -""").playMoves(E1 -> C1) map (_.sans) must beRight.like { case ms => - ms must_== List("O-O-O") - } +""").playMoves(E1 -> C1) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("O-O-O"))) - "ambiguous moves" should: - "ambiguous file only" in: - val game = Game(""" + test("ambiguous file only"): + val game = Game(""" k @@ -165,11 +170,13 @@ k P K P R R """) - game.playMoves(H1 -> B1) map (_.sans) must beRight.like { case ms => - ms must_== List("Rhb1") - } - "ambiguous rank only" in: - val game = Game(""" + game + .playMoves(H1 -> B1) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("Rhb1"))) + test("ambiguous rank only"): + val game = Game(""" k @@ -179,11 +186,13 @@ k K P N """) - game.playMoves(B5 -> C3) map (_.sans) must beRight.like { case ms => - ms must_== List("N5c3") - } - "ambiguous file and rank" in: - val game = Game(""" + game + .playMoves(B5 -> C3) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("N5c3"))) + test("ambiguous file and rank"): + val game = Game(""" QQ @@ -193,11 +202,13 @@ k K k """) - game.playMoves(C6 -> D5) map (_.sans) must beRight.like { case ms => - ms must_== List("Qc6d5") - } - "unambiguous file" in: - val game = Game(""" + game + .playMoves(C6 -> D5) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("Qc6d5"))) + test("unambiguous file"): + val game = Game(""" k @@ -207,11 +218,13 @@ k P P R K R """) - game.playMoves(H1 -> F1) map (_.sans) must beRight.like { case ms => - ms must_== List("Rf1") - } - "unambiguous rank" in: - val game = Game(""" + game + .playMoves(H1 -> F1) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("Rf1"))) + test("unambiguous rank"): + val game = Game(""" k KRq @@ -221,39 +234,42 @@ k """) - game.playMoves(E4 -> E5) map (_.sans) must beRight.like { case ms => - ms must_== List("Re5") - } - - "chess960" should: - "castle queenside as white" in: - Game( - makeBoard( - """ + game + .playMoves(E4 -> E5) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("Re5"))) + + test("chess960 castle queenside as white"): + Game( + makeBoard( + """ PPPPPPPP NRK RQBB """, - variant.Chess960 - ) - ).playMoves(C1 -> B1) map (_.sans) must beRight.like { case ms => - ms must_== List("O-O-O") - } - "castle kingside as white" in: - Game( - makeBoard( - """ + variant.Chess960 + ) + ).playMoves(C1 -> B1) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("O-O-O"))) + test("chess960 castle kingside as white"): + Game( + makeBoard( + """ PP PPPPP NRK R B """, - variant.Chess960 - ) - ).playMoves(C1 -> E1) map (_.sans) must beRight.like { case ms => - ms must_== List("O-O") - } - "castle queenside as black" in: - Game( - makeBoard( - """ + variant.Chess960 + ) + ).playMoves(C1 -> E1) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("O-O"))) + test("chess960 castle queenside as black"): + Game( + makeBoard( + """ nrk rqbb pppppppp @@ -263,15 +279,17 @@ pppppppp PPPPPPPP NRK RQBB """, - variant.Chess960 - ) - ).withPlayer(Black).playMoves(C8 -> B8) map (_.sans) must beRight.like { case ms => - ms must_== List("O-O-O") - } - "castle kingside as black" in: - Game( - makeBoard( - """ + variant.Chess960 + ) + ).withPlayer(Black) + .playMoves(C8 -> B8) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("O-O-O"))) + test("chess960 castle kingside as black"): + Game( + makeBoard( + """ nrk r b pppppppp @@ -281,16 +299,18 @@ pppppppp PPPPPPPP NRK RQBB """, - variant.Chess960 - ) - ).withPlayer(Black).playMoves(C8 -> E8) map (_.sans) must beRight.like { case ms => - ms must_== List("O-O") - } - - "opening with castles" in: - Game( - makeBoard( - """ + variant.Chess960 + ) + ).withPlayer(Black) + .playMoves(C8 -> E8) + .map(_.sans) + .assertRight: ms => + assertEquals(ms, Vector(SanStr("O-O"))) + + test("chess960 opening with castles"): + Game( + makeBoard( + """ nrknrqbb pppppppp @@ -300,23 +320,23 @@ pppppppp PPPPPPPP NRKNRQBB """, - variant.Chess960 - ) - ).playMoves( - F2 -> F4, - D8 -> C6, - D1 -> C3, - G7 -> G6, - C3 -> B5, - C8 -> B8, - C1 -> B1 - ) map (_.sans) must beRight.like { case ms => - ms must_== "f4 Nc6 Nc3 g6 Nb5 O-O-O O-O-O".split(' ').toList - } - - "tricky rook disambiguation" in: - val fen = EpdFen("r5k1/1b5p/N3p1p1/Q4p2/4r3/2P1q3/1PK2RP1/5R2 w - - 1 38") - val sit = Fen.read(fen).get - val game1 = Game(sit.board, sit.color) - val (game2, move) = game1(Square.F2, Square.F3).toOption.get - Dumper(game1.situation, move, game2.situation) must_== "Rf3" + variant.Chess960 + ) + ).playMoves( + F2 -> F4, + D8 -> C6, + D1 -> C3, + G7 -> G6, + C3 -> B5, + C8 -> B8, + C1 -> B1 + ).map(_.sans) + .assertRight: ms => + assertEquals(ms, SanStr from "f4 Nc6 Nc3 g6 Nb5 O-O-O O-O-O".split(' ').toVector) + + test("chess960 tricky rook disambiguation"): + val fen = EpdFen("r5k1/1b5p/N3p1p1/Q4p2/4r3/2P1q3/1PK2RP1/5R2 w - - 1 38") + val sit = Fen.read(fen).get + val game1 = Game(sit.board, sit.color) + val (game2, move) = game1(Square.F2, Square.F3).toOption.get + assertEquals(Dumper(game1.situation, move, game2.situation), "Rf3") diff --git a/test-kit/src/test/scala/format/pgn/ReaderTest.scala b/test-kit/src/test/scala/format/pgn/ReaderTest.scala index 2e06f1395..9f26fe27d 100644 --- a/test-kit/src/test/scala/format/pgn/ReaderTest.scala +++ b/test-kit/src/test/scala/format/pgn/ReaderTest.scala @@ -4,116 +4,141 @@ package format.pgn import scala.language.implicitConversions import MoveOrDrop.* -class ReaderTest extends ChessSpecs: +class ReaderTest extends ChessTest: import Fixtures.* import Reader.Result.* - "only raw moves" should: - "many games" in: - forall(raws) { (c: String) => - Reader.full(c) must beRight.like { case Complete(replay) => - replay.moves must have size c.split(' ').length - } - } - "example from prod 1" in: - Reader.full(fromProd1) must beRight - "example from prod 2" in: - Reader.full(fromProd2) must beRight - "rook promotion" in: - Reader.full(promoteRook) must beRight - "castle check O-O-O+" in: - Reader.full(castleCheck1) must beRight - "castle checkmate O-O#" in: - Reader.full(castleCheck2) must beRight - "and delimiters" in: - Reader.full(withDelimiters) must beRight.like { case Complete(replay) => - replay.moves must have size 33 - } - "and delimiters on new lines" in: - Reader.full(withDelimitersOnNewLines) must beRight.like { case Complete(replay) => - replay.moves must have size 33 - } - "tags and moves" should: - "chess960" in: - Reader.full(complete960) must beRight - "with empty lines" in: - Reader.full("\n" + complete960 + "\n") must beRight - "example from wikipedia" in: - Reader.full(fromWikipedia) must beRight - "with inline comments" in: - Reader.full(inlineComments) must beRight - "example from chessgames.com" in: - Reader.full(fromChessgames) must beRight - "example from chessgames.com with escape chars" in: - Reader.full(fromChessgamesWithEscapeChar) must beRight - "immortal with NAG" in: - Reader.full(withNag) must beRight - "example from TCEC" in: - Reader.full(fromTcec) must beRight - "from https://chessprogramming.wikispaces.com/Kasparov+versus+Deep+Blue+1996" in: - Reader.full(fromChessProgrammingWiki) must beRight - "comments and variations" in: - Reader.full(commentsAndVariations) must beRight - "comments and variations by smartchess" in: - Reader.full(bySmartChess) must beRight - "invalid variant" in: - Reader.full(invalidVariant) must beRight.like { case Complete(replay) => - replay.setup.board.variant must_== variant.Standard - } - "promoting to a rook" in: - Reader.full(fromLichessBadPromotion) must beRight.like { case Complete(replay) => - replay.chronoMoves lift 10 must beSome: - (_: MoveOrDrop).fold(_.promotion, _ => None) must_== Option(Rook) - } - "chessbase arrows" in: - Reader.full(chessbaseArrows) must beRight - "atomic regression" in: - Reader.full(atomicRegression) must beRight - "atomic promotion" in: - Reader.full(atomicPromotion) must beRight - "lichobile export" in: - Reader.full(lichobile) must beRight - "crazyhouse 1" in: - Reader.full(crazyhouse1) must beRight.like { case Complete(replay) => - replay.chronoMoves lift 11 must beSome: - (_: MoveOrDrop).toUci.uci must_== "P@c6" - } - "crazyhouse 2" in: - Reader.full(crazyhouse2) must beRight.like { case Complete(replay) => - replay.chronoMoves.size must_== 111 - } - "crazyhouse without variant tag" in: - Reader.full(crazyhouseNoVariantTag) must beRight.like { case Incomplete(replay, _) => - replay.chronoMoves.size must_== 8 - } - "crazyhouse from chess.com" in: - Reader.full(chessComCrazyhouse) must beRight - "from prod" in: - "from position close chess" in: - Reader.full(fromPosProdCloseChess) must beRight.like { case Complete(replay) => - replay.chronoMoves.size must_== 152 - } - "from position empty FEN" in: - Reader.full(fromPositionEmptyFen) must beRight.like { case Complete(replay) => - replay.chronoMoves.size must_== 164 - } - "preserves initial ply" in: - Reader.full(caissa) must beRight.like { case Complete(replay) => - replay.setup.startedAtPly must_== 43 - replay.state.startedAtPly must_== 43 - } - "partial from broadcast" in: - Reader.full(festivalFigueira) must beRight.like { case Incomplete(replay, _) => - replay.chronoMoves.size must_== 113 - } - "invisible char" in: - Reader.full(invisibleChar) must beRight.like { case Complete(replay) => - replay.chronoMoves.size must_== 19 - } - "exotic notation from clono.no" in: - Reader.full(clonoNoExoticNotation) must beRight.like { case Complete(replay) => - replay.chronoMoves lift 42 must beSome { (m: MoveOrDrop) => - m.toUci.uci must_== "e7f8q" - } - } + // "only raw moves" should: + test("many games"): + raws.foreach: c => + Reader + .full(c) + .assertRight: + case Complete(replay) => assertEquals(replay.moves.size, c.split(' ').length) + test("example from prod 1"): + assert(Reader.full(fromProd1).isRight) + test("example from prod 2"): + assert(Reader.full(fromProd2).isRight) + test("rook promotion"): + assert(Reader.full(promoteRook).isRight) + test("castle check O-O-O+"): + assert(Reader.full(castleCheck1).isRight) + test("castle checkmate O-O#"): + assert(Reader.full(castleCheck2).isRight) + test("and delimiters"): + Reader + .full(withDelimiters) + .assertRight: + case Complete(replay) => assertEquals(replay.moves.size, 33) + test("and delimiters on new lines"): + Reader + .full(withDelimitersOnNewLines) + .assertRight: + case Complete(replay) => assertEquals(replay.moves.size, 33) + // "tags and moves" should: + test("chess960"): + assert(Reader.full(complete960).isRight) + test("with empty lines"): + assert(Reader.full("\n" + complete960 + "\n").isRight) + test("example from wikipedia"): + assert(Reader.full(fromWikipedia).isRight) + test("with inline comments"): + assert(Reader.full(inlineComments).isRight) + test("example from chessgames.com"): + assert(Reader.full(fromChessgames).isRight) + test("example from chessgames.com with escape chars"): + assert(Reader.full(fromChessgamesWithEscapeChar).isRight) + test("immortal with NAG"): + assert(Reader.full(withNag).isRight) + test("example from TCEC"): + assert(Reader.full(fromTcec).isRight) + test("from https://chessprogramming.wikispaces.com/Kasparov+versus+Deep+Blue+1996"): + assert(Reader.full(fromChessProgrammingWiki).isRight) + test("comments and variations"): + assert(Reader.full(commentsAndVariations).isRight) + test("comments and variations by smartchess"): + assert(Reader.full(bySmartChess).isRight) + test("invalid variant"): + Reader + .full(invalidVariant) + .assertRight: + case Complete(replay) => + assertEquals(replay.setup.board.variant, variant.Standard) + test("promoting to a rook"): + Reader + .full(fromLichessBadPromotion) + .assertRight: + case Complete(replay) => + replay.chronoMoves + .lift(10) + .assertSome: m => + assertEquals(m.fold(_.promotion, _ => None), Option(Rook)) + test("chessbase arrows"): + assert(Reader.full(chessbaseArrows).isRight) + test("atomic regression"): + assert(Reader.full(atomicRegression).isRight) + test("atomic promotion"): + assert(Reader.full(atomicPromotion).isRight) + test("lichobile export"): + assert(Reader.full(lichobile).isRight) + test("crazyhouse 1"): + Reader + .full(crazyhouse1) + .assertRight: + case Complete(replay) => + replay.chronoMoves lift 11 assertSome: m => + assertEquals(m.toUci.uci, "P@c6") + test("crazyhouse 2"): + Reader + .full(crazyhouse2) + .assertRight: + case Complete(replay) => assertEquals(replay.chronoMoves.size, 111) + test("crazyhouse without variant tag"): + Reader + .full(crazyhouseNoVariantTag) + .assertRight: + case Incomplete(replay, _) => + assertEquals(replay.chronoMoves.size, 8) + test("crazyhouse from chess.com"): + assert(Reader.full(chessComCrazyhouse).isRight) + + // "from prod" in: + test("from position close chess"): + Reader + .full(fromPosProdCloseChess) + .assertRight: + case Complete(replay) => + assertEquals(replay.chronoMoves.size, 152) + test("from position empty FEN"): + Reader + .full(fromPositionEmptyFen) + .assertRight: + case Complete(replay) => + assertEquals(replay.chronoMoves.size, 164) + test("preserves initial ply"): + Reader + .full(caissa) + .assertRight: + case Complete(replay) => + assertEquals(replay.setup.startedAtPly, 43) + + test("partial from broadcast"): + Reader + .full(festivalFigueira) + .assertRight: + case Incomplete(replay, _) => + assertEquals(replay.chronoMoves.size, 113) + test("invisible char"): + Reader + .full(invisibleChar) + .assertRight: + case Complete(replay) => + assertEquals(replay.chronoMoves.size, 19) + test("exotic notation from clono.no"): + Reader + .full(clonoNoExoticNotation) + .assertRight: + case Complete(replay) => + replay.chronoMoves lift 42 assertSome: m => + assertEquals(m.toUci.uci, "e7f8q") diff --git a/test-kit/src/test/scala/format/pgn/TagTest.scala b/test-kit/src/test/scala/format/pgn/TagTest.scala index 2a17a65ce..d97e8ea61 100644 --- a/test-kit/src/test/scala/format/pgn/TagTest.scala +++ b/test-kit/src/test/scala/format/pgn/TagTest.scala @@ -1,11 +1,11 @@ package chess package format.pgn -class TagTest extends ChessSpecs: +class TagTest extends ChessTest: - "Tags" should: - // http://www.saremba.de/chessgml/standards/pgn/pgn-complete.htm#c8.1.1 - "be sorted" in: + // http://www.saremba.de/chessgml/standards/pgn/pgn-complete.htm#c8.1.1 + test("be sorted"): + assertEquals( Tags( List( Tag(Tag.Site, "https://lichess.org/QuCzSfxw"), @@ -22,7 +22,8 @@ class TagTest extends ChessSpecs: Tag(Tag.BlackRatingDiff, "-7"), Tag(Tag.Event, "Titled Arena 5") ) - ).sorted.value.map(_.name) must_== List( + ).sorted.value.map(_.name), + List( Tag.Event, Tag.Site, Tag.Date, @@ -37,12 +38,16 @@ class TagTest extends ChessSpecs: Tag.WhiteRatingDiff, Tag.BlackRatingDiff ) + ) - "be trimmed" in: + test("be trimmed"): + assertEquals( List( Tag(_.Site, " https://lichess.org/QuCzSfxw "), Tag(_.Black, " penguingim1 ") - ) must_== List( + ), + List( Tag(_.Site, "https://lichess.org/QuCzSfxw"), Tag(_.Black, "penguingim1") ) + )