Spaces:
Runtime error
Runtime error
| 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(); | |
| }); | |