scratch-vm/test/integration/clone-cleanup.js
Christopher Willis-Ford 6320fd72c3 Add test for clone cleanup
This new test verifies that clones and their associated threads are
cleaned up properly by the `delete this clone` block. The clones run two
stacks each: one which waits and then deletes the clone, and another
which includes a `forever` loop: this is to verify that the thread
running the `forever` loop is ended when the clone itself is deleted.
The project does this with two batches of clones to ensure there are no
problems with reusing array indices previously occupied by now-removed
threads or clones.
2017-06-08 11:16:29 -07:00

96 lines
2.9 KiB
JavaScript

const path = require('path');
const test = require('tap').test;
const attachTestStorage = require('../fixtures/attach-test-storage');
const extract = require('../fixtures/extract');
const VirtualMachine = require('../../src/index');
const projectUri = path.resolve(__dirname, '../fixtures/clone-cleanup.sb2');
const project = extract(projectUri);
test('clone-cleanup', t => {
const vm = new VirtualMachine();
attachTestStorage(vm);
/**
* Track which step of the project is currently under test.
* @type {number}
*/
let testStep = -1;
/**
* We test using setInterval; track the interval ID here so we can cancel it.
* @type {object}
*/
let testInterval = null;
const verifyCounts = (expectedClones, extraThreads) => {
// stage plus one sprite, plus clones
t.strictEqual(vm.runtime.targets.length, 2 + expectedClones,
`target count at step ${testStep}`);
// the stage should never have any clones
t.strictEqual(vm.runtime.targets[0].sprite.clones.length, 1,
`stage clone count at step ${testStep}`);
// check sprite clone count (+1 for original)
t.strictEqual(vm.runtime.targets[1].sprite.clones.length, 1 + expectedClones,
`sprite clone count at step ${testStep}`);
// thread count isn't directly tied to clone count since threads can end
t.strictEqual(vm.runtime.threads.length, extraThreads + (2 * expectedClones),
`thread count at step ${testStep}`);
};
const testNextStep = () => {
++testStep;
switch (testStep) {
case 0:
// Project has started, main thread running, no clones yet
verifyCounts(0, 1);
break;
case 1:
// 10 clones have been created, main thread still running
verifyCounts(10, 1);
break;
case 2:
// The first batch of clones has deleted themselves; main thread still running
verifyCounts(0, 1);
break;
case 3:
// The second batch of clones has been created and the main thread has ended
verifyCounts(10, 0);
break;
case 4:
// The second batch of clones has deleted themselves; everything is finished
verifyCounts(0, 0);
clearInterval(testInterval);
t.end();
process.nextTick(process.exit);
break;
}
};
// Start VM, load project, and run
t.doesNotThrow(() => {
vm.start();
vm.clear();
vm.setCompatibilityMode(false);
vm.setTurboMode(false);
vm.loadProject(project).then(() => {
// Verify initial state: no clones, nothing running ("step -1")
verifyCounts(0, 0);
vm.greenFlag();
// Every second, advance the testing step
testInterval = setInterval(testNextStep, 1000);
});
});
});