import assert from 'node:assert/strict'; import test from 'node:test'; import { parseKaramaFremenSpecialSource as parse, windowCardNativeEffect, windowCardOpportunity, type WindowCardGame } from '../game/window-card-play'; const source = (): WindowCardGame => ({ status: 'playing', advanced: true, phase: 1, turn: 2, shieldWallDestroyed: false, players: [{ id: 'h', faction: 'fremen', specialKaramaUsed: false }, { id: 'a', faction: 'atreides', specialKaramaUsed: false }] }); const event = JSON.stringify(['karamaFremenSpecial', 2, 'h']); void test('Fremen special window is public, turn-bound and independent of private custody', () => { const game = source(), before = structuredClone(game); assert.deepEqual(windowCardOpportunity(game, 'karamaFremenSpecial'), { effect: 'karamaFremenSpecial', source: event, turn: 2 }); assert.deepEqual(parse(event), { turn: 2, owner: 'h' }); assert.equal(windowCardNativeEffect('karamaFremenSpecial'), 'karama'); assert.equal(windowCardOpportunity({ ...game, response: { kind: 'voice' }, decision: { kind: 'other' } }, 'karamaFremenSpecial')?.source, event); assert.equal(windowCardOpportunity(game, 'karamaFremenSpecial', event)?.source, event); assert.deepEqual(game, before); }); void test('special opportunity ends with use, turn or phase; malformed sources reject', () => { const game = source(); for (const changes of [{ status: 'lobby' }, { advanced: false }, { phase: 4 }, { turn: 0 }, { players: [{ id: 'h', faction: 'fremen', specialKaramaUsed: true }] }, { players: [{ id: 'h', faction: 'atreides' }] }, { players: [{ id: 'h', faction: 'fremen' }, { id: 'h', faction: 'atreides' }] }, { players: [{ id: 'h', faction: 'fremen' }, { id: 'h2', faction: 'fremen' }] }]) assert.equal(windowCardOpportunity({ ...game, ...changes } as WindowCardGame, 'karamaFremenSpecial'), null); for (const value of ['', '[]', '["karamaFremenSpecial",2," h"]', '["karamaFremenSpecial", 2,"h"]', '["karamaFremenSpecial",0,"h"]', '["karamaFremenSpecial",2,"h","extra"]']) assert.equal(parse(value), null); assert.equal(windowCardOpportunity(game, 'karamaFremenSpecial', JSON.stringify(['karamaFremenSpecial', 2, 'a'])), null); assert.equal(windowCardOpportunity({ ...game, turn: 3 }, 'karamaFremenSpecial', event), null); assert.ok(windowCardOpportunity({ ...game, players: [{ id: 'h', faction: 'fremen' }] }, 'karamaFremenSpecial')); });