]>
Commit | Line | Data |
---|---|---|
3db7d198 BB |
1 | 'use strict'; |
2 | ||
b3b840f8 RBR |
3 | const Code = require('code'); // assertion library |
4 | const Lab = require('lab'); | |
5 | const Serpentity = require('..'); | |
3db7d198 | 6 | |
b3b840f8 RBR |
7 | const internals = { |
8 | system: class TestSystem extends Serpentity.System { | |
9 | added(engine) { | |
3db7d198 | 10 | |
b3b840f8 RBR |
11 | this.testNodes = engine.getNodes(internals.node); |
12 | this.addedCalled = true; | |
13 | this.addedEngine = engine; | |
3db7d198 BB |
14 | } |
15 | ||
b3b840f8 RBR |
16 | removed(engine) { |
17 | ||
3db7d198 | 18 | this.testNodes = null; |
b3b840f8 RBR |
19 | this.removedCalled = true; |
20 | this.removedEngine = engine; | |
3db7d198 BB |
21 | } |
22 | ||
b3b840f8 | 23 | update(dt) { |
3db7d198 | 24 | |
b3b840f8 RBR |
25 | this.updateCalled = Date.now(); |
26 | this.updateDt = dt; | |
3db7d198 | 27 | |
b3b840f8 RBR |
28 | for (const node of this.testNodes) { |
29 | node.test.called = true; | |
30 | node.entity.called = true; | |
31 | } | |
3db7d198 | 32 | |
b3b840f8 RBR |
33 | while (Date.now() === this.updateCalled) { /* pass some time */ } |
34 | } | |
35 | }, | |
36 | component: class TestComponent extends Serpentity.Component { | |
37 | constructor(config) { | |
3db7d198 | 38 | |
3db7d198 BB |
39 | super(config); |
40 | ||
b3b840f8 | 41 | this.called = false; |
3db7d198 | 42 | } |
b3b840f8 RBR |
43 | }, |
44 | node: class TestNode extends Serpentity.Node {}, | |
45 | delta: 10 | |
46 | }; | |
3db7d198 | 47 | |
b3b840f8 RBR |
48 | // adds a component to the node |
49 | internals.node.types = { | |
50 | test: internals.component | |
51 | }; | |
3db7d198 | 52 | |
b3b840f8 | 53 | const lab = exports.lab = Lab.script(); |
3db7d198 | 54 | |
b3b840f8 | 55 | lab.experiment('loading', () => { |
3db7d198 | 56 | |
b3b840f8 | 57 | lab.test('Serpentity should be exported', (done) => { |
3db7d198 | 58 | |
b3b840f8 RBR |
59 | Code.expect(typeof Serpentity).to.not.be.undefined(); |
60 | done(); | |
61 | }); | |
3db7d198 | 62 | |
b3b840f8 | 63 | lab.test('Serpentity should include the Entity class', (done) => { |
3db7d198 | 64 | |
b3b840f8 RBR |
65 | Code.expect(typeof Serpentity.Entity).to.not.be.undefined(); |
66 | done(); | |
67 | }); | |
3db7d198 | 68 | |
b3b840f8 | 69 | lab.test('Serpentity should include the Component class', (done) => { |
3db7d198 | 70 | |
b3b840f8 RBR |
71 | Code.expect(typeof Serpentity.Component).to.not.be.undefined(); |
72 | done(); | |
73 | }); | |
3db7d198 | 74 | |
b3b840f8 | 75 | lab.test('Serpentity should include the System class', (done) => { |
3db7d198 | 76 | |
b3b840f8 RBR |
77 | Code.expect(typeof Serpentity.System).to.not.be.undefined(); |
78 | done(); | |
79 | }); | |
3db7d198 | 80 | |
b3b840f8 | 81 | lab.test('Serpentity should include the Node class', (done) => { |
3db7d198 | 82 | |
b3b840f8 RBR |
83 | Code.expect(typeof Serpentity.Node).to.not.be.undefined(); |
84 | done(); | |
85 | }); | |
86 | ||
87 | lab.test('Serpentity should include the NodeCollection class', (done) => { | |
88 | ||
89 | Code.expect(typeof Serpentity.NodeCollection).to.not.be.undefined(); | |
90 | done(); | |
91 | }); | |
92 | }); | |
93 | ||
94 | lab.experiment('Engine Tests', () => { | |
95 | ||
96 | lab.beforeEach((done) => { | |
97 | ||
98 | this.engine = new Serpentity(); | |
99 | ||
100 | this.regularSystem = new internals.system(); | |
101 | this.highPrioritySystem = new internals.system(); | |
102 | this.lowPrioritySystem = new internals.system(); | |
103 | ||
104 | this.firstEntity = new Serpentity.Entity(); | |
105 | this.firstEntity.addComponent(new internals.component()); | |
106 | this.secondEntity = new Serpentity.Entity(); | |
107 | this.secondEntity.addComponent(new internals.component()); | |
108 | this.emptyEntity = new Serpentity.Entity(); | |
109 | ||
110 | // Add entity before the systems | |
111 | this.engine.addEntity(this.firstEntity); | |
112 | ||
113 | this.engine.addSystem(this.regularSystem, 100); | |
114 | this.engine.addSystem(this.highPrioritySystem, 0); | |
115 | this.engine.addSystem(this.lowPrioritySystem, 1000); | |
116 | ||
117 | // Add entity after the systems | |
118 | this.engine.addEntity(this.secondEntity); | |
119 | this.engine.addEntity(this.emptyEntity); | |
120 | ||
121 | done(); | |
122 | }); | |
123 | ||
124 | lab.test('Engine should call added callback on added systems', (done) => { | |
125 | ||
126 | // Ensure the added callback is being called | |
127 | Code.expect(this.regularSystem.addedCalled).to.be.true(); | |
128 | Code.expect(this.highPrioritySystem.addedCalled).to.be.true(); | |
129 | Code.expect(this.lowPrioritySystem.addedCalled).to.be.true(); | |
130 | ||
131 | done(); | |
132 | }); | |
133 | ||
134 | lab.test('Engine should send the engine instance in added callback', (done) => { | |
135 | ||
136 | // Ensure the added callback is sending the engine | |
137 | Code.expect(this.regularSystem.addedEngine instanceof Serpentity).to.be.true(); | |
138 | Code.expect(this.highPrioritySystem.addedEngine instanceof Serpentity).to.be.true(); | |
139 | Code.expect(this.lowPrioritySystem.addedEngine instanceof Serpentity).to.be.true(); | |
140 | ||
141 | done(); | |
142 | }); | |
143 | ||
144 | lab.test('Engine should not add duplicate systems', (done) => { | |
145 | ||
146 | const originalSystemsLength = this.engine.systems.length; | |
147 | const added = this.engine.addSystem(this.regularSystem, 0); | |
148 | const newSystemsLength = this.engine.systems.length; | |
149 | ||
150 | // Ensure we don't add the same system twice | |
151 | Code.expect(added).to.be.false(); | |
152 | Code.expect(originalSystemsLength).to.be.equal(newSystemsLength); | |
153 | ||
154 | done(); | |
155 | }); | |
156 | ||
157 | lab.test('Engine should call update callback on added systems', (done) => { | |
158 | ||
159 | this.engine.update(internals.delta); | |
160 | ||
161 | // Ensure update function called | |
162 | Code.expect(!!this.regularSystem.updateCalled).to.be.true(); | |
163 | Code.expect(!!this.highPrioritySystem.updateCalled).to.be.true(); | |
164 | Code.expect(!!this.lowPrioritySystem.updateCalled).to.be.true(); | |
165 | ||
166 | done(); | |
167 | }); | |
168 | ||
169 | lab.test('Engine should call update callback in the order of priorities', (done) => { | |
170 | ||
171 | this.engine.update(internals.delta); | |
172 | ||
173 | // Ensure order of priorities | |
174 | Code.expect(this.regularSystem.updateCalled).to.be.lessThan(this.lowPrioritySystem.updateCalled); | |
175 | Code.expect(this.regularSystem.updateCalled).to.be.greaterThan(this.highPrioritySystem.updateCalled); | |
176 | ||
177 | done(); | |
178 | }); | |
179 | ||
180 | lab.test('Engine should send the delta in the update callback', (done) => { | |
181 | ||
182 | this.engine.update(internals.delta); | |
183 | ||
184 | // Ensure delta is being sent | |
185 | Code.expect(this.regularSystem.updateDt).to.be.equal(internals.delta); | |
186 | Code.expect(this.highPrioritySystem.updateDt).to.be.equal(internals.delta); | |
187 | Code.expect(this.lowPrioritySystem.updateDt).to.be.equal(internals.delta); | |
188 | ||
189 | done(); | |
190 | }); | |
191 | ||
192 | lab.test('System remove callback', (done) => { | |
193 | ||
194 | const originalSystemLength = this.engine.systems.length; | |
195 | const originalRemoved = this.engine.removeSystem(this.lowPrioritySystem); | |
196 | const intermediateSystemLength = this.engine.systems.length; | |
197 | const finalRemoved = this.engine.removeSystem(this.lowPrioritySystem); | |
198 | const finalSystemLength = this.engine.systems.length; | |
199 | this.engine.update(internals.delta); | |
200 | ||
201 | // Check for return value | |
202 | Code.expect(originalRemoved).to.be.true(); | |
203 | Code.expect(finalRemoved).to.be.false(); | |
204 | ||
205 | // Confirm that only removed if found by checking length of systems | |
206 | // array | |
207 | Code.expect(originalSystemLength).to.be.above(intermediateSystemLength); | |
208 | Code.expect(finalSystemLength).to.be.equal(intermediateSystemLength); | |
209 | ||
210 | // Ensure callback is sent | |
211 | Code.expect(!!this.regularSystem.removedCalled).to.be.false(); | |
212 | Code.expect(!!this.highPrioritySystem.removedCalled).to.be.false(); | |
213 | Code.expect(!!this.lowPrioritySystem.removedCalled).to.be.true(); | |
214 | ||
215 | // Ensure update is no longer sent | |
216 | Code.expect(!!this.regularSystem.updateCalled).to.be.true(); | |
217 | Code.expect(!!this.highPrioritySystem.updateCalled).to.be.true(); | |
218 | Code.expect(!!this.lowPrioritySystem.updateCalled).to.be.false(); | |
219 | ||
220 | done(); | |
221 | }); | |
222 | ||
223 | lab.test('Entity node selection', (done) => { | |
224 | ||
225 | this.engine.update(internals.delta); | |
226 | ||
227 | // Ensure component is called for each entity | |
228 | Code.expect(!!this.firstEntity._components[0].called).to.be.true(); | |
229 | Code.expect(!!this.secondEntity._components[0].called).to.be.true(); | |
230 | ||
231 | // Ensure entity not in node collection not called | |
232 | Code.expect(!!this.firstEntity.called).to.be.true(); | |
233 | Code.expect(!!this.secondEntity.called).to.be.true(); | |
234 | Code.expect(!!this.emptyEntity.called).to.be.false(); | |
235 | ||
236 | done(); | |
237 | }); | |
238 | ||
239 | lab.test('Entity node removal', (done) => { | |
240 | ||
241 | this.engine.removeEntity(this.secondEntity); | |
242 | this.engine.update(internals.delta); | |
243 | ||
244 | Code.expect(!!this.firstEntity._components[0].called).to.be.true(); | |
245 | Code.expect(!!this.secondEntity._components[0].called).to.be.false(); | |
246 | ||
247 | Code.expect(!!this.firstEntity.called).to.be.true(); | |
248 | Code.expect(!!this.secondEntity.called).to.be.false(); | |
249 | Code.expect(!!this.emptyEntity.called).to.be.false(); | |
250 | ||
251 | done(); | |
252 | }); | |
253 | ||
254 | lab.test('Entity should not add duplicate components', (done) => { | |
255 | const originalComponentsLength = this.secondEntity._components.length; | |
256 | const result = this.secondEntity.addComponent(new internals.component()); | |
257 | const newComponentsLength = this.secondEntity._components.length; | |
258 | ||
259 | Code.expect(result).to.be.false(); | |
260 | Code.expect(originalComponentsLength).to.be.equal(newComponentsLength); | |
261 | ||
262 | done(); | |
263 | }); | |
264 | ||
265 | lab.test('Entity should allow access to components by class', (done) => { | |
266 | const firstComponent = this.firstEntity.getComponent(internals.component); | |
267 | const emptyComponent = this.emptyEntity.getComponent(internals.component); | |
268 | ||
269 | Code.expect(firstComponent instanceof internals.component).to.be.true(); | |
270 | Code.expect(emptyComponent).to.be.equal(undefined); | |
271 | ||
272 | done(); | |
273 | }); | |
274 | ||
275 | lab.test('Engine should not add duplicate entities', (done) => { | |
276 | const originalEntitiesLength = this.engine.entities.length; | |
277 | const added = this.engine.addEntity(this.firstEntity); | |
278 | const finalEntitiesLength = this.engine.entities.length; | |
279 | ||
280 | Code.expect(added).to.be.false(); | |
281 | ||
282 | Code.expect(originalEntitiesLength).to.be.equal(finalEntitiesLength); | |
283 | done(); | |
284 | }); | |
285 | ||
286 | lab.test('Engine should remove entities', (done) => { | |
287 | ||
288 | const originalEntityLength = this.engine.entities.length; | |
289 | const originalRemoved = this.engine.removeEntity(this.firstEntity); | |
290 | const intermediateEntityLength = this.engine.entities.length; | |
291 | const finalRemoved = this.engine.removeEntity(this.firstEntity); | |
292 | const finalEntityLength = this.engine.entities.length; | |
293 | this.engine.update(internals.delta); | |
294 | ||
295 | // Check for return value | |
296 | Code.expect(originalRemoved).to.be.true(); | |
297 | Code.expect(finalRemoved).to.be.false(); | |
298 | ||
299 | // Confirm that only removed if found by checking length of systems | |
300 | // array | |
301 | Code.expect(originalEntityLength).to.be.above(intermediateEntityLength); | |
302 | Code.expect(finalEntityLength).to.be.equal(intermediateEntityLength); | |
303 | ||
304 | // Ensure callback is sent | |
305 | Code.expect(!!this.firstEntity.called).to.be.false(); | |
306 | Code.expect(!!this.secondEntity.called).to.be.true(); | |
3db7d198 | 307 | |
b3b840f8 | 308 | done(); |
3db7d198 | 309 | }); |
b3b840f8 | 310 | }); |