Files
Dune/tests/ghola-leader-promises.test.ts
T
Quintine c1ffa1c28a
Verify and publish checkpoint container / container (push) Successful in 10m45s
Prototype named Ghola leader Truthtrance promises
2026-10-29 17:34:55 +11:00

52 lines
3.6 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { GholaLeaderPromiseError, gholaLeaderClaimText, gholaLeaderRequirements,
liveGholaLeaderPromises, parseGholaLeaderClaim, recordPromisedGholaLeader,
validateGholaLeaderPromises, type GholaLeaderPromise } from '../game/ghola-leader-promises';
const promise = (event: string, leader = 'leader-a', changes: Partial<GholaLeaderPromise> = {}): GholaLeaderPromise =>
({ event, player: 'target', asker: 'asker', turn: 2, leader, answer: true, ...changes });
void test('named Ghola claims require a current turn and exact identity without coercion', () => {
assert.deepEqual(parseGholaLeaderClaim({ kind: 'gholaLeader', target: 'target', turn: 2, leader: 'kwisatz' }),
{ turn: 2, leader: 'kwisatz' });
assert.match(gholaLeaderClaimText({ turn: 2, leader: 'kwisatz' }), /Kwisatz Haderach.*Ghola/);
for (const value of [null, [], {}, { turn: 0, leader: 'a' }, { turn: 2.5, leader: 'a' },
{ turn: '2', leader: 'a' }, { turn: 2, leader: '' }, { turn: 2, leader: ' a' }])
assert.throws(() => parseGholaLeaderClaim(value), GholaLeaderPromiseError);
});
void test('live obligations combine duplicates, flag conflicts, and do not grant extra Ghola uses', () => {
const records = [promise('a'), promise('a-again'), promise('no', 'leader-b', { answer: false }),
promise('old', 'leader-c', { turn: 1 }), promise('other', 'leader-d', { player: 'other' }),
promise('done', 'leader-e', { fulfilled: true }), promise('released', 'leader-f', { released: true })];
assert.deepEqual(liveGholaLeaderPromises(records, 'target', 2), records.slice(0, 3));
assert.deepEqual(gholaLeaderRequirements(records, 'target', 2), { required: ['leader-a'], forbidden: ['leader-b'] });
assert.equal(gholaLeaderRequirements([...records, promise('contradiction', 'leader-a', { answer: false })], 'target', 2), null);
});
void test('only an actual matching return fulfills Yes, and No rejects without mutation', () => {
const records = [promise('a'), promise('a-again'), promise('no', 'leader-b', { answer: false }),
promise('other', 'leader-a', { player: 'other' }), promise('earlier', 'leader-a', { fulfilled: true })];
const before = structuredClone(records);
assert.throws(() => recordPromisedGholaLeader(records, 'target', 2, 'leader-b'), GholaLeaderPromiseError);
assert.deepEqual(records, before);
const after = recordPromisedGholaLeader(records, 'target', 2, 'leader-a');
assert.equal(after[0].fulfilled, true); assert.equal(after[1].fulfilled, true);
assert.equal(after[2], records[2]); assert.equal(after[3], records[3]); assert.equal(after[4], records[4]);
assert.deepEqual(records, before);
const unrelated = recordPromisedGholaLeader(records, 'target', 2, 'kwisatz');
assert.equal(unrelated[0], records[0]);
assert.throws(() => recordPromisedGholaLeader(records, 'target', 2, ' leader-a'), GholaLeaderPromiseError);
});
void test('ledger validation enforces participants, unique events and terminal state', () => {
const valid = [promise('a'), promise('b', 'kwisatz', { answer: false }), promise('c', 'leader-c', { released: true })];
assert.doesNotThrow(() => validateGholaLeaderPromises(JSON.parse(JSON.stringify(valid)), ['target', 'asker']));
for (const invalid of [null, [null], [promise('a'), promise('a')],
[promise('bad', 'a', { asker: 'target' })], [promise('bad', 'a', { player: 'absent' })],
[promise('bad', 'a', { fulfilled: true, released: true })],
[{ ...promise('bad'), answer: 'yes' }]])
assert.throws(() => validateGholaLeaderPromises(invalid as GholaLeaderPromise[], ['target', 'asker']), GholaLeaderPromiseError);
});