diff --git a/modules/io/src/test/scala/de/nowchess/io/json/JsonParserTest.scala b/modules/io/src/test/scala/de/nowchess/io/json/JsonParserTest.scala index b97f609..4340b03 100644 --- a/modules/io/src/test/scala/de/nowchess/io/json/JsonParserTest.scala +++ b/modules/io/src/test/scala/de/nowchess/io/json/JsonParserTest.scala @@ -130,7 +130,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: // Edge cases with defaults test("parse invalid turn color returns error") { - val json = """{ + val json = """{ "metadata": {}, "gameState": {"turn": "Invalid", "board": []}, "moves": [] @@ -141,7 +141,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse invalid piece type filters it out") { - val json = """{ + val json = """{ "metadata": {}, "gameState": { "turn": "White", @@ -158,7 +158,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse invalid color in board filters piece") { - val json = """{ + val json = """{ "metadata": {}, "gameState": { "turn": "White", @@ -175,7 +175,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse with missing turn uses default") { - val json = """{ + val json = """{ "metadata": {}, "gameState": {"board": []}, "moves": [] @@ -187,7 +187,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse with missing board uses empty") { - val json = """{ + val json = """{ "metadata": {}, "gameState": {"turn": "White"}, "moves": [] @@ -199,7 +199,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse with missing moves uses empty list") { - val json = """{ + val json = """{ "metadata": {}, "gameState": {"turn": "White", "board": []} }""" @@ -210,7 +210,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse invalid square in board filters it") { - val json = """{ + val json = """{ "metadata": {}, "gameState": { "turn": "White", @@ -227,7 +227,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse all valid piece types") { - val json = """{ + val json = """{ "metadata": {}, "gameState": { "turn": "White", @@ -255,7 +255,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse with all castling rights false") { - val json = """{ + val json = """{ "metadata": {}, "gameState": { "turn": "White", @@ -278,7 +278,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: // Move type parsing tests test("parse all move type variations") { - val json = """{ + val json = """{ "metadata": {"event": "Game", "result": "*"}, "gameState": {"turn": "White", "board": []}, "moves": [ @@ -303,7 +303,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse invalid move type defaults to None") { - val json = """{ + val json = """{ "metadata": {"event": "Game"}, "gameState": {"turn": "White", "board": []}, "moves": [{"from": "e2", "to": "e4", "type": {"type": "unknown"}}] @@ -313,7 +313,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse promotion with invalid piece uses default") { - val json = """{ + val json = """{ "metadata": {}, "gameState": {"turn": "White", "board": []}, "moves": [{"from": "a7", "to": "a8", "type": {"type": "promotion", "promotionPiece": "invalid"}}] @@ -323,7 +323,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse move with invalid from/to skips it") { - val json = """{ + val json = """{ "metadata": {}, "gameState": {"turn": "White", "board": []}, "moves": [{"from": "e2", "to": "invalid", "type": {"type": "normal"}}] @@ -335,7 +335,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse normal move with isCapture true") { - val json = """{ + val json = """{ "metadata": {}, "gameState": {"turn": "White", "board": []}, "moves": [{"from": "e4", "to": "d5", "type": {"type": "normal", "isCapture": true}}] @@ -348,7 +348,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse board with invalid pieces filters them") { - val json = """{ + val json = """{ "metadata": {}, "gameState": { "turn": "White", @@ -366,7 +366,7 @@ class JsonParserTest extends AnyFunSuite with Matchers: } test("parse with empty board") { - val json = """{ + val json = """{ "metadata": {"event": "Game", "players": {"white": "A", "black": "B"}, "date": "2026-04-06", "result": "*"}, "gameState": { "board": [], diff --git a/modules/rule/src/main/scala/de/nowchess/rules/dto/DtoMapper.scala b/modules/rule/src/main/scala/de/nowchess/rules/dto/DtoMapper.scala index 986820e..2c00fc2 100644 --- a/modules/rule/src/main/scala/de/nowchess/rules/dto/DtoMapper.scala +++ b/modules/rule/src/main/scala/de/nowchess/rules/dto/DtoMapper.scala @@ -29,7 +29,7 @@ object DtoMapper: case "castleKingside" => Right(MoveType.CastleKingside) case "castleQueenside" => Right(MoveType.CastleQueenside) case "enPassant" => Right(MoveType.EnPassant) - case "promotion" => + case "promotion" => dto.promotionPiece.toRight("Missing promotion piece").flatMap(toPromotionPiece).map(MoveType.Promotion(_)) case other => Left(s"Unknown move type: $other") @@ -51,13 +51,13 @@ object DtoMapper: moves <- sequenceList(dto.moves.map(toMove)) initialBoard <- toBoard(dto.initialBoard) yield GameContext( - board = board, - turn = turn, - castlingRights = toCastlingRights(dto.castlingRights), + board = board, + turn = turn, + castlingRights = toCastlingRights(dto.castlingRights), enPassantSquare = epSquare, - halfMoveClock = dto.halfMoveClock, - moves = moves, - initialBoard = initialBoard, + halfMoveClock = dto.halfMoveClock, + moves = moves, + initialBoard = initialBoard, ) def fromMove(move: Move): MoveDto = @@ -71,13 +71,13 @@ object DtoMapper: def fromGameContext(ctx: GameContext): GameContextDto = GameContextDto( - board = fromBoard(ctx.board), - turn = ctx.turn.label, - castlingRights = fromCastlingRights(ctx.castlingRights), + board = fromBoard(ctx.board), + turn = ctx.turn.label, + castlingRights = fromCastlingRights(ctx.castlingRights), enPassantSquare = ctx.enPassantSquare.map(_.toString), - halfMoveClock = ctx.halfMoveClock, - moves = ctx.moves.map(fromMove), - initialBoard = fromBoard(ctx.initialBoard), + halfMoveClock = ctx.halfMoveClock, + moves = ctx.moves.map(fromMove), + initialBoard = fromBoard(ctx.initialBoard), ) private def toPromotionPiece(s: String): Either[String, PromotionPiece] = s match diff --git a/modules/rule/src/test/scala/de/nowchess/rules/resource/RuleSetResourceTest.scala b/modules/rule/src/test/scala/de/nowchess/rules/resource/RuleSetResourceTest.scala index d452c9c..bb7209a 100644 --- a/modules/rule/src/test/scala/de/nowchess/rules/resource/RuleSetResourceTest.scala +++ b/modules/rule/src/test/scala/de/nowchess/rules/resource/RuleSetResourceTest.scala @@ -247,11 +247,13 @@ class RuleSetResourceTest: // ── position builders ───────────────────────────────────────────── private def buildCheckContext(): GameContext = - val board = Board(Map( - Square(File.E, Rank.R1) -> Piece(Color.White, PieceType.King), - Square(File.E, Rank.R8) -> Piece(Color.Black, PieceType.King), - Square(File.E, Rank.R3) -> Piece(Color.Black, PieceType.Rook), - )) + val board = Board( + Map( + Square(File.E, Rank.R1) -> Piece(Color.White, PieceType.King), + Square(File.E, Rank.R8) -> Piece(Color.Black, PieceType.King), + Square(File.E, Rank.R3) -> Piece(Color.Black, PieceType.Rook), + ), + ) GameContext(board, Color.White, CastlingRights.None, None, 0, List.empty, initialBoard = board) private def buildFoolsMate(): GameContext = @@ -263,18 +265,22 @@ class RuleSetResourceTest: } private def buildStalemateContext(): GameContext = - val board = Board(Map( - Square(File.H, Rank.R8) -> Piece(Color.Black, PieceType.King), - Square(File.F, Rank.R7) -> Piece(Color.White, PieceType.Queen), - Square(File.G, Rank.R6) -> Piece(Color.White, PieceType.King), - )) + val board = Board( + Map( + Square(File.H, Rank.R8) -> Piece(Color.Black, PieceType.King), + Square(File.F, Rank.R7) -> Piece(Color.White, PieceType.Queen), + Square(File.G, Rank.R6) -> Piece(Color.White, PieceType.King), + ), + ) GameContext(board, Color.Black, CastlingRights.None, None, 0, List.empty, initialBoard = board) private def buildKingsOnlyContext(): GameContext = - val board = Board(Map( - Square(File.E, Rank.R1) -> Piece(Color.White, PieceType.King), - Square(File.E, Rank.R8) -> Piece(Color.Black, PieceType.King), - )) + val board = Board( + Map( + Square(File.E, Rank.R1) -> Piece(Color.White, PieceType.King), + Square(File.E, Rank.R8) -> Piece(Color.Black, PieceType.King), + ), + ) GameContext(board, Color.White, CastlingRights.None, None, 0, List.empty, initialBoard = board) private def buildThreefoldContext(): GameContext = diff --git a/modules/rule/src/test/scala/de/nowchess/rules/resource/RuleSetResourceUnitTest.scala b/modules/rule/src/test/scala/de/nowchess/rules/resource/RuleSetResourceUnitTest.scala index fb7235e..b32f55d 100644 --- a/modules/rule/src/test/scala/de/nowchess/rules/resource/RuleSetResourceUnitTest.scala +++ b/modules/rule/src/test/scala/de/nowchess/rules/resource/RuleSetResourceUnitTest.scala @@ -16,16 +16,18 @@ class RuleSetResourceUnitTest extends AnyFunSuite with Matchers: private def ctx(g: GameContext) = ContextRequest(DtoMapper.fromGameContext(g)) private def ctxSq(g: GameContext, sq: String) = ContextSquareRequest(DtoMapper.fromGameContext(g), sq) - private def ctxMv(g: GameContext, m: Move) = ContextMoveRequest(DtoMapper.fromGameContext(g), DtoMapper.fromMove(m)) + private def ctxMv(g: GameContext, m: Move) = ContextMoveRequest(DtoMapper.fromGameContext(g), DtoMapper.fromMove(m)) // ── position builders ───────────────────────────────────────────── private def checkContext(): GameContext = - val board = Board(Map( - Square(File.E, Rank.R1) -> Piece(Color.White, PieceType.King), - Square(File.E, Rank.R8) -> Piece(Color.Black, PieceType.King), - Square(File.E, Rank.R3) -> Piece(Color.Black, PieceType.Rook), - )) + val board = Board( + Map( + Square(File.E, Rank.R1) -> Piece(Color.White, PieceType.King), + Square(File.E, Rank.R8) -> Piece(Color.Black, PieceType.King), + Square(File.E, Rank.R3) -> Piece(Color.Black, PieceType.Rook), + ), + ) GameContext(board, Color.White, CastlingRights.None, None, 0, List.empty, initialBoard = board) private def foolsMate(): GameContext = @@ -37,18 +39,22 @@ class RuleSetResourceUnitTest extends AnyFunSuite with Matchers: } private def stalemateContext(): GameContext = - val board = Board(Map( - Square(File.H, Rank.R8) -> Piece(Color.Black, PieceType.King), - Square(File.F, Rank.R7) -> Piece(Color.White, PieceType.Queen), - Square(File.G, Rank.R6) -> Piece(Color.White, PieceType.King), - )) + val board = Board( + Map( + Square(File.H, Rank.R8) -> Piece(Color.Black, PieceType.King), + Square(File.F, Rank.R7) -> Piece(Color.White, PieceType.Queen), + Square(File.G, Rank.R6) -> Piece(Color.White, PieceType.King), + ), + ) GameContext(board, Color.Black, CastlingRights.None, None, 0, List.empty, initialBoard = board) private def kingsOnlyContext(): GameContext = - val board = Board(Map( - Square(File.E, Rank.R1) -> Piece(Color.White, PieceType.King), - Square(File.E, Rank.R8) -> Piece(Color.Black, PieceType.King), - )) + val board = Board( + Map( + Square(File.E, Rank.R1) -> Piece(Color.White, PieceType.King), + Square(File.E, Rank.R8) -> Piece(Color.Black, PieceType.King), + ), + ) GameContext(board, Color.White, CastlingRights.None, None, 0, List.empty, initialBoard = board) private def threefoldContext(): GameContext = @@ -100,9 +106,9 @@ class RuleSetResourceUnitTest extends AnyFunSuite with Matchers: test("isCheck throws BadRequestException for invalid context"): an[BadRequestException] should be thrownBy - resource.isCheck(ctx(GameContext.initial).copy(context = - DtoMapper.fromGameContext(GameContext.initial).copy(turn = "Red"), - )) + resource.isCheck( + ctx(GameContext.initial).copy(context = DtoMapper.fromGameContext(GameContext.initial).copy(turn = "Red")), + ) // ── isCheckmate ─────────────────────────────────────────────────── @@ -154,7 +160,8 @@ class RuleSetResourceUnitTest extends AnyFunSuite with Matchers: resource.applyMove(ctxMv(GameContext.initial, move)).turn shouldBe "Black" test("applyMove throws BadRequestException for invalid move"): - val badMove = DtoMapper.fromMove(Move(Square(File.E, Rank.R2), Square(File.E, Rank.R4))) + val badMove = DtoMapper + .fromMove(Move(Square(File.E, Rank.R2), Square(File.E, Rank.R4))) .copy(moveType = "unknown") an[BadRequestException] should be thrownBy resource.applyMove(ContextMoveRequest(DtoMapper.fromGameContext(GameContext.initial), badMove))