scratch-vm/test/unit/engine_thread.js

319 lines
8.6 KiB
JavaScript
Raw Normal View History

const test = require('tap').test;
const Thread = require('../../src/engine/thread');
const RenderedTarget = require('../../src/sprites/rendered-target');
const Sprite = require('../../src/sprites/sprite');
const Runtime = require('../../src/engine/runtime');
2016-04-18 17:20:30 -04:00
test('spec', t => {
2016-04-18 17:20:30 -04:00
t.type(Thread, 'function');
const th = new Thread('arbitraryString');
t.type(th, 'object');
t.ok(th instanceof Thread);
t.type(th.pushStack, 'function');
t.type(th.reuseStackForNextBlock, 'function');
t.type(th.popStack, 'function');
t.type(th.stopThisScript, 'function');
t.type(th.peekStack, 'function');
t.type(th.peekStackFrame, 'function');
t.type(th.peekParentStackFrame, 'function');
t.type(th.pushReportedValue, 'function');
t.type(th.initParams, 'function');
t.type(th.pushParam, 'function');
t.type(th.peekStack, 'function');
t.type(th.getParam, 'function');
t.type(th.atStackTop, 'function');
t.type(th.goToNextBlock, 'function');
t.type(th.isRecursiveCall, 'function');
t.end();
});
test('pushStack', t => {
const th = new Thread('arbitraryString');
th.pushStack('arbitraryString');
t.end();
});
test('popStack', t => {
const th = new Thread('arbitraryString');
th.pushStack('arbitraryString');
t.strictEquals(th.popStack(), 'arbitraryString');
t.strictEquals(th.popStack(), null);
t.end();
});
test('atStackTop', t => {
const th = new Thread('arbitraryString');
th.pushStack('arbitraryString');
th.pushStack('secondString');
t.strictEquals(th.atStackTop(), false);
th.popStack();
t.strictEquals(th.atStackTop(), true);
t.end();
});
test('reuseStackForNextBlock', t => {
const th = new Thread('arbitraryString');
th.pushStack('arbitraryString');
th.reuseStackForNextBlock('secondString');
t.strictEquals(th.popStack(), 'secondString');
t.end();
});
test('peekStackFrame', t => {
const th = new Thread('arbitraryString');
th.pushStack('arbitraryString');
t.strictEquals(th.peekStackFrame().warpMode, false);
th.popStack();
t.strictEquals(th.peekStackFrame(), null);
t.end();
});
test('peekParentStackFrame', t => {
const th = new Thread('arbitraryString');
th.pushStack('arbitraryString');
th.peekStackFrame().warpMode = true;
t.strictEquals(th.peekParentStackFrame(), null);
th.pushStack('secondString');
t.strictEquals(th.peekParentStackFrame().warpMode, true);
t.end();
});
test('pushReportedValue', t => {
const th = new Thread('arbitraryString');
th.pushStack('arbitraryString');
th.pushStack('secondString');
th.pushReportedValue('value');
t.strictEquals(th.justReported, 'value');
t.end();
});
test('peekStack', t => {
const th = new Thread('arbitraryString');
th.pushStack('arbitraryString');
t.strictEquals(th.peekStack(), 'arbitraryString');
th.popStack();
t.strictEquals(th.peekStack(), null);
t.end();
});
test('PushGetParam', t => {
const th = new Thread('arbitraryString');
th.pushStack('arbitraryString');
th.initParams();
th.pushParam('testParam', 'testValue');
t.strictEquals(th.peekStackFrame().params.testParam, 'testValue');
t.strictEquals(th.getParam('testParam'), 'testValue');
// Params outside of define stack always evaluate to null
t.strictEquals(th.getParam('nonExistentParam'), null);
2016-04-18 17:20:30 -04:00
t.end();
});
2017-02-10 13:06:39 -05:00
test('goToNextBlock', t => {
const th = new Thread('arbitraryString');
const r = new Runtime();
const s = new Sprite(null, r);
const rt = new RenderedTarget(s, r);
const block1 = {fields: Object,
2017-02-10 13:06:39 -05:00
id: 'arbitraryString',
inputs: Object,
STEPS: Object,
block: 'fakeBlock',
name: 'STEPS',
next: 'secondString',
opcode: 'motion_movesteps',
parent: null,
shadow: false,
topLevel: true,
x: 0,
y: 0
};
const block2 = {fields: Object,
2017-02-10 13:06:39 -05:00
id: 'secondString',
inputs: Object,
STEPS: Object,
block: 'fakeBlock',
name: 'STEPS',
next: null,
2017-11-16 14:23:56 -05:00
opcode: 'procedures_call',
2017-02-10 13:06:39 -05:00
mutation: {proccode: 'fakeCode'},
parent: null,
shadow: false,
topLevel: true,
x: 0,
y: 0
};
2017-02-10 13:06:39 -05:00
rt.blocks.createBlock(block1);
rt.blocks.createBlock(block2);
rt.blocks.createBlock(block2);
th.target = rt;
2017-02-10 13:06:39 -05:00
t.strictEquals(th.peekStack(), null);
th.pushStack('secondString');
t.strictEquals(th.peekStack(), 'secondString');
th.goToNextBlock();
t.strictEquals(th.peekStack(), null);
th.pushStack('secondString');
th.pushStack('arbitraryString');
t.strictEquals(th.peekStack(), 'arbitraryString');
th.goToNextBlock();
t.strictEquals(th.peekStack(), 'secondString');
th.goToNextBlock();
t.strictEquals(th.peekStack(), null);
2017-02-10 13:06:39 -05:00
t.end();
});
test('stopThisScript', t => {
const th = new Thread('arbitraryString');
const r = new Runtime();
const s = new Sprite(null, r);
const rt = new RenderedTarget(s, r);
const block1 = {fields: Object,
2017-02-10 13:06:39 -05:00
id: 'arbitraryString',
inputs: Object,
STEPS: Object,
block: 'fakeBlock',
name: 'STEPS',
next: null,
opcode: 'motion_movesteps',
parent: null,
shadow: false,
topLevel: true,
x: 0,
y: 0
};
const block2 = {fields: Object,
2017-02-10 13:06:39 -05:00
id: 'secondString',
inputs: Object,
STEPS: Object,
block: 'fakeBlock',
name: 'STEPS',
next: null,
opcode: 'procedures_call',
2017-02-10 13:06:39 -05:00
mutation: {proccode: 'fakeCode'},
parent: null,
shadow: false,
topLevel: true,
x: 0,
y: 0
};
const block3 = {fields: Object,
id: 'thirdString',
inputs: Object,
STEPS: Object,
block: 'fakeBlock',
name: 'STEPS',
next: null,
opcode: 'procedures_definition',
mutation: {proccode: 'fakeCode'},
parent: null,
shadow: false,
topLevel: true,
x: 0,
y: 0
};
2017-02-10 13:06:39 -05:00
rt.blocks.createBlock(block1);
rt.blocks.createBlock(block2);
rt.blocks.createBlock(block3);
2017-02-10 13:06:39 -05:00
th.target = rt;
2017-02-10 13:06:39 -05:00
th.stopThisScript();
t.strictEquals(th.peekStack(), null);
t.strictEquals(th.peekStackFrame(), null);
2017-02-10 13:06:39 -05:00
th.pushStack('arbitraryString');
t.strictEquals(th.peekStack(), 'arbitraryString');
t.notEqual(th.peekStackFrame(), null);
2017-02-10 13:06:39 -05:00
th.stopThisScript();
t.strictEquals(th.peekStack(), null);
t.strictEquals(th.peekStackFrame(), null);
2017-02-10 13:06:39 -05:00
th.pushStack('arbitraryString');
th.pushStack('secondString');
th.stopThisScript();
t.strictEquals(th.peekStack(), null);
t.same(th.stack, ['arbitraryString', 'secondString']);
t.notEqual(th.peekStackFrame(), null);
while (th.peekStackFrame()) th.popStack();
th.pushStack('arbitraryString');
th.pushStack('secondString');
th.pushStack('thirdString');
th.stopThisScript();
t.strictEquals(th.peekStack(), null);
t.same(th.stack, ['arbitraryString', 'secondString']);
t.notEqual(th.peekStackFrame(), null);
2017-02-10 13:06:39 -05:00
t.end();
});
test('isRecursiveCall', t => {
const th = new Thread('arbitraryString');
const r = new Runtime();
const s = new Sprite(null, r);
const rt = new RenderedTarget(s, r);
const block1 = {fields: Object,
2017-02-10 13:06:39 -05:00
id: 'arbitraryString',
inputs: Object,
STEPS: Object,
block: 'fakeBlock',
name: 'STEPS',
next: null,
opcode: 'motion_movesteps',
parent: null,
shadow: false,
topLevel: true,
x: 0,
y: 0
};
const block2 = {fields: Object,
2017-02-10 13:06:39 -05:00
id: 'secondString',
inputs: Object,
STEPS: Object,
block: 'fakeBlock',
name: 'STEPS',
next: null,
opcode: 'procedures_call',
2017-02-10 13:06:39 -05:00
mutation: {proccode: 'fakeCode'},
parent: null,
shadow: false,
topLevel: true,
x: 0,
y: 0
};
2017-02-10 13:06:39 -05:00
rt.blocks.createBlock(block1);
rt.blocks.createBlock(block2);
th.target = rt;
2017-02-10 13:06:39 -05:00
t.strictEquals(th.isRecursiveCall('fakeCode'), false);
th.pushStack('secondString');
t.strictEquals(th.isRecursiveCall('fakeCode'), false);
th.pushStack('arbitraryString');
t.strictEquals(th.isRecursiveCall('fakeCode'), true);
th.pushStack('arbitraryString');
t.strictEquals(th.isRecursiveCall('fakeCode'), true);
th.popStack();
t.strictEquals(th.isRecursiveCall('fakeCode'), true);
th.popStack();
t.strictEquals(th.isRecursiveCall('fakeCode'), false);
th.popStack();
t.strictEquals(th.isRecursiveCall('fakeCode'), false);
2017-02-10 13:06:39 -05:00
t.end();
});