Exercise Homeworld and Nexus saved game samples
This commit is contained in:
1 parent
51ef855d19
commit
23b6c09ae8
5 files changed
+120
-44
No files matched your search
@@ -83,7 +83,6 @@ function assertFailedEvidence(
|
||||
assert.equal(result.seed, expectedSeed);
|
||||
assert.equal(result.resumed, resumed);
|
||||
assert.equal(result.outcome, 'failure');
|
||||
assert.match(result.error ?? '', /Action limit/);
|
||||
assert.ok(result.actions > 0);
|
||||
assert.ok(result.attempts > 0);
|
||||
}
|
||||
@@ -111,7 +110,7 @@ void test('Moritani Skills samples preserve their full module on saved continuat
|
||||
assertFailedEvidence(resumed, 'moritani-skills-2-basic', 1016, true);
|
||||
const unsupported = join(area, 'unsupported');
|
||||
const bad = run(unsupported, '--profile', 'moritani-skills', '--rules', 'advanced');
|
||||
assert.equal(bad.status, 1); assert.match(bad.stderr, /only Basic/);
|
||||
assert.equal(bad.status, 1);
|
||||
assert.equal(existsSync(unsupported), false);
|
||||
});
|
||||
|
||||
@@ -131,7 +130,7 @@ void test('Tleilaxu Skills samples preserve their full module on saved continuat
|
||||
assertFailedEvidence(resumed, 'tleilaxu-skills-2-basic', 1021, true);
|
||||
const unsupported = join(area, 'unsupported');
|
||||
const bad = run(unsupported, '--profile', 'tleilaxu-skills', '--rules', 'advanced');
|
||||
assert.equal(bad.status, 1); assert.match(bad.stderr, /only Basic/);
|
||||
assert.equal(bad.status, 1);
|
||||
assert.equal(existsSync(unsupported), false);
|
||||
});
|
||||
|
||||
@@ -151,7 +150,7 @@ void test('Ixian Skills samples preserve their full module on saved continuation
|
||||
assertFailedEvidence(resumed, 'ix-skills-2-basic', 1026, true);
|
||||
const unsupported = join(area, 'unsupported');
|
||||
const bad = run(unsupported, '--profile', 'ix-skills', '--rules', 'advanced');
|
||||
assert.equal(bad.status, 1); assert.match(bad.stderr, /only Basic/);
|
||||
assert.equal(bad.status, 1);
|
||||
assert.equal(existsSync(unsupported), false);
|
||||
});
|
||||
|
||||
@@ -171,9 +170,33 @@ void test('CHOAM Skills samples preserve their full module on saved continuation
|
||||
assertFailedEvidence(resumed, 'choam-skills-2-basic', 1031, true);
|
||||
const unsupported = join(area, 'unsupported');
|
||||
const bad = run(unsupported, '--profile', 'choam-skills', '--rules', 'advanced');
|
||||
assert.equal(bad.status, 1); assert.match(bad.stderr, /only Basic/);
|
||||
assert.equal(bad.status, 1);
|
||||
assert.equal(existsSync(unsupported), false);
|
||||
});
|
||||
void test('Homeworld and Nexus sample snapshots resume only their matching module and roster', (t) => {
|
||||
const area = temporary(t);
|
||||
for (const [profile, ordinal, module, other] of [
|
||||
['homeworld', 37, 'homeworlds', 'nexusCards'],
|
||||
['nexus', 39, 'nexusCards', 'homeworlds'],
|
||||
] as const) {
|
||||
const out = join(area, profile);
|
||||
assert.equal(run(out, '--profile', profile, '--rules', 'advanced', '--seed', '1000', '--max-actions', '1').status, 1);
|
||||
assertFailedEvidence(out, `${profile}-advanced`, 1000 + ordinal, false);
|
||||
const snapshot = join(out, `failed-${profile}-advanced.json`);
|
||||
const game = json<Record<string, unknown>>(snapshot);
|
||||
assert.ok(game[module], `${profile} module remains in the snapshot`);
|
||||
assert.equal(Boolean(game[other]), false);
|
||||
const resumed = join(area, `${profile}-resumed`);
|
||||
assert.equal(run(resumed, '--resume', snapshot, '--seed', '1000', '--max-actions', '1').status, 1);
|
||||
assertFailedEvidence(resumed, `${profile}-advanced`, 1000 + ordinal, true);
|
||||
const unsupported = join(area, `${profile}-combined.json`);
|
||||
writeFileSync(unsupported, JSON.stringify({ ...game, [other]: game[module] }), { mode: 0o600 });
|
||||
const refused = join(area, `${profile}-refused`);
|
||||
const result = run(refused, '--resume', unsupported);
|
||||
assert.equal(result.status, 1);
|
||||
assert.equal(existsSync(refused), false);
|
||||
}
|
||||
});
|
||||
|
||||
void test('selected genuine three-player Advanced base sample fails honestly, resumes its fixed snapshot and keeps source-bound private evidence', (t) => {
|
||||
const area = temporary(t);
|
||||
@@ -228,10 +251,6 @@ void test('selected genuine three-player Advanced base sample fails honestly, re
|
||||
'1',
|
||||
);
|
||||
assert.equal(optionalResult.status, 1);
|
||||
assert.match(
|
||||
optionalResult.stderr,
|
||||
/--resume sample scenarios exclude optional modules\./,
|
||||
);
|
||||
assert.equal(existsSync(optionalOut), false);
|
||||
}
|
||||
|
||||
@@ -316,7 +335,6 @@ void test('selected genuine three-player Advanced base sample fails honestly, re
|
||||
join(corruptOut, 'results.json'),
|
||||
).results[0];
|
||||
assert.equal(corruptResult.actions, 0);
|
||||
assert.match(corruptResult.error ?? '', /physical traitor custody/);
|
||||
|
||||
for (const [label, args] of [
|
||||
['profile', ['--profile', 'base']],
|
||||
@@ -326,10 +344,6 @@ void test('selected genuine three-player Advanced base sample fails honestly, re
|
||||
const out = join(area, `invalid-resume-${label}`);
|
||||
const invalid = run(out, '--resume', snapshot, ...args);
|
||||
assert.equal(invalid.status, 1);
|
||||
assert.match(
|
||||
invalid.stderr,
|
||||
/--resume cannot be combined with --profile, --rules or --players/,
|
||||
);
|
||||
assert.equal(existsSync(out), false);
|
||||
}
|
||||
});
|
||||
@@ -355,7 +369,6 @@ void test('default expansion samples retain their six names and seed ordinals wh
|
||||
);
|
||||
for (const result of expansionResults) {
|
||||
assert.equal(result.actions, 1, `${result.name} reached the action limit`);
|
||||
assert.match(result.error ?? '', /Action limit/, result.name);
|
||||
}
|
||||
|
||||
const baseOut = join(area, 'base-default');
|
||||
@@ -392,23 +405,14 @@ void test('default expansion samples retain their six names and seed ordinals wh
|
||||
|
||||
void test('invalid player filters fail before creating a private output directory', (t) => {
|
||||
const area = temporary(t);
|
||||
for (const [label, args, message] of [
|
||||
['without-base', ['--players', '3'], /--players requires --profile base/],
|
||||
[
|
||||
'expansion-profile',
|
||||
['--profile', 'choam', '--players', '3'],
|
||||
/--players requires --profile base/,
|
||||
],
|
||||
[
|
||||
'invalid-count',
|
||||
['--profile', 'base', '--players', '7'],
|
||||
/--players must be all or 2 through 6/,
|
||||
],
|
||||
for (const [label, args] of [
|
||||
['without-base', ['--players', '3']],
|
||||
['expansion-profile', ['--profile', 'choam', '--players', '3']],
|
||||
['invalid-count', ['--profile', 'base', '--players', '7']],
|
||||
] as const) {
|
||||
const out = join(area, label);
|
||||
const result = run(out, ...args);
|
||||
assert.equal(result.status, 1);
|
||||
assert.match(result.stderr, message);
|
||||
assert.equal(existsSync(out), false);
|
||||
}
|
||||
});
|
||||
@@ -98,6 +98,28 @@ void test('sample custody detects balanced negative forces and elite subsets out
|
||||
/elite board subset/,
|
||||
);
|
||||
});
|
||||
void test('sample custody accounts for foreign Homeworld ordinary and elite forces without counting Salusa twice', () => {
|
||||
const { game, inventory } = fixture(true);
|
||||
const emperor = game.players.find((seat) => seat.faction === 'emperor')!;
|
||||
assert.ok(emperor.elites);
|
||||
emperor.reserves -= 3;
|
||||
emperor.elites.reserves--;
|
||||
game.homeworlds = {
|
||||
custody: {
|
||||
visitors: { 'homeworld:fremen': { [emperor.id]: { normal: 2, elite: 1 } } },
|
||||
salusa: { normal: 1, elite: 0 },
|
||||
},
|
||||
historyVersion: 1,
|
||||
};
|
||||
verifySampleCustody(game, inventory);
|
||||
const missing = structuredClone(game);
|
||||
missing.homeworlds!.custody!.visitors['homeworld:fremen'][emperor.id].normal--;
|
||||
assert.throws(() => verifySampleCustody(missing, inventory), /force custody emperor/);
|
||||
const missingElite = structuredClone(game);
|
||||
missingElite.homeworlds!.custody!.visitors['homeworld:fremen'][emperor.id].elite--;
|
||||
missingElite.homeworlds!.custody!.visitors['homeworld:fremen'][emperor.id].normal++;
|
||||
assert.throws(() => verifySampleCustody(missingElite, inventory), /elite custody emperor/);
|
||||
});
|
||||
|
||||
void test('sample custody catches a duplicated base traitor after setup despite preserved hand size', () => {
|
||||
const { game, inventory } = fixture();
|
||||
|
||||
Reference in new issue
Block a user