37 lines
1.9 KiB
TypeScript
37 lines
1.9 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { createGame, joinGame, newPlayer, type Game } from '../game/engine';
|
|
import { truthQuestionText, validateTruthQuestionReceipt, type TruthQuestion } from '../game/truthtrance';
|
|
|
|
/** Parser-only game; this does not claim a legal Ghola completion or bind an answer. */
|
|
function gameAt(phase: number): Game {
|
|
const g = createGame('GHOLATRUTHPARSER', newPlayer('a', 'Asker', 'atreides'));
|
|
joinGame(g, newPlayer('p', 'Respondent', 'harkonnen'));
|
|
g.status = 'playing'; g.turn = 2; g.phase = phase;
|
|
return g;
|
|
}
|
|
const question = { kind: 'gholaLeader', target: 'p', turn: 2, leader: 'named-leader' } as const;
|
|
|
|
void test('Ghola named-leader questions parse through quiet phases until turn end', () => {
|
|
for (const phase of [0, 4, 7]) {
|
|
const game = gameAt(phase);
|
|
assert.doesNotThrow(() => validateTruthQuestionReceipt(game, 'a', question));
|
|
}
|
|
assert.match(truthQuestionText(question, id => id === 'named-leader' ? 'Named Commander' : id, id => id),
|
|
/revive Named Commander with Ghola.*end of this turn/);
|
|
assert.match(truthQuestionText({ ...question, leader: 'kwisatz' }, id => id, id => id), /Kwisatz Haderach/);
|
|
assert.throws(() => validateTruthQuestionReceipt(gameAt(8), 'a', question));
|
|
});
|
|
|
|
void test('Ghola question rejects stale, self-targeted and noncanonical receipts', () => {
|
|
const game = gameAt(4);
|
|
for (const malformed of [
|
|
{ ...question, turn: 1 }, { ...question, target: 'a' }, { ...question, target: 'absent' },
|
|
{ ...question, leader: '' }, { ...question, leader: ' named-leader' },
|
|
{ ...question, extra: true },
|
|
]) assert.throws(() => validateTruthQuestionReceipt(game, 'a', malformed as TruthQuestion));
|
|
const busy = gameAt(4);
|
|
busy.phaseOpening = { passed: [], initialize: false };
|
|
assert.throws(() => validateTruthQuestionReceipt(busy, 'a', question));
|
|
});
|