-
-
Notifications
You must be signed in to change notification settings - Fork 230
Expand file tree
/
Copy pathengineStep.test.mjs
More file actions
118 lines (104 loc) · 4.07 KB
/
Copy pathengineStep.test.mjs
File metadata and controls
118 lines (104 loc) · 4.07 KB
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { test } from 'node:test';
import assert from 'node:assert/strict';
import * as LJS from '../dist/littlejs.esm.js';
const near = (a, b, eps=1e-9) => Math.abs(a - b) <= eps;
// Read through the module namespace rather than named imports so the live
// bindings for engine globals (frame, time) are observed after the engine
// mutates them.
//
// One engineInit for the whole file: `frame` and `time` are module globals
// and monotonic, and ES module caching gives every test in this file the
// same bundle instance. `node --test` runs each test file in its own
// process, so this does not leak into other test files.
//
// Everything at module scope below runs before any test body, so pre-init
// state has to be captured here rather than inside a test.
// engineManualStep is still false here, so this exercises the
// "manual step not enabled" assert.
let preInitThrew = false;
try { LJS.engineStep(); } catch (e) { preInitThrew = /Assert failed/.test(e.message); }
let updateCount = 0, updatePostCount = 0;
LJS.setEngineManualStep(true);
await LJS.engineInit(
()=>{}, // gameInit
()=>{ ++updateCount; }, // gameUpdate
()=>{ ++updatePostCount; }, // gameUpdatePost
()=>{}, // gameRender
()=>{}); // gameRenderPost
test('engineStep throws when manual step is not enabled', () =>
{
assert.equal(preInitThrew, true);
});
test('engineInit does not advance the engine in manual step mode', () =>
{
// startEngine() normally burns a frame before the caller gets control.
// Skipping it is what makes post-gameInit state observable.
assert.equal(LJS.frame, 0);
assert.equal(updateCount, 0);
});
test('one engineStep advances exactly one frame', () =>
{
const f0 = LJS.frame, u0 = updateCount;
LJS.engineStep();
assert.equal(LJS.frame, f0 + 1);
assert.equal(updateCount, u0 + 1);
});
test('engineStep(n) advances exactly n frames and n/frameRate seconds', () =>
{
const f0 = LJS.frame, t0 = LJS.time, u0 = updateCount;
LJS.engineStep(10);
assert.equal(LJS.frame, f0 + 10);
assert.equal(updateCount, u0 + 10);
assert(near(LJS.time - t0, 10 / LJS.frameRate));
});
test('engineStep stays exact over many frames', () =>
{
// Guards the delta-smoothing branch: float residue in the frame time
// buffer must not accumulate into a dropped or doubled tick.
const f0 = LJS.frame;
for (let i = 0; i < 600; ++i)
LJS.engineStep();
assert.equal(LJS.frame, f0 + 600);
});
test('engineStep(0) is a no-op', () =>
{
const f0 = LJS.frame, u0 = updateCount;
LJS.engineStep(0);
assert.equal(LJS.frame, f0);
assert.equal(updateCount, u0);
});
test('a Timer elapses on schedule under engineStep', () =>
{
const t = new LJS.Timer(1); // 1 second == frameRate frames
LJS.engineStep(30);
assert.equal(t.elapsed(), false); // half a second in
LJS.engineStep(60);
assert.equal(t.elapsed(), true); // well past one second
});
test('engineStep respects paused', () =>
{
LJS.setPaused(true);
const f0 = LJS.frame, t0 = LJS.time;
const u0 = updateCount, p0 = updatePostCount;
LJS.engineStep(5);
assert.equal(LJS.frame, f0); // no fixed updates
assert.equal(LJS.time, t0); // time frozen
assert.equal(updateCount, u0); // gameUpdate not called
assert.equal(updatePostCount, p0 + 5); // gameUpdatePost still runs
LJS.setPaused(false);
});
test('engineStep resumes cleanly after unpausing', () =>
{
const f0 = LJS.frame;
LJS.engineStep(3);
assert.equal(LJS.frame, f0 + 3);
});
test('engineStep rejects a non-whole or negative frame count', () =>
{
assert.throws(()=> LJS.engineStep(-1), /Assert failed/);
assert.throws(()=> LJS.engineStep(1.5), /Assert failed/);
assert.throws(()=> LJS.engineStep('3'), /Assert failed/);
assert.throws(()=> LJS.engineStep(NaN), /Assert failed/);
assert.throws(()=> LJS.engineStep(Infinity), /Assert failed/);
assert.throws(()=> LJS.engineStep(36001), /Assert failed/); // engineStepMaxFrames is 36000
});