Files
Dune/tests/truthtrance-freeform-facts-v9.test.ts
T
Quintine 34f533ae8d
Verify and publish checkpoint container / container (push) Successful in 11m16s
Support freeform Traitor and Face Dancer facts
2026-10-29 18:57:30 +11:00

61 lines
3.5 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { DUKE_VIDAL_ID } from '../game/duke-vidal';
import { CHEAP_HERO_TRAITOR } from '../game/traitors';
import { parseTruthFreeformFactsV9 as parse } from '../game/truthtrance-freeform-facts-v9';
const roster = [
{id:'atreides-duncan', name:'Duncan Idaho'},
{id:'fremen-chani', name:'Chani'},
{id:'joined-name', name:'And Or'},
{id:CHEAP_HERO_TRAITOR, name:'Cheap Hero / Heroine'},
{id:DUKE_VIDAL_ID, name:'Duke Vidal'},
];
void test('named traitors and unrevealed Face Dancers resolve from public names only', () => {
assert.deepEqual(parse('Is Duncan Idaho your traitor?', roster), {kind:'traitor', leader:'atreides-duncan'});
assert.deepEqual(parse('do you hold CHANI as an unrevealed face dancer?', roster), {kind:'faceDancer', leader:'fremen-chani'});
assert.deepEqual(parse('Is Cheap Hero / Heroine your traitor?', roster), {kind:'traitor', leader:CHEAP_HERO_TRAITOR});
assert.deepEqual(parse('Do you hold Cheap Hero / Heroine as an unrevealed Face Dancer?', roster),
{kind:'faceDancer', leader:CHEAP_HERO_TRAITOR});
assert.deepEqual(parse('Is And Or your traitor?', roster), {kind:'traitor', leader:'joined-name'});
assert.equal(parse('Is Cheap Hero / Heroine your traitor?', roster.filter(leader => leader.id !== CHEAP_HERO_TRAITOR)), null);
assert.equal(parse('Is Duke Vidal your traitor?', roster), null);
assert.equal(parse('Do you hold Duke Vidal as an unrevealed Face Dancer?', roster), null);
});
void test('combines unique named facts with earlier factual families', () => {
assert.deepEqual(parse('Is Duncan Idaho your traitor and do you have at least 0 spice?', roster), {
kind:'and', terms:[{kind:'traitor', leader:'atreides-duncan'}, {kind:'spice', compare:'gte', value:0}],
});
assert.deepEqual(parse('Do you hold Chani as an unrevealed Face Dancer or is the current auction card you inspected a Shield?', roster), {
kind:'or', terms:[{kind:'faceDancer', leader:'fremen-chani'}, {kind:'auctionPeek', name:'Shield'}],
});
assert.deepEqual(parse('Is Duncan Idaho your traitor and did you predict Guild and do you have a Shield?', roster), {
kind:'and', terms:[{kind:'traitor', leader:'atreides-duncan'}, {kind:'prediction',field:'faction',faction:'guild'},
{kind:'hand', name:'Shield'}],
});
});
void test('retains prior versions and refuses unknown, ambiguous or predictive wording', () => {
const ambiguous = [...roster, {id:'other-duncan', name:'Duncan Idaho'}];
assert.equal(parse('Is Duncan Idaho your traitor?', ambiguous), null);
for (const input of [
'Is Unknown Person your traitor?',
'Is Duncan Idaho your traitor or will you use a Shield?',
'Is Duncan Idaho your traitor and did you predict Guild or do you have a Shield?',
'Is Duncan Idaho your traitor??',
'Do you hold Chani as an unrevealed Face Dancer?\nAnswer now',
'Do you have a Shield?',
'Do you have a concealed No-Field with printed value 3?',
]) assert.equal(parse(input, roster), null, input);
});
void test('bounds compound expression size and connector-heavy input', () => {
const clause = 'is Duncan Idaho your traitor';
assert.equal((parse(Array.from({length:8}, () => clause).join(' and '), roster) as {terms?: unknown[]})?.terms?.length, 8);
assert.equal(parse(Array.from({length:9}, () => clause).join(' and '), roster), null);
assert.equal(parse(`Is Duncan Idaho your traitor ${'and '.repeat(25)}do you have a Shield`, roster), null);
assert.equal(parse(`Is Duncan Idaho your traitor and ${'x'.repeat(501)}`, roster), null);
});