diff options
Diffstat (limited to 'prototypes/live-rules/adapter.test.mjs')
| -rw-r--r-- | prototypes/live-rules/adapter.test.mjs | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/prototypes/live-rules/adapter.test.mjs b/prototypes/live-rules/adapter.test.mjs new file mode 100644 index 0000000..95af13b --- /dev/null +++ b/prototypes/live-rules/adapter.test.mjs @@ -0,0 +1,96 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { loadCore, snapshot, storage, parseCommand, execute } from './runtime.mjs'; + +test('the actual Wasm preserves airborne state through a rule change, then permits the second jump', async () => { + const c = await loadCore(); + execute(c, parseCommand('jump')); + execute(c, parseCommand('step 8')); + execute(c, parseCommand('jump')); + const before = snapshot(c); + assert.equal(before.state.lastReason, 3); + const after = execute(c, parseCommand('rules double 12 on')); + for (const field of ['tick', 'y', 'vy', 'distance', 'obstacleX', 'jumpsUsed', 'hits', 'passed']) { + assert.equal(after.state[field], before.state[field], field); + } + assert.deepEqual(after.decision, before.decision); + assert.equal(after.state.revision, 1); + execute(c, parseCommand('jump')); + assert.equal(c.get(10), 1); + assert.equal(c.get(2), 1200); + assert.equal(c.get(7), 2); + assert.equal(c.input(2), 0); + assert.equal(c.get(10), 4); +}); + +test('bad CLI edits and malformed numeric input cannot silently coerce into a different rule', async () => { + const c = await loadCore(); + const before = snapshot(c); + for (const command of ['rules double 8.5 on', 'rules double 4294967306 on', 'rules ground 5 on', + 'rules other 10 on', 'rules double 10 maybe', 'rules double 10 on extra', 'step 0', 'step 601', 'jump extra']) { + assert.throws(() => execute(c, parseCommand(command)), undefined, command); + assert.deepEqual(snapshot(c), before); + } + assert.equal(c.apply_rules(2, 10, 1), 1); + assert.deepEqual(snapshot(c), before); +}); + +test('keyboard, pointer and terminal requests give the same simulation result', async () => { + const states = []; + for (const source of [0, 1, 2]) { + const c = await loadCore(); + c.apply_rules(1, 12, 1); + c.input(source); + for (let i = 0; i < 8; i++) c.step(); + c.input(source); + const { lastSource, ...state } = snapshot(c).state; + assert.equal(lastSource, source); + states.push(state); + } + assert.deepEqual(states[0], states[1]); + assert.deepEqual(states[1], states[2]); +}); + +test('paused input has an inspectable decision; advance cannot move paused state', async () => { + const c = await loadCore(); + assert.equal(snapshot(c).decision, null); + assert.equal(c.input(0), 1); + assert.equal(c.get(1), 0); + assert.equal(c.get(17), 0); + const before = snapshot(c); + assert.equal(c.advance(60), 0); + assert.deepEqual(snapshot(c), before); + c.step(); + assert.equal(c.get(1), 945); + assert.equal(c.get(0), 1); +}); + +test('bounded history and fixed linear memory survive repeated play and edits', async () => { + const c = await loadCore(); + const before = storage(c); + c.set_running(1); + for (let i = 0; i < 5000; i++) { + c.apply_rules(i % 2, 6 + i % 11, 1); + c.input(i % 3); + c.advance(8); + } + assert.equal(c.history_count(), 16); + assert.equal(c.history_get(16, 0), -1); + assert.equal(c.get(0), 40000); + assert.deepEqual(storage(c), before); + assert.equal(before.wasmLinearMemoryBytes, 65536); + assert.throws(() => c.memory.grow(1), RangeError); + const b = before.layoutBytes; + assert.equal(b.logicalTotal, b.engine + b.graph); + assert.ok(b.engine >= b.rules + b.state + b.decision + b.history); +}); + +test('replaying the same CLI operations produces identical snapshots and journal', async () => { + const trace = ['jump', 'step 8', 'jump', 'rules double 10 on', 'jump', 'step 60', 'rules ground 8 off', 'jump']; + const snapshots = []; + for (let i = 0; i < 2; i++) { + const c = await loadCore(); + snapshots.push(trace.map((line) => execute(c, parseCommand(line)))); + } + assert.deepEqual(snapshots[0], snapshots[1]); +}); |
