scratch-vm/test/integration/monitor-threads-run-every-frame.js
Michael "Z" Goddard 2ffa8eb333
update runtime thread tests
Threads are now removed after every "inner" step. Any thread that
reaches its DONE conditions is immediately removed instead of requiring
an extra step to remove it. As such tests that check the number of
threads have been updated to consider this.
2018-10-31 17:56:12 -04:00

129 lines
4.5 KiB
JavaScript

const path = require('path');
const test = require('tap').test;
const makeTestStorage = require('../fixtures/make-test-storage');
const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer;
const VirtualMachine = require('../../src/index');
const Thread = require('../../src/engine/thread');
const Runtime = require('../../src/engine/runtime');
const projectUri = path.resolve(__dirname, '../fixtures/default.sb2');
const project = readFileToBuffer(projectUri);
const checkMonitorThreadPresent = (t, threads) => {
t.equal(threads.length, 1);
const monitorThread = threads[0];
t.equal(monitorThread.stackClick, false);
t.equal(monitorThread.updateMonitor, true);
t.equal(monitorThread.topBlock.toString(), 'sensing_timer');
};
/**
* Creates a monitor and then checks if it gets run every frame.
*/
/* TODO: when loadProject loads monitors, we can create a project with a monitor and will
* not have to do the create monitor step manually.
*/
test('monitor thread runs every frame', t => {
const vm = new VirtualMachine();
vm.attachStorage(makeTestStorage());
// Start VM, load project, and run
t.doesNotThrow(() => {
// Note: don't run vm.start(), we handle calling _step() manually in this test
vm.runtime.currentStepTime = Runtime.THREAD_STEP_INTERVAL;
// Manually populate the monitor block and set its isMonitored to true.
vm.runtime.monitorBlocks.createBlock({
id: 'sensing_timer',
opcode: 'sensing_timer',
inputs: {},
fields: {},
next: null,
topLevel: true,
parent: null,
shadow: false,
isMonitored: true,
x: '0',
y: '0'
});
vm.clear();
vm.setCompatibilityMode(false);
vm.setTurboMode(false);
vm.loadProject(project).then(() => {
t.equal(vm.runtime.threads.length, 0);
vm.runtime._step();
let doneThreads = vm.runtime._lastStepDoneThreads;
t.equal(vm.runtime.threads.length, 0);
t.equal(doneThreads.length, 1);
checkMonitorThreadPresent(t, doneThreads);
t.assert(doneThreads[0].status === Thread.STATUS_DONE);
// Check that both are added again when another step is taken
vm.runtime._step();
doneThreads = vm.runtime._lastStepDoneThreads;
t.equal(vm.runtime.threads.length, 0);
t.equal(doneThreads.length, 1);
checkMonitorThreadPresent(t, doneThreads);
t.assert(doneThreads[0].status === Thread.STATUS_DONE);
t.end();
});
});
});
/**
* If the monitor doesn't finish evaluating within one frame, it shouldn't be added again
* on the next frame. (We skip execution by setting the step time to 0)
*/
test('monitor thread not added twice', t => {
const vm = new VirtualMachine();
vm.attachStorage(makeTestStorage());
// Start VM, load project, and run
t.doesNotThrow(() => {
// Note: don't run vm.start(), we handle calling _step() manually in this test
vm.runtime.currentStepTime = 0;
// Manually populate the monitor block and set its isMonitored to true.
vm.runtime.monitorBlocks.createBlock({
id: 'sensing_timer',
opcode: 'sensing_timer',
inputs: {},
fields: {},
next: null,
topLevel: true,
parent: null,
shadow: false,
isMonitored: true,
x: '0',
y: '0'
});
vm.clear();
vm.setCompatibilityMode(false);
vm.setTurboMode(false);
vm.loadProject(project).then(() => {
t.equal(vm.runtime.threads.length, 0);
vm.runtime._step();
let doneThreads = vm.runtime._lastStepDoneThreads;
t.equal(vm.runtime.threads.length, 1);
t.equal(doneThreads.length, 0);
checkMonitorThreadPresent(t, vm.runtime.threads);
t.assert(vm.runtime.threads[0].status === Thread.STATUS_RUNNING);
const prevThread = vm.runtime.threads[0];
// Check that both are added again when another step is taken
vm.runtime._step();
doneThreads = vm.runtime._lastStepDoneThreads;
t.equal(vm.runtime.threads.length, 1);
t.equal(doneThreads.length, 0);
checkMonitorThreadPresent(t, vm.runtime.threads);
t.equal(vm.runtime.threads[0], prevThread);
t.end();
});
});
});