fix(rules): Serializers
Added serializers like in IO
This commit is contained in:
@@ -3,12 +3,6 @@ package de.nowchess.rules.dto
|
||||
import de.nowchess.api.game.GameContext
|
||||
import de.nowchess.api.move.Move
|
||||
|
||||
case class ContextRequest(context: GameContext)
|
||||
|
||||
case class ContextSquareRequest(context: GameContext, square: String)
|
||||
|
||||
case class ContextMoveRequest(context: GameContext, move: Move)
|
||||
|
||||
case class MovesResponse(moves: List[Move])
|
||||
|
||||
case class BooleanResponse(result: Boolean)
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.nowchess.rules.resource
|
||||
|
||||
import de.nowchess.api.board.Square
|
||||
import de.nowchess.api.game.GameContext
|
||||
import de.nowchess.api.move.Move
|
||||
import de.nowchess.rules.dto.*
|
||||
import de.nowchess.rules.sets.DefaultRules
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
@@ -22,64 +23,64 @@ class RuleSetResource:
|
||||
@Path("/candidate-moves")
|
||||
@Consumes(Array(MediaType.APPLICATION_JSON))
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
def candidateMoves(req: ContextSquareRequest): MovesResponse =
|
||||
MovesResponse(rules.candidateMoves(req.context)(parseSquare(req.square)))
|
||||
def candidateMoves(req: ContextSquareRequest): List[Move] =
|
||||
rules.candidateMoves(req.context)(parseSquare(req.square))
|
||||
|
||||
@POST
|
||||
@Path("/legal-moves")
|
||||
@Consumes(Array(MediaType.APPLICATION_JSON))
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
def legalMoves(req: ContextSquareRequest): MovesResponse =
|
||||
MovesResponse(rules.legalMoves(req.context)(parseSquare(req.square)))
|
||||
def legalMoves(req: ContextSquareRequest): List[Move] =
|
||||
rules.legalMoves(req.context)(parseSquare(req.square))
|
||||
|
||||
@POST
|
||||
@Path("/all-legal-moves")
|
||||
@Consumes(Array(MediaType.APPLICATION_JSON))
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
def allLegalMoves(req: ContextRequest): MovesResponse =
|
||||
MovesResponse(rules.allLegalMoves(req.context))
|
||||
def allLegalMoves(ctx: GameContext): List[Move] =
|
||||
rules.allLegalMoves(ctx)
|
||||
|
||||
@POST
|
||||
@Path("/is-check")
|
||||
@Consumes(Array(MediaType.APPLICATION_JSON))
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
def isCheck(req: ContextRequest): BooleanResponse =
|
||||
BooleanResponse(rules.isCheck(req.context))
|
||||
def isCheck(ctx: GameContext): Boolean =
|
||||
rules.isCheck(ctx)
|
||||
|
||||
@POST
|
||||
@Path("/is-checkmate")
|
||||
@Consumes(Array(MediaType.APPLICATION_JSON))
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
def isCheckmate(req: ContextRequest): BooleanResponse =
|
||||
BooleanResponse(rules.isCheckmate(req.context))
|
||||
def isCheckmate(ctx: GameContext): Boolean =
|
||||
rules.isCheckmate(ctx)
|
||||
|
||||
@POST
|
||||
@Path("/is-stalemate")
|
||||
@Consumes(Array(MediaType.APPLICATION_JSON))
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
def isStalemate(req: ContextRequest): BooleanResponse =
|
||||
BooleanResponse(rules.isStalemate(req.context))
|
||||
def isStalemate(ctx: GameContext): Boolean =
|
||||
rules.isStalemate(ctx)
|
||||
|
||||
@POST
|
||||
@Path("/is-insufficient-material")
|
||||
@Consumes(Array(MediaType.APPLICATION_JSON))
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
def isInsufficientMaterial(req: ContextRequest): BooleanResponse =
|
||||
BooleanResponse(rules.isInsufficientMaterial(req.context))
|
||||
def isInsufficientMaterial(ctx: GameContext): Boolean =
|
||||
rules.isInsufficientMaterial(ctx)
|
||||
|
||||
@POST
|
||||
@Path("/is-fifty-move-rule")
|
||||
@Consumes(Array(MediaType.APPLICATION_JSON))
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
def isFiftyMoveRule(req: ContextRequest): BooleanResponse =
|
||||
BooleanResponse(rules.isFiftyMoveRule(req.context))
|
||||
def isFiftyMoveRule(ctx: GameContext): Boolean =
|
||||
rules.isFiftyMoveRule(ctx)
|
||||
|
||||
@POST
|
||||
@Path("/is-threefold-repetition")
|
||||
@Consumes(Array(MediaType.APPLICATION_JSON))
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
def isThreefoldRepetition(req: ContextRequest): BooleanResponse =
|
||||
BooleanResponse(rules.isThreefoldRepetition(req.context))
|
||||
def isThreefoldRepetition(ctx: GameContext): Boolean =
|
||||
rules.isThreefoldRepetition(ctx)
|
||||
|
||||
@POST
|
||||
@Path("/apply-move")
|
||||
|
||||
@@ -5,7 +5,7 @@ import de.nowchess.api.board.{Board, CastlingRights, Color, File, Piece, PieceTy
|
||||
import de.nowchess.api.game.GameContext
|
||||
import de.nowchess.api.move.Move
|
||||
import de.nowchess.rules.config.JacksonConfig
|
||||
import de.nowchess.rules.dto.{ContextMoveRequest, ContextRequest, ContextSquareRequest}
|
||||
import de.nowchess.rules.dto.{ContextMoveRequest, ContextSquareRequest}
|
||||
import de.nowchess.rules.sets.DefaultRules
|
||||
import io.quarkus.test.junit.QuarkusTest
|
||||
import io.restassured.RestAssured
|
||||
@@ -27,9 +27,6 @@ class RuleSetResourceTest:
|
||||
|
||||
private def toJson(value: AnyRef): String = mapper.writeValueAsString(value)
|
||||
|
||||
private def contextBody(ctx: GameContext): String =
|
||||
toJson(ContextRequest(ctx))
|
||||
|
||||
private def contextSquareBody(ctx: GameContext, square: String): String =
|
||||
toJson(ContextSquareRequest(ctx, square))
|
||||
|
||||
@@ -42,12 +39,12 @@ class RuleSetResourceTest:
|
||||
def allLegalMoves_initialPositionHas20Moves(): Unit =
|
||||
request()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(contextBody(GameContext.initial))
|
||||
.body(toJson(GameContext.initial))
|
||||
.when()
|
||||
.post("/api/rules/all-legal-moves")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("moves.size()", is(20))
|
||||
.body("size()", is(20))
|
||||
|
||||
// ── legal-moves ───────────────────────────────────────────────────
|
||||
|
||||
@@ -60,7 +57,7 @@ class RuleSetResourceTest:
|
||||
.post("/api/rules/legal-moves")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("moves.size()", is(2))
|
||||
.body("size()", is(2))
|
||||
|
||||
// ── candidate-moves ───────────────────────────────────────────────
|
||||
|
||||
@@ -73,7 +70,7 @@ class RuleSetResourceTest:
|
||||
.post("/api/rules/candidate-moves")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("moves.size()", is(2))
|
||||
.body("size()", is(2))
|
||||
|
||||
// ── is-check ──────────────────────────────────────────────────────
|
||||
|
||||
@@ -81,23 +78,23 @@ class RuleSetResourceTest:
|
||||
def isCheck_falseForInitialPosition(): Unit =
|
||||
request()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(contextBody(GameContext.initial))
|
||||
.body(toJson(GameContext.initial))
|
||||
.when()
|
||||
.post("/api/rules/is-check")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("result", is(false))
|
||||
.body(is("false"))
|
||||
|
||||
@Test
|
||||
def isCheck_trueWhenKingAttacked(): Unit =
|
||||
request()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(contextBody(buildCheckContext()))
|
||||
.body(toJson(buildCheckContext()))
|
||||
.when()
|
||||
.post("/api/rules/is-check")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("result", is(true))
|
||||
.body(is("true"))
|
||||
|
||||
// ── is-checkmate ──────────────────────────────────────────────────
|
||||
|
||||
@@ -105,23 +102,23 @@ class RuleSetResourceTest:
|
||||
def isCheckmate_falseForInitialPosition(): Unit =
|
||||
request()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(contextBody(GameContext.initial))
|
||||
.body(toJson(GameContext.initial))
|
||||
.when()
|
||||
.post("/api/rules/is-checkmate")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("result", is(false))
|
||||
.body(is("false"))
|
||||
|
||||
@Test
|
||||
def isCheckmate_trueForFoolsMate(): Unit =
|
||||
request()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(contextBody(buildFoolsMate()))
|
||||
.body(toJson(buildFoolsMate()))
|
||||
.when()
|
||||
.post("/api/rules/is-checkmate")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("result", is(true))
|
||||
.body(is("true"))
|
||||
|
||||
// ── is-stalemate ──────────────────────────────────────────────────
|
||||
|
||||
@@ -129,23 +126,23 @@ class RuleSetResourceTest:
|
||||
def isStalemate_falseForInitialPosition(): Unit =
|
||||
request()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(contextBody(GameContext.initial))
|
||||
.body(toJson(GameContext.initial))
|
||||
.when()
|
||||
.post("/api/rules/is-stalemate")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("result", is(false))
|
||||
.body(is("false"))
|
||||
|
||||
@Test
|
||||
def isStalemate_trueForStalematePosition(): Unit =
|
||||
request()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(contextBody(buildStalemateContext()))
|
||||
.body(toJson(buildStalemateContext()))
|
||||
.when()
|
||||
.post("/api/rules/is-stalemate")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("result", is(true))
|
||||
.body(is("true"))
|
||||
|
||||
// ── is-insufficient-material ──────────────────────────────────────
|
||||
|
||||
@@ -153,23 +150,23 @@ class RuleSetResourceTest:
|
||||
def isInsufficientMaterial_falseForInitialPosition(): Unit =
|
||||
request()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(contextBody(GameContext.initial))
|
||||
.body(toJson(GameContext.initial))
|
||||
.when()
|
||||
.post("/api/rules/is-insufficient-material")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("result", is(false))
|
||||
.body(is("false"))
|
||||
|
||||
@Test
|
||||
def isInsufficientMaterial_trueForKingsOnly(): Unit =
|
||||
request()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(contextBody(buildKingsOnlyContext()))
|
||||
.body(toJson(buildKingsOnlyContext()))
|
||||
.when()
|
||||
.post("/api/rules/is-insufficient-material")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("result", is(true))
|
||||
.body(is("true"))
|
||||
|
||||
// ── is-fifty-move-rule ────────────────────────────────────────────
|
||||
|
||||
@@ -177,23 +174,23 @@ class RuleSetResourceTest:
|
||||
def isFiftyMoveRule_falseForInitialPosition(): Unit =
|
||||
request()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(contextBody(GameContext.initial))
|
||||
.body(toJson(GameContext.initial))
|
||||
.when()
|
||||
.post("/api/rules/is-fifty-move-rule")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("result", is(false))
|
||||
.body(is("false"))
|
||||
|
||||
@Test
|
||||
def isFiftyMoveRule_trueWhenClockAt100(): Unit =
|
||||
request()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(contextBody(GameContext.initial.copy(halfMoveClock = 100)))
|
||||
.body(toJson(GameContext.initial.copy(halfMoveClock = 100)))
|
||||
.when()
|
||||
.post("/api/rules/is-fifty-move-rule")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("result", is(true))
|
||||
.body(is("true"))
|
||||
|
||||
// ── is-threefold-repetition ───────────────────────────────────────
|
||||
|
||||
@@ -201,23 +198,23 @@ class RuleSetResourceTest:
|
||||
def isThreefoldRepetition_falseForInitialPosition(): Unit =
|
||||
request()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(contextBody(GameContext.initial))
|
||||
.body(toJson(GameContext.initial))
|
||||
.when()
|
||||
.post("/api/rules/is-threefold-repetition")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("result", is(false))
|
||||
.body(is("false"))
|
||||
|
||||
@Test
|
||||
def isThreefoldRepetition_trueAfterRepeatedMoves(): Unit =
|
||||
request()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(contextBody(buildThreefoldContext()))
|
||||
.body(toJson(buildThreefoldContext()))
|
||||
.when()
|
||||
.post("/api/rules/is-threefold-repetition")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("result", is(true))
|
||||
.body(is("true"))
|
||||
|
||||
// ── apply-move ────────────────────────────────────────────────────
|
||||
|
||||
|
||||
+16
-17
@@ -3,7 +3,7 @@ package de.nowchess.rules.resource
|
||||
import de.nowchess.api.board.{Board, CastlingRights, Color, File, Piece, PieceType, Rank, Square}
|
||||
import de.nowchess.api.game.GameContext
|
||||
import de.nowchess.api.move.Move
|
||||
import de.nowchess.rules.dto.{ContextMoveRequest, ContextRequest, ContextSquareRequest}
|
||||
import de.nowchess.rules.dto.{ContextMoveRequest, ContextSquareRequest}
|
||||
import de.nowchess.rules.sets.DefaultRules
|
||||
import jakarta.ws.rs.BadRequestException
|
||||
import org.scalatest.funsuite.AnyFunSuite
|
||||
@@ -14,7 +14,6 @@ class RuleSetResourceUnitTest extends AnyFunSuite with Matchers:
|
||||
private val resource = new RuleSetResource()
|
||||
private val rules = DefaultRules
|
||||
|
||||
private def ctx(g: GameContext) = ContextRequest(g)
|
||||
private def ctxSq(g: GameContext, sq: String) = ContextSquareRequest(g, sq)
|
||||
private def ctxMv(g: GameContext, m: Move) = ContextMoveRequest(g, m)
|
||||
|
||||
@@ -76,12 +75,12 @@ class RuleSetResourceUnitTest extends AnyFunSuite with Matchers:
|
||||
// ── allLegalMoves ─────────────────────────────────────────────────
|
||||
|
||||
test("allLegalMoves returns 20 moves for initial position"):
|
||||
resource.allLegalMoves(ctx(GameContext.initial)).moves should have size 20
|
||||
resource.allLegalMoves(GameContext.initial) should have size 20
|
||||
|
||||
// ── legalMoves ────────────────────────────────────────────────────
|
||||
|
||||
test("legalMoves returns 2 moves for e2 pawn"):
|
||||
resource.legalMoves(ctxSq(GameContext.initial, "e2")).moves should have size 2
|
||||
resource.legalMoves(ctxSq(GameContext.initial, "e2")) should have size 2
|
||||
|
||||
test("legalMoves throws BadRequestException for invalid square"):
|
||||
an[BadRequestException] should be thrownBy
|
||||
@@ -90,7 +89,7 @@ class RuleSetResourceUnitTest extends AnyFunSuite with Matchers:
|
||||
// ── candidateMoves ────────────────────────────────────────────────
|
||||
|
||||
test("candidateMoves returns moves for e2 pawn"):
|
||||
resource.candidateMoves(ctxSq(GameContext.initial, "e2")).moves should not be empty
|
||||
resource.candidateMoves(ctxSq(GameContext.initial, "e2")) should not be empty
|
||||
|
||||
test("candidateMoves throws BadRequestException for invalid square"):
|
||||
an[BadRequestException] should be thrownBy
|
||||
@@ -99,50 +98,50 @@ class RuleSetResourceUnitTest extends AnyFunSuite with Matchers:
|
||||
// ── isCheck ───────────────────────────────────────────────────────
|
||||
|
||||
test("isCheck returns false for initial position"):
|
||||
resource.isCheck(ctx(GameContext.initial)).result shouldBe false
|
||||
resource.isCheck(GameContext.initial) shouldBe false
|
||||
|
||||
test("isCheck returns true when king is attacked"):
|
||||
resource.isCheck(ctx(checkContext())).result shouldBe true
|
||||
resource.isCheck(checkContext()) shouldBe true
|
||||
|
||||
// ── isCheckmate ───────────────────────────────────────────────────
|
||||
|
||||
test("isCheckmate returns false for initial position"):
|
||||
resource.isCheckmate(ctx(GameContext.initial)).result shouldBe false
|
||||
resource.isCheckmate(GameContext.initial) shouldBe false
|
||||
|
||||
test("isCheckmate returns true for Fool's mate"):
|
||||
resource.isCheckmate(ctx(foolsMate())).result shouldBe true
|
||||
resource.isCheckmate(foolsMate()) shouldBe true
|
||||
|
||||
// ── isStalemate ───────────────────────────────────────────────────
|
||||
|
||||
test("isStalemate returns false for initial position"):
|
||||
resource.isStalemate(ctx(GameContext.initial)).result shouldBe false
|
||||
resource.isStalemate(GameContext.initial) shouldBe false
|
||||
|
||||
test("isStalemate returns true for stalemate position"):
|
||||
resource.isStalemate(ctx(stalemateContext())).result shouldBe true
|
||||
resource.isStalemate(stalemateContext()) shouldBe true
|
||||
|
||||
// ── isInsufficientMaterial ────────────────────────────────────────
|
||||
|
||||
test("isInsufficientMaterial returns false for initial position"):
|
||||
resource.isInsufficientMaterial(ctx(GameContext.initial)).result shouldBe false
|
||||
resource.isInsufficientMaterial(GameContext.initial) shouldBe false
|
||||
|
||||
test("isInsufficientMaterial returns true for kings only"):
|
||||
resource.isInsufficientMaterial(ctx(kingsOnlyContext())).result shouldBe true
|
||||
resource.isInsufficientMaterial(kingsOnlyContext()) shouldBe true
|
||||
|
||||
// ── isFiftyMoveRule ───────────────────────────────────────────────
|
||||
|
||||
test("isFiftyMoveRule returns false for initial position"):
|
||||
resource.isFiftyMoveRule(ctx(GameContext.initial)).result shouldBe false
|
||||
resource.isFiftyMoveRule(GameContext.initial) shouldBe false
|
||||
|
||||
test("isFiftyMoveRule returns true when halfMoveClock is 100"):
|
||||
resource.isFiftyMoveRule(ctx(GameContext.initial.copy(halfMoveClock = 100))).result shouldBe true
|
||||
resource.isFiftyMoveRule(GameContext.initial.copy(halfMoveClock = 100)) shouldBe true
|
||||
|
||||
// ── isThreefoldRepetition ─────────────────────────────────────────
|
||||
|
||||
test("isThreefoldRepetition returns false for initial position"):
|
||||
resource.isThreefoldRepetition(ctx(GameContext.initial)).result shouldBe false
|
||||
resource.isThreefoldRepetition(GameContext.initial) shouldBe false
|
||||
|
||||
test("isThreefoldRepetition returns true after repeated moves"):
|
||||
resource.isThreefoldRepetition(ctx(threefoldContext())).result shouldBe true
|
||||
resource.isThreefoldRepetition(threefoldContext()) shouldBe true
|
||||
|
||||
// ── applyMove ─────────────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user