Spaces:
Runtime error
Runtime error
| const test = require('tap').test; | |
| const Control = require('../../src/blocks/scratch3_control'); | |
| const Runtime = require('../../src/engine/runtime'); | |
| const BlockUtility = require('../../src/engine/block-utility'); | |
| test('getPrimitives', t => { | |
| const rt = new Runtime(); | |
| const c = new Control(rt); | |
| t.type(c.getPrimitives(), 'object'); | |
| t.end(); | |
| }); | |
| test('repeat', t => { | |
| const rt = new Runtime(); | |
| const c = new Control(rt); | |
| // Test harness (mocks `util`) | |
| let i = 0; | |
| const repeat = 10; | |
| const util = { | |
| stackFrame: Object.create(null), | |
| startBranch: function () { | |
| i++; | |
| c.repeat({TIMES: repeat}, util); | |
| } | |
| }; | |
| // Execute test | |
| c.repeat({TIMES: 10}, util); | |
| t.strictEqual(util.stackFrame.loopCounter, -1); | |
| t.strictEqual(i, repeat); | |
| t.end(); | |
| }); | |
| test('repeat rounds with round()', t => { | |
| const rt = new Runtime(); | |
| const c = new Control(rt); | |
| const roundingTest = (inputForRepeat, expectedTimes) => { | |
| // Test harness (mocks `util`) | |
| let i = 0; | |
| const util = { | |
| stackFrame: Object.create(null), | |
| startBranch: function () { | |
| i++; | |
| c.repeat({TIMES: inputForRepeat}, util); | |
| } | |
| }; | |
| // Execute test | |
| c.repeat({TIMES: inputForRepeat}, util); | |
| t.strictEqual(i, expectedTimes); | |
| }; | |
| // Execute tests | |
| roundingTest(3.2, 3); | |
| roundingTest(3.7, 4); | |
| roundingTest(3.5, 4); | |
| t.end(); | |
| }); | |
| test('repeatUntil', t => { | |
| const rt = new Runtime(); | |
| const c = new Control(rt); | |
| // Test harness (mocks `util`) | |
| let i = 0; | |
| const repeat = 10; | |
| const util = { | |
| stackFrame: Object.create(null), | |
| startBranch: function () { | |
| i++; | |
| c.repeatUntil({CONDITION: (i === repeat)}, util); | |
| } | |
| }; | |
| // Execute test | |
| c.repeatUntil({CONDITION: (i === repeat)}, util); | |
| t.strictEqual(i, repeat); | |
| t.end(); | |
| }); | |
| test('repeatWhile', t => { | |
| const rt = new Runtime(); | |
| const c = new Control(rt); | |
| // Test harness (mocks `util`) | |
| let i = 0; | |
| const repeat = 10; | |
| const util = { | |
| stackFrame: Object.create(null), | |
| startBranch: function () { | |
| i++; | |
| // Note !== instead of === | |
| c.repeatWhile({CONDITION: (i !== repeat)}, util); | |
| } | |
| }; | |
| // Execute test | |
| c.repeatWhile({CONDITION: (i !== repeat)}, util); | |
| t.strictEqual(i, repeat); | |
| t.end(); | |
| }); | |
| test('forEach', t => { | |
| const rt = new Runtime(); | |
| const c = new Control(rt); | |
| const variableValues = []; | |
| const variable = {value: 0}; | |
| let value; | |
| const util = { | |
| stackFrame: Object.create(null), | |
| target: { | |
| lookupOrCreateVariable: function () { | |
| return variable; | |
| } | |
| }, | |
| startBranch: function () { | |
| variableValues.push(variable.value); | |
| c.forEach({VARIABLE: {}, VALUE: value}, util); | |
| } | |
| }; | |
| // for each (variable) in "5" | |
| // ..should yield variable values 1, 2, 3, 4, 5 | |
| util.stackFrame = Object.create(null); | |
| variableValues.splice(0); | |
| variable.value = 0; | |
| value = '5'; | |
| c.forEach({VARIABLE: {}, VALUE: value}, util); | |
| t.deepEqual(variableValues, [1, 2, 3, 4, 5]); | |
| // for each (variable) in 4 | |
| // ..should yield variable values 1, 2, 3, 4 | |
| util.stackFrame = Object.create(null); | |
| variableValues.splice(0); | |
| variable.value = 0; | |
| value = 4; | |
| c.forEach({VARIABLE: {}, VALUE: value}, util); | |
| t.deepEqual(variableValues, [1, 2, 3, 4]); | |
| t.end(); | |
| }); | |
| test('forever', t => { | |
| const rt = new Runtime(); | |
| const c = new Control(rt); | |
| // Test harness (mocks `util`) | |
| let i = 0; | |
| const util = { | |
| startBranch: function (branchNum, isLoop) { | |
| i++; | |
| t.strictEqual(branchNum, 1); | |
| t.strictEqual(isLoop, true); | |
| } | |
| }; | |
| // Execute test | |
| c.forever(null, util); | |
| t.strictEqual(i, 1); | |
| t.end(); | |
| }); | |
| test('if / ifElse', t => { | |
| const rt = new Runtime(); | |
| const c = new Control(rt); | |
| // Test harness (mocks `util`) | |
| let i = 0; | |
| const util = { | |
| startBranch: function (branchNum) { | |
| i += branchNum; | |
| } | |
| }; | |
| // Execute test | |
| c.if({CONDITION: true}, util); | |
| t.strictEqual(i, 1); | |
| c.if({CONDITION: false}, util); | |
| t.strictEqual(i, 1); | |
| c.ifElse({CONDITION: true}, util); | |
| t.strictEqual(i, 2); | |
| c.ifElse({CONDITION: false}, util); | |
| t.strictEqual(i, 4); | |
| t.end(); | |
| }); | |
| test('stop', t => { | |
| const rt = new Runtime(); | |
| const c = new Control(rt); | |
| // Test harness (mocks `util`) | |
| const state = { | |
| stopAll: 0, | |
| stopOtherTargetThreads: 0, | |
| stopThisScript: 0 | |
| }; | |
| const util = { | |
| stopAll: function () { | |
| state.stopAll++; | |
| }, | |
| stopOtherTargetThreads: function () { | |
| state.stopOtherTargetThreads++; | |
| }, | |
| stopThisScript: function () { | |
| state.stopThisScript++; | |
| } | |
| }; | |
| // Execute test | |
| c.stop({STOP_OPTION: 'all'}, util); | |
| c.stop({STOP_OPTION: 'other scripts in sprite'}, util); | |
| c.stop({STOP_OPTION: 'other scripts in stage'}, util); | |
| c.stop({STOP_OPTION: 'this script'}, util); | |
| t.strictEqual(state.stopAll, 1); | |
| t.strictEqual(state.stopOtherTargetThreads, 2); | |
| t.strictEqual(state.stopThisScript, 1); | |
| t.end(); | |
| }); | |
| test('counter, incrCounter, clearCounter', t => { | |
| const rt = new Runtime(); | |
| const c = new Control(rt); | |
| // Default value | |
| t.strictEqual(c.getCounter(), 0); | |
| c.incrCounter(); | |
| c.incrCounter(); | |
| t.strictEqual(c.getCounter(), 2); | |
| c.clearCounter(); | |
| t.strictEqual(c.getCounter(), 0); | |
| t.end(); | |
| }); | |
| test('allAtOnce', t => { | |
| const rt = new Runtime(); | |
| const c = new Control(rt); | |
| // Test harness (mocks `util`) | |
| let ran = false; | |
| const util = { | |
| startBranch: function () { | |
| ran = true; | |
| } | |
| }; | |
| // Execute test | |
| c.allAtOnce({}, util); | |
| t.true(ran); | |
| t.end(); | |
| }); | |
| test('wait', t => { | |
| const rt = new Runtime(); | |
| const c = new Control(rt); | |
| const args = {DURATION: .01}; | |
| const waitTime = args.DURATION * 1000; | |
| const startTest = Date.now(); | |
| const threshold = 1000 / 60; // 60 hz | |
| let yields = 0; | |
| const util = new BlockUtility(); | |
| const mockUtil = { | |
| stackFrame: {}, | |
| yield: () => yields++, | |
| stackTimerNeedsInit: util.stackTimerNeedsInit, | |
| startStackTimer: util.startStackTimer, | |
| stackTimerFinished: util.stackTimerFinished | |
| }; | |
| c.wait(args, mockUtil); | |
| t.equal(yields, 1, 'First wait block yielded'); | |
| // Spin the cpu until enough time passes | |
| let timeElapsed = 0; | |
| while (timeElapsed < waitTime) { | |
| timeElapsed = mockUtil.stackFrame.timer.timeElapsed(); | |
| // In case util.timer is broken - have our own "exit" | |
| if (Date.now() - startTest > timeElapsed + threshold) { | |
| break; | |
| } | |
| } | |
| c.wait(args, mockUtil); | |
| t.equal(yields, 1, 'Second call after timeElapsed does not yield'); | |
| t.equal(waitTime, mockUtil.stackFrame.duration); | |
| t.ok(timeElapsed >= (waitTime - threshold) && | |
| timeElapsed <= (waitTime + threshold)); | |
| t.end(); | |
| }); | |