Support consensual lobby faction swaps
This commit is contained in:
1 parent
4dc2df2513
commit
c6b4a165bd
15 files changed
+680
-14
No files matched your search
@@ -0,0 +1,67 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
answerFactionSwap, cancelFactionSwap, createFactionSwap, FactionSwapError,
|
||||
validateFactionSwap, type FactionSwapSeat,
|
||||
} from '../game/faction-swap';
|
||||
|
||||
const roster: FactionSwapSeat[] = [
|
||||
{ id: 'one', faction: 'atreides' },
|
||||
{ id: 'two', faction: 'harkonnen' },
|
||||
{ id: 'three', faction: 'guild' },
|
||||
];
|
||||
|
||||
void test('an offer snapshots the public identities and current faction assignments', () => {
|
||||
const players = structuredClone(roster);
|
||||
const offer = createFactionSwap(players, 'one', 'two', 'swap:1');
|
||||
assert.deepEqual(offer, {
|
||||
event: 'swap:1', from: 'one', to: 'two', fromFaction: 'atreides', toFaction: 'harkonnen',
|
||||
});
|
||||
assert.deepEqual(players, roster);
|
||||
validateFactionSwap(JSON.parse(JSON.stringify(offer)), players);
|
||||
});
|
||||
|
||||
void test('only the recipient may accept or reject and acceptance swaps precisely two factions', () => {
|
||||
const players = structuredClone(roster);
|
||||
const offer = createFactionSwap(players, 'one', 'two', 'swap:1');
|
||||
const original = structuredClone(offer);
|
||||
assert.deepEqual(answerFactionSwap(players, offer, 'two', true), {
|
||||
accepted: true, assignments: [
|
||||
{ player: 'one', faction: 'harkonnen' },
|
||||
{ player: 'two', faction: 'atreides' },
|
||||
],
|
||||
});
|
||||
assert.deepEqual(answerFactionSwap(players, offer, 'two', false), { accepted: false, assignments: [] });
|
||||
assert.throws(() => answerFactionSwap(players, offer, 'one', true), FactionSwapError);
|
||||
assert.throws(() => answerFactionSwap(players, offer, 'three', false), FactionSwapError);
|
||||
assert.throws(() => answerFactionSwap(players, offer, 'two', 'yes' as unknown as boolean), FactionSwapError);
|
||||
assert.deepEqual(players, roster);
|
||||
assert.deepEqual(offer, original);
|
||||
});
|
||||
|
||||
void test('only the proposer can cancel an offer', () => {
|
||||
const offer = createFactionSwap(roster, 'one', 'two', 'swap:1');
|
||||
assert.doesNotThrow(() => cancelFactionSwap(roster, offer, 'one'));
|
||||
assert.throws(() => cancelFactionSwap(roster, offer, 'two'), FactionSwapError);
|
||||
assert.throws(() => cancelFactionSwap(roster, offer, 'three'), FactionSwapError);
|
||||
});
|
||||
|
||||
void test('invalid rosters and participants cannot create an offer', () => {
|
||||
assert.throws(() => createFactionSwap(roster, 'one', 'one', 'swap:1'), FactionSwapError);
|
||||
assert.throws(() => createFactionSwap(roster, 'one', 'missing', 'swap:1'), FactionSwapError);
|
||||
assert.throws(() => createFactionSwap(roster, 'one', 'two', ' '), FactionSwapError);
|
||||
assert.throws(() => createFactionSwap([roster[0], roster[0]], 'one', 'two', 'swap:1'), FactionSwapError);
|
||||
assert.throws(() => createFactionSwap([roster[0], { ...roster[1], faction: 'atreides' }], 'one', 'two', 'swap:1'), FactionSwapError);
|
||||
assert.throws(() => createFactionSwap([roster[0]], 'one', 'two', 'swap:1'), FactionSwapError);
|
||||
});
|
||||
|
||||
void test('saved offers cannot authorize stale or malformed faction assignments', () => {
|
||||
const offer = createFactionSwap(roster, 'one', 'two', 'swap:1');
|
||||
const changed = [roster[0], { ...roster[1], faction: 'fremen' as const }, roster[2]];
|
||||
assert.throws(() => answerFactionSwap(changed, offer, 'two', true), FactionSwapError);
|
||||
assert.throws(() => validateFactionSwap(offer, [roster[0], roster[2]]), FactionSwapError);
|
||||
assert.throws(() => validateFactionSwap({ ...offer, event: '' }, roster), FactionSwapError);
|
||||
assert.throws(() => validateFactionSwap({ ...offer, to: 'one' }, roster), FactionSwapError);
|
||||
assert.throws(() => validateFactionSwap({ ...offer, toFaction: 'invalid' }, roster), FactionSwapError);
|
||||
assert.throws(() => validateFactionSwap({ ...offer, secret: 'extra' }, roster), FactionSwapError);
|
||||
});
|
||||
Reference in new issue
Block a user