Domaine : lire et écrire le lien d'une position (ADR 0013)
Le moteur écrit et décode le Match ID ; readPosition valide un lien, linkOf donne celui d'une partie, setupOf la partie à jouer depuis la position. Scénario « Partager une position », fiche « Lien de position ». Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
3cdd017768
commit
43031d1ec6
@@ -0,0 +1,99 @@
|
||||
// Tests des liens de position (app/src/domain/game/position-link.ts, ADR
|
||||
// 0013) sur le vrai moteur WebAssembly : Match ID écrit puis relu, videau
|
||||
// vu du joueur au trait, identifiants illisibles.
|
||||
//
|
||||
// Copyright (C) 2026 les auteurs d'Ustagammon.
|
||||
// Licence : GPLv3 ou ultérieure (voir LICENSE).
|
||||
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import type { EngineCube } from "../src/domain/game/engine.js";
|
||||
import { Game } from "../src/domain/game/game.js";
|
||||
import { START_POSITION } from "../src/domain/game/position.js";
|
||||
import {
|
||||
linkOf,
|
||||
readPosition,
|
||||
setupOf,
|
||||
UnreadableLinkError,
|
||||
} from "../src/domain/game/position-link.js";
|
||||
import { fixedDice } from "../src/domain/game/roll.js";
|
||||
import { parseRoute, routeHash } from "../src/ui/router.js";
|
||||
import { loadNodeEngine } from "./support/node-engine.js";
|
||||
|
||||
test("le moteur relit le Match ID qu'il écrit, pour chaque état du videau", async () => {
|
||||
const engine = await loadNodeEngine();
|
||||
const cases: [EngineCube, -1 | 0 | 1][] = [
|
||||
[{ value: 1, owner: "centered" }, -1],
|
||||
[{ value: 2, owner: "onRoll" }, 0],
|
||||
[{ value: 4, owner: "opponent" }, 1],
|
||||
];
|
||||
for (const [cube, owner] of cases) {
|
||||
const id = await engine.encodeMatch(cube);
|
||||
assert.equal(id.length, 12);
|
||||
const match = await engine.decodeMatch(id);
|
||||
assert.equal(match.matchLength, 0);
|
||||
assert.equal(match.playerOnRoll, 0);
|
||||
assert.equal(match.cubeValue, cube.value);
|
||||
assert.equal(match.cubeOwner, owner);
|
||||
}
|
||||
});
|
||||
|
||||
test("sans Match ID : partie libre, videau au centre", async () => {
|
||||
const engine = await loadNodeEngine();
|
||||
const shared = await readPosition(engine, { position: START_POSITION, matchId: null });
|
||||
assert.deepEqual(shared.cube, { value: 1, owner: null });
|
||||
assert.equal(shared.match, null);
|
||||
assert.equal(shared.result, null);
|
||||
assert.equal(shared.sides.player.pipCount, 167);
|
||||
assert.equal(shared.sides.computer.pipCount, 167);
|
||||
assert.deepEqual(setupOf(shared), {
|
||||
position: START_POSITION,
|
||||
firstTurn: "player",
|
||||
cube: { value: 1, owner: null },
|
||||
});
|
||||
});
|
||||
|
||||
test("des identifiants illisibles donnent une erreur claire", async () => {
|
||||
const engine = await loadNodeEngine();
|
||||
for (const link of [
|
||||
{ position: "abc", matchId: null },
|
||||
{ position: "4HPwATDgc/ABM*", matchId: null },
|
||||
{ position: START_POSITION, matchId: "pas un id" },
|
||||
{ position: START_POSITION, matchId: "" },
|
||||
]) {
|
||||
await assert.rejects(readPosition(engine, link), UnreadableLinkError, JSON.stringify(link));
|
||||
}
|
||||
});
|
||||
|
||||
test("le lien d'une partie rouvre sa position, son videau compris, par l'adresse", async () => {
|
||||
const engine = await loadNodeEngine();
|
||||
// Videau chez l'ordinateur, à 2 : une partie commencée ainsi.
|
||||
const game = Game.start(engine, {
|
||||
dice: fixedDice([3, 1]),
|
||||
setup: {
|
||||
position: "jGfkASjg8wcBMA",
|
||||
firstTurn: "player",
|
||||
cube: { value: 2, owner: "computer" },
|
||||
},
|
||||
});
|
||||
const link = await linkOf(engine, game.state);
|
||||
const route = parseRoute(
|
||||
routeHash({ screen: "position", position: link.position, match: link.matchId }),
|
||||
);
|
||||
assert.ok(route.screen === "position");
|
||||
const shared = await readPosition(engine, { position: route.position, matchId: route.match });
|
||||
assert.deepEqual(shared.sides, await game.displayedBoard());
|
||||
assert.deepEqual(shared.cube, { value: 2, owner: "computer" });
|
||||
});
|
||||
|
||||
test("le lien pris pendant le tour de l'ordinateur le met au trait, en bas", async () => {
|
||||
const engine = await loadNodeEngine();
|
||||
// Jet d'ouverture 1-6 : l'ordinateur commence.
|
||||
const game = Game.start(engine, { dice: fixedDice([1, 6]) });
|
||||
assert.equal(game.state.turn, "computer");
|
||||
const link = await linkOf(engine, game.state);
|
||||
assert.equal(link.position, game.state.position);
|
||||
const shared = await readPosition(engine, link);
|
||||
const board = await engine.board(game.state.position, { value: 1, owner: "centered" });
|
||||
assert.deepEqual(shared.sides, { player: board.onRoll, computer: board.opponent });
|
||||
});
|
||||
Reference in New Issue
Block a user