import assert from 'node:assert/strict'; import test from 'node:test'; import { matchesShipment, parseShipmentClaim, parseShipmentExpression, shipmentClaimDestinations, shipmentClaimHasNoField, shipmentClaimText, ShipmentClaimError, } from '../game/shipment-promises'; import { TERRITORIES } from '../game/board'; import { shipmentExpressionInputError, shipmentExpressionInputSize } from '../game/shipment-expression-input'; void test('a No-Field shipment statement keeps identity and denomination private', () => { const wildcard = parseShipmentClaim({ claim: { kind: 'noField' } }); assert.deepEqual(wildcard, { claim: { kind: 'noField' } }); assert.equal(shipmentClaimHasNoField(wildcard), true); assert.deepEqual(shipmentClaimDestinations(wildcard), TERRITORIES.map(t => t.id)); assert.equal(shipmentClaimText(wildcard), 'ship your No-Field from your reserves'); assert.equal(matchesShipment(wildcard, null), false); assert.equal(matchesShipment(wildcard, { territory: 'carthag', sector: 11, amount: 1 }), false); assert.equal(matchesShipment(wildcard, { territory: 'carthag', sector: 11, amount: 0, noField: true }), true); assert.equal(shipmentExpressionInputError({ kind: 'noField' }), null); assert.deepEqual(shipmentExpressionInputSize({ kind: 'noField' }), { leaves: 1, depth: 0 }); const target = parseShipmentClaim({ claim: { kind: 'noField', territory: 'carthag', sector: 11 } }); assert.deepEqual(shipmentClaimDestinations(target), ['carthag']); assert.match(shipmentClaimText(target), /Carthag, sector 11/); assert.equal(matchesShipment(target, { territory: 'carthag', sector: 11, amount: 0, noField: true }), true); assert.equal(matchesShipment(target, { territory: 'carthag', sector: 10, amount: 0, noField: true }), false); assert.equal(matchesShipment(target, { territory: 'arrakeen', sector: 10, amount: 0, noField: true }), false); }); void test('No-Field and physical clauses constrain the same real shipment', () => { const claim = parseShipmentClaim({ claim: { op: 'and', terms: [ { kind: 'noField', territory: 'carthag' }, { territory: 'carthag', minimum: 2 }, ] } }); assert.equal(matchesShipment(claim, { territory: 'carthag', sector: 11, amount: 2, noField: true }), true); assert.equal(matchesShipment(claim, { territory: 'carthag', sector: 11, amount: 1, noField: true }), false); assert.equal(matchesShipment(claim, { territory: 'carthag', sector: 11, amount: 2 }), false); assert.equal(matchesShipment(claim, null), false); const old = parseShipmentClaim({ territory: 'carthag', minimum: 1 }); assert.equal(shipmentClaimHasNoField(old), false); assert.equal(shipmentClaimHasNoField(claim), true); assert.equal(matchesShipment(old, { territory: 'carthag', amount: 0, noField: true }), false); assert.equal(matchesShipment(old, { territory: 'carthag', amount: 1 }), true); const either = parseShipmentClaim({ claim: { op: 'or', terms: [ { kind: 'noField' }, { territory: 'arrakeen', minimum: 3 }, ] } }); assert.equal(matchesShipment(either, { territory: 'carthag', amount: 0, noField: true }), true); assert.equal(matchesShipment(either, { territory: 'arrakeen', amount: 3 }), true); assert.equal(matchesShipment(either, null), false); }); void test('No-Field statements reject secret identifiers, invalid destinations and standalone sectors', () => { for (const bad of [ { kind: 'noField', token: 'secret' }, { kind: 'noField', value: 3 }, { kind: 'noField', sector: 11 }, { kind: 'noField', territory: 'not-a-territory' }, { kind: 'noField', territory: 'carthag', sector: 10 }, { kind: 'noField', territory: 'carthag', minimum: 1 }, ]) assert.throws(() => parseShipmentExpression(bad), ShipmentClaimError); assert.match(shipmentExpressionInputError({ kind: 'noField', sector: 11 })!, /No-Field shipment/); });