Spaces:
Running
Running
const test = require('tap').test; | |
const Sequencer = require('../../src/engine/sequencer'); | |
const Runtime = require('../../src/engine/runtime'); | |
const Thread = require('../../src/engine/thread'); | |
const RenderedTarget = require('../../src/sprites/rendered-target'); | |
const Sprite = require('../../src/sprites/sprite'); | |
test('spec', t => { | |
t.type(Sequencer, 'function'); | |
const r = new Runtime(); | |
const s = new Sequencer(r); | |
t.type(s, 'object'); | |
t.ok(s instanceof Sequencer); | |
t.type(s.stepThreads, 'function'); | |
t.type(s.stepThread, 'function'); | |
t.type(s.stepToBranch, 'function'); | |
t.type(s.stepToProcedure, 'function'); | |
t.type(s.retireThread, 'function'); | |
t.end(); | |
}); | |
const randomString = function () { | |
const top = Math.random().toString(36); | |
return top.substring(7); | |
}; | |
const generateBlock = function (id) { | |
const block = {fields: Object, | |
id: id, | |
inputs: {}, | |
STEPS: Object, | |
block: 'fakeBlock', | |
name: 'fakeName', | |
next: null, | |
opcode: 'procedures_definition', | |
mutation: {proccode: 'fakeCode'}, | |
parent: null, | |
shadow: false, | |
topLevel: true, | |
x: 0, | |
y: 0 | |
}; | |
return block; | |
}; | |
const generateBlockInput = function (id, next, inp) { | |
const block = {fields: Object, | |
id: id, | |
inputs: {SUBSTACK: {block: inp, name: 'SUBSTACK'}}, | |
STEPS: Object, | |
block: 'fakeBlock', | |
name: 'fakeName', | |
next: next, | |
opcode: 'procedures_definition', | |
mutation: {proccode: 'fakeCode'}, | |
parent: null, | |
shadow: false, | |
topLevel: true, | |
x: 0, | |
y: 0 | |
}; | |
return block; | |
}; | |
const generateThread = function (runtime) { | |
const s = new Sprite(null, runtime); | |
const rt = new RenderedTarget(s, runtime); | |
const th = new Thread(randomString()); | |
let next = randomString(); | |
let inp = randomString(); | |
let name = th.topBlock; | |
rt.blocks.createBlock(generateBlockInput(name, next, inp)); | |
th.pushStack(name); | |
rt.blocks.createBlock(generateBlock(inp)); | |
for (let i = 0; i < 10; i++) { | |
name = next; | |
next = randomString(); | |
inp = randomString(); | |
rt.blocks.createBlock(generateBlockInput(name, next, inp)); | |
th.pushStack(name); | |
rt.blocks.createBlock(generateBlock(inp)); | |
} | |
rt.blocks.createBlock(generateBlock(next)); | |
th.pushStack(next); | |
th.target = rt; | |
th.blockContainer = rt.blocks; | |
runtime.threads.push(th); | |
return th; | |
}; | |
test('stepThread', t => { | |
const r = new Runtime(); | |
const s = new Sequencer(r); | |
let th = generateThread(r); | |
t.notEquals(th.status, Thread.STATUS_DONE); | |
s.stepThread(th); | |
t.strictEquals(th.status, Thread.STATUS_DONE); | |
th = generateThread(r); | |
th.status = Thread.STATUS_YIELD; | |
s.stepThread(th); | |
t.notEquals(th.status, Thread.STATUS_DONE); | |
th.status = Thread.STATUS_PROMISE_WAIT; | |
s.stepThread(th); | |
t.notEquals(th.status, Thread.STATUS_DONE); | |
t.end(); | |
}); | |
test('stepToBranch', t => { | |
const r = new Runtime(); | |
const s = new Sequencer(r); | |
const th = generateThread(r); | |
s.stepToBranch(th, 2, false); | |
t.strictEquals(th.peekStack(), null); | |
th.popStack(); | |
s.stepToBranch(th, 1, false); | |
t.strictEquals(th.peekStack(), null); | |
th.popStack(); | |
th.popStack(); | |
s.stepToBranch(th, 1, false); | |
t.notEquals(th.peekStack(), null); | |
t.end(); | |
}); | |
test('retireThread', t => { | |
const r = new Runtime(); | |
const s = new Sequencer(r); | |
const th = generateThread(r); | |
t.strictEquals(th.stack.length, 12); | |
s.retireThread(th); | |
t.strictEquals(th.stack.length, 0); | |
t.strictEquals(th.status, Thread.STATUS_DONE); | |
t.end(); | |
}); | |
test('stepToProcedure', t => { | |
const r = new Runtime(); | |
const s = new Sequencer(r); | |
const th = generateThread(r); | |
let expectedBlock = th.peekStack(); | |
s.stepToProcedure(th, ''); | |
t.strictEquals(th.peekStack(), expectedBlock); | |
s.stepToProcedure(th, 'faceCode'); | |
t.strictEquals(th.peekStack(), expectedBlock); | |
th.target.blocks.createBlock({ | |
id: 'internalId', | |
opcode: 'procedures_prototype', | |
mutation: { | |
proccode: 'othercode' | |
} | |
}); | |
expectedBlock = th.stack[th.stack.length - 4]; | |
th.target.blocks.getBlock(expectedBlock).inputs.custom_block = { | |
type: 'custom_block', | |
block: 'internalId' | |
}; | |
s.stepToProcedure(th, 'othercode'); | |
t.strictEquals(th.peekStack(), expectedBlock); | |
t.end(); | |
}); | |
test('stepThreads', t => { | |
const r = new Runtime(); | |
r.currentStepTime = Infinity; | |
const s = new Sequencer(r); | |
t.strictEquals(s.stepThreads().length, 0); | |
generateThread(r); | |
t.strictEquals(r.threads.length, 1); | |
// Threads should be marked DONE and removed in the same step they finish. | |
t.strictEquals(s.stepThreads().length, 1); | |
t.end(); | |
}); | |