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>
100 lines
4.1 KiB
TypeScript
100 lines
4.1 KiB
TypeScript
// 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 });
|
|
});
|