1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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]);
});
|