UNPKG

rollo

Version:

The Rollo programming language for the Orbotix Sphero robot using Node.js and Cylon.js

896 lines (744 loc) 29.7 kB
/** * Created with IntelliJ IDEA. * User: mfo * Date: 5/15/15 * Time: 11:10 PM */ var should = require('chai').should(); var sinon = require('sinon'); var events = require('../lib/events'); var parse = require('../lib/rolloLanguage').parse; var constants = require('../lib/constants'); var proxyquire = require('proxyquire'); //console.log("skip: " + process.env.MOCHA_SKIP_SLOW_TESTS); var doSlowTests = process.env.MOCHA_SKIP_SLOW_TESTS ? false : true; describe('state', function () { it('should have default values', function () { var state = require('../lib/rolloExec').state; state.speed.should.equal(0); state.defaultSpeed.should.equal(50); state.heading.should.equal(0); state.cmdCount.should.equal(0); state.unknownCmdCount.should.equal(0); state.stopped.should.equal(false); }) }); function linesOnly(obj) { if (obj.hasOwnProperty('line')) { var a = obj.line; var b = []; a.forEach(function (element) { if (typeof element != 'object') { b.push(element); } else { b.push(element.map(linesOnly)); } }); return b; } else { return obj; } } function getMockSphero() { mySphero = { roll: sinon.stub(), on: sinon.stub(), configureCollisionDetection: sinon.stub(), setColor: sinon.stub(), startCalibration: sinon.stub(), finishCalibration: sinon.stub() }; return mySphero; } describe('parse', function () { it('should parse a simple command with no params', function () { parse('go').map(linesOnly).should.deep.equal([['go']]); }); it('should parse a simple command with 1 string param', function () { parse('color "red"').map(linesOnly).should.deep.equal([['color', 'red']]); }); it('should parse a simple command with 1 numeric param', function () { parse('go 3 seconds').map(linesOnly).should.deep.equal([['go', 3]]); }); it('should parse a block command with 1 numeric param', function () { parse('repeat 3 times {\ngo\nstop\n}').map(linesOnly) .should.deep.equal([['repeat', 3, [['go'], ['stop']]]]); }); it('should parse a conditional > block', function () { parse('if 2 > 4 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['>', 2, 4], [['stop'], ['go']], []]]); parse('if 2 greater than 4 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['>', 2, 4], [['stop'], ['go']], []]]); parse('if 2 is greater than 4 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['>', 2, 4], [['stop'], ['go']], []]]); parse('if 2 more than 4 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['>', 2, 4], [['stop'], ['go']], []]]); parse('if 2 is more than 4 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['>', 2, 4], [['stop'], ['go']], []]]); }); it('should parse a conditional > block', function () { parse('if 2 > 4 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['>', 2, 4], [['stop'], ['go']], []]]); parse('if 2 greater than 4 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['>', 2, 4], [['stop'], ['go']], []]]); parse('if 2 is greater than 4 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['>', 2, 4], [['stop'], ['go']], []]]); parse('if 2 more than 4 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['>', 2, 4], [['stop'], ['go']], []]]); parse('if 2 is more than 4 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['>', 2, 4], [['stop'], ['go']], []]]); }); it('should parse EOL comments', function () { parse('if 5 < 2 {\nstop# comment here\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['<', 5, 2], [['stop'], ['go']], []]]); parse('if 5 less than 2 {\nstop\ngo #comment here\n}').map(linesOnly) .should.deep.equal([['if', ['<', 5, 2], [['stop'], ['go']], []]]); parse('if 5 is less than 2 {#comment here\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['<', 5, 2], [['stop'], ['go']], []]]); }); it('should parse line comments', function () { parse('if 5 < 2 {\n# comment here\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['<', 5, 2], [['#'], ['stop'], ['go']], []]]); parse('if 5 less than 2 {\n #comment here\nstop\ngo \n}').map(linesOnly) .should.deep.equal([['if', ['<', 5, 2], [['#'], ['stop'], ['go']], []]]); parse('if 5 is less than 2 {\nstop\n#comment here\n # more comment here\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['<', 5, 2], [['stop'], ['#'], ['#'], ['go']], []]]); }); it('should parse a conditional == block', function () { parse('if 1 == 7 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['==', 1, 7], [['stop'], ['go']], []]]); parse('if 1 === 7 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['==', 1, 7], [['stop'], ['go']], []]]); parse('if 1 equals 7 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['==', 1, 7], [['stop'], ['go']], []]]); parse('if 1 is equal to 7 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['==', 1, 7], [['stop'], ['go']], []]]); }); it('should parse a conditional != block', function () { parse('if 1 != 7 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['!=', 1, 7], [['stop'], ['go']], []]]); parse('if 1 !== 7 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['!=', 1, 7], [['stop'], ['go']], []]]); parse('if 1 not equals 7 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['!=', 1, 7], [['stop'], ['go']], []]]); parse('if 1 is not equal to 7 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['!=', 1, 7], [['stop'], ['go']], []]]); }); it('should parse a conditional >= block', function () { parse('if 10 >= 11 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['>=', 10, 11], [['stop'], ['go']], []]]); }); it('should parse a conditional <= block', function () { parse('if 10 <= 11 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['<=', 10, 11], [['stop'], ['go']], []]]); }); it('should parse a conditional block with a complex comparison', function () { //console.log("Object: " + JSON.stringify(parse('if 10 >= 2 + 3 {\nstop\ngo\n}'))); parse('if 10 >= 2 + 3 {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([["if", [">=", 10, ["+", [2, 3]]], [["stop"], ["go"]], []]]); }); it('should parse an if ... else', function () { parse('if 10 >= 11 {\nstop\n}\nelse {\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['>=', 10, 11], [['stop']], [['go']]]]); }); it('should parse a sub and gosub', function () { parse('gosub mySub\nsub mySub {\nstop\ngo\n}').map(linesOnly) .should.deep.equal([["gosub", "mysub"], ["sub", "mysub", [["stop"], ["go"]]]]); }); it('should parse regardless of case', function () { parse('iF 1 != 7 {\nsTOp\nGo\n}').map(linesOnly) .should.deep.equal([['if', ['!=', 1, 7], [['stop'], ['go']], []]]); parse('IF 1 !== 7 {\nSTOP\nGO\n}').map(linesOnly) .should.deep.equal([['if', ['!=', 1, 7], [['stop'], ['go']], []]]); parse('If 1 NOT EQuals 7 {\nstOP\nGO\n}').map(linesOnly) .should.deep.equal([['if', ['!=', 1, 7], [['stop'], ['go']], []]]); parse('if 1 IS nOt EquAL to 7 {\nSTOP\ngo\n}').map(linesOnly) .should.deep.equal([['if', ['!=', 1, 7], [['stop'], ['go']], []]]); }); }); describe('functions', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; var variables = require('../lib/rolloExec').variables; it('should return the getSpeed() value', function (done) { var mySphero = getMockSphero(); delete variables['$var1']; state.speed = 23; execute(mySphero, parse('let $var1 = getSpeed()'), function () { variables['$var1'].should.equal(23); done(); }); }); it('should return the getHeading() value', function (done) { var mySphero = getMockSphero(); delete variables['$var1']; state.heading = 42; execute(mySphero, parse('let $var1 = getHeading()'), function () { variables['$var1'].should.equal(42); done(); }); }); it('should return the getDefaultSpeed() value', function (done) { var mySphero = getMockSphero(); delete variables['$var1']; state.defaultSpeed = 3.1415; execute(mySphero, parse('let $var1 = getDefaultSpeed()'), function () { variables['$var1'].should.equal(3.1415); done(); }); }); }); describe('while', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; var variables = require('../lib/rolloExec').variables; it('should loop until the condition is true', function (done) { var mySphero = getMockSphero(); delete variables['$var1']; execute(mySphero, parse('while $var1 < 3 {\n let $var1 = $var1 + 1\n color "blue"\n}'), function () { variables['$var1'].should.equal(3); mySphero.setColor.callCount.should.equal(3); done(); }); }); }); describe('do ... while', function () { var execute = require('../lib/rolloExec').execute; var variables = require('../lib/rolloExec').variables; it('should loop until the condition is true', function (done) { var mySphero = getMockSphero(); delete variables['$var1']; execute(mySphero, parse('do {\n let $var1 = $var1 + 1\n color "blue"\n} while $var1 < 3\n'), function () { variables['$var1'].should.equal(3); mySphero.setColor.callCount.should.equal(3); done(); }); }); }); describe('do ... until', function () { var execute = require('../lib/rolloExec').execute; var variables = require('../lib/rolloExec').variables; it('should loop until the condition is true', function (done) { var mySphero = getMockSphero(); delete variables['$var1']; execute(mySphero, parse('do {\n let $var1 = $var1 + 1\n color "blue"\n} until $var1 > 2 '), function () { //console.log('count: ' + mySphero.setColor.callCount); variables['$var1'].should.equal(3); mySphero.setColor.callCount.should.equal(3); done(); }); }); }); describe('if', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; var variables = require('../lib/rolloExec').variables; it('should process a true expression evaluation', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('if 10> 9 {\ncolor "red"\n go\n}'), function () { //console.log('count: ' + mySphero.setColor.callCount); mySphero.setColor.callCount.should.equal(1); mySphero.roll.callCount.should.equal(2); done(); }); }); it('should skip a false expression evaluation', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('if 10 <= 9 {\ncolor "red"\n go\n}'), function () { //console.log('count: ' + mySphero.setColor.callCount); mySphero.setColor.callCount.should.equal(0); mySphero.roll.callCount.should.equal(1); done(); }); }); it('should run an else block when false', function (done) { var mySphero = getMockSphero(); var state = require('../lib/rolloExec').state; execute(mySphero, parse('if 10 <= 9 {\ncolor "red"\n go\n}\nelse {\nspeed 50\n}\n'), function () { //console.log('count: ' + mySphero.setColor.callCount); mySphero.setColor.callCount.should.equal(0); mySphero.roll.callCount.should.equal(1); state.defaultSpeed.should.equal(127); done(); }); }); it('should process a complex true expression evaluation', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('if 10 - 2 > 3 * (9 - 2*4) {\ncolor "red"\n go\n}'), function () { //console.log('count: ' + mySphero.setColor.callCount); mySphero.setColor.callCount.should.equal(1); mySphero.roll.callCount.should.equal(2); done(); }); }); }); /* * let $var = 2 + 3*2 + (2+$v2) /3 */ describe('let', function () { var execute = require('../lib/rolloExec').execute; var variables = require('../lib/rolloExec').variables; it('should be able to assign a value to a variable', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('let $myVar= 2'), function () { variables.hasOwnProperty('$myVar').should.equal(true); variables['$myVar'].should.equal(2); done(); }); }); it('should be able to assign an addition expression to a variable', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('let $myVar= 2 + 3'), function () { variables.hasOwnProperty('$myVar').should.equal(true); variables['$myVar'].should.equal(5); done(); }); }); it('should be able to assign a multiplication expression to a variable', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('let $myVar= 2* 3'), function () { variables.hasOwnProperty('$myVar').should.equal(true); variables['$myVar'].should.equal(6); done(); }); }); it('should be able to assign a subtraction expression to a variable', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('let $myVar= 3-2'), function () { variables.hasOwnProperty('$myVar').should.equal(true); variables['$myVar'].should.equal(1); done(); }); }); it('should be able to assign a division expression to a variable', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('let $myVar=6 /2'), function () { variables.hasOwnProperty('$myVar').should.equal(true); variables['$myVar'].should.equal(3); done(); }); }); it('should be able to assign a complex expression to a variable', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('let $myVar= 2*3+3'), function () { variables.hasOwnProperty('$myVar').should.equal(true); variables['$myVar'].should.equal(9); done(); }); }); it('should be able to evaluate an expression with a self-refrencing variable', function (done) { var mySphero = getMockSphero(); variables['$myVar'] = 4; execute(mySphero, parse('let $myVar= 3*$myVar + 3'), function () { variables.hasOwnProperty('$myVar').should.equal(true); variables['$myVar'].should.equal(15); done(); }); }); it('should be able to evaluate an expression with a variable', function (done) { var mySphero = getMockSphero(); variables['$someVar'] = 5; execute(mySphero, parse('let $myVar= 3* $someVar + 3'), function () { variables.hasOwnProperty('$myVar').should.equal(true); variables['$myVar'].should.equal(18); variables['$someVar'].should.equal(5); done(); }); }); }); describe('waitForTap', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; if (doSlowTests) { it('should be able to waitForTap with 1 second timeout', function (done) { var mySphero = getMockSphero(); var now = Date.now(); execute(mySphero, parse('waitForTap 1'), function () { var now2 = Date.now(); now2.should.be.above(now + 1000); now2.should.not.be.above(now + 1250); // 250ms wiggle room for other code execution time mySphero.finishCalibration.callCount.should.equal(1); done(); }); }); } if (doSlowTests) { it('should be able to waitForTap and respond to tap event', function (done) { var mySphero = getMockSphero(); var TOPIC_COLLISION = 'collision'; var now = Date.now(); setTimeout(function () { events.publish(TOPIC_COLLISION, {xImpact: 1, yImpact: 2, speed: 50}); }, 250); execute(mySphero, parse('waitForTap 1'), function () { var now2 = Date.now(); //console.log(now2 - now); now2.should.be.above(now + 250); mySphero.finishCalibration.callCount.should.equal(1); done(); }); }); } }); describe('stop()', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; var stop = require('../lib').stop; if (doSlowTests) { it('show allow a stop() command to halt execution', function (done) { var mySphero = getMockSphero(); state.stopped = true; execute(mySphero, parse('waitForTap 1\ncolor "blue"\ncolor "red"'), function () { mySphero.setColor.callCount.should.equal(0); // if >0, then the stop command didn't prevent it done(); }); setTimeout(function() { stop(); }, 250); }); } }); describe('line numbers', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; it('should know how many lines have been run', function (done) { var mySphero = getMockSphero(); var lineEvent = sinon.stub(); var unknownLineEvent = sinon.stub(); var testSub = events.subscribe(constants.LINE_RUNNING, lineEvent); var testSubUnknown = events.subscribe(constants.UNKNOWN_LINE_RUNNING, unknownLineEvent); execute(mySphero, parse('color "orange"\nstop\n\r say "test"'), function () { lineEvent.callCount.should.equal(3); unknownLineEvent.callCount.should.equal(0); testSub.remove(); testSubUnknown.remove(); return done(); }) }); it('should know how many unknown lines have been run', function (done) { var mySphero = getMockSphero(); var lineEvent = sinon.stub(); var unknownLineEvent = sinon.stub(); var testSub = events.subscribe(constants.LINE_RUNNING, lineEvent); var testSubUnknown = events.subscribe(constants.UNKNOWN_LINE_RUNNING, unknownLineEvent); execute(mySphero, [{"number": 1, "line": ["color", "orange"]}, {"number": 2, "line": ["STOOP"]}, {"number": 4, "line": ["say", "test"]}] , function () { lineEvent.callCount.should.equal(2); unknownLineEvent.callCount.should.equal(1); testSub.remove(); testSubUnknown.remove(); return done(); }) }); it('should get a valid line object with the event', function (done) { var mySphero = getMockSphero(); var lineEvent = sinon.stub(); var unknownLineEvent = sinon.stub(); var testSub = events.subscribe(constants.LINE_RUNNING, lineEvent); var testSubUnknown = events.subscribe(constants.UNKNOWN_LINE_RUNNING, unknownLineEvent); execute(mySphero, parse('color "red"'), function () { lineEvent.callCount.should.equal(1); unknownLineEvent.callCount.should.equal(0); lineEvent.calledWith({"number": 1, "line": ["color", "red"]}).should.equal(true); testSub.remove(); testSubUnknown.remove(); return done(); }) }); }); describe('repeat', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; it('should call a block of commands multiple times', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('repeat 2 times {\n color "blue"\n stop\n}'), function () { mySphero.setColor.callCount.should.equal(2); mySphero.roll.callCount.should.equal(3); // exec calls it once every time, so 2 + 1 = 3 done(); }); }); }); describe('gosub', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; it('should call a named sub that appears at end of code', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('gosub myTestSub\n sub myTestSub{\n color "yellow"\n go\n}'), function () { mySphero.setColor.callCount.should.equal(1); mySphero.roll.callCount.should.equal(2); // exec calls it once every time, so 2 + 1 = 3 done(); }); }); it('should call a named sub that appears at start of code', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('sub myTestSub{\n color "yellow"\n go\n}\ngosub myTestSub\n'), function () { mySphero.setColor.callCount.should.equal(1); mySphero.roll.callCount.should.equal(2); // exec calls it once every time, so 2 + 1 = 3 done(); }); }); }); describe('stop', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; it('should be able to stop', function (done) { var mySphero = getMockSphero(); state.heading = 75; state.defaultSpeed = 35; state.speed = 35; execute(mySphero, parse('stop'), function () { mySphero.roll.callCount.should.equal(2); mySphero.roll.calledWith(0, 75).should.equal(true); state.speed.should.equal(0); state.heading.should.equal(75); done(); }); }); }); describe('pointMe', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; it('should be able to start calibration mode', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('pointMe'), function () { mySphero.startCalibration.callCount.should.equal(1); done(); }); }); }); describe('color', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; it('should be able to set the color', function (done) { var mySphero = getMockSphero(); state.color = 0xffffff; execute(mySphero, parse("color 'red'"), function () { mySphero.setColor.calledOnce.should.equal(true); mySphero.setColor.calledWith(0xff0000).should.equal(true); state.color.should.equal(0xff0000); done(); }); }); it('should be able to set the color with mixed case', function (done) { var mySphero = getMockSphero(); state.color = 0xffffff; execute(mySphero, parse("color 'rED'"), function () { mySphero.setColor.calledOnce.should.equal(true); mySphero.setColor.calledWith(0xff0000).should.equal(true); state.color.should.equal(0xff0000); done(); }); }); if (doSlowTests) { it('should be able to flash the color', function (done) { var mySphero = getMockSphero(); state.color = 0xffffff; execute(mySphero, parse("flash 'blue'"), function () { mySphero.setColor.calledOnce.should.equal(true); mySphero.setColor.calledWith(0x0000ff).should.equal(true); setTimeout(function () { mySphero.setColor.calledTwice.should.equal(true); mySphero.setColor.calledWith(0xffffff).should.equal(true); state.color.should.equal(0xffffff); done(); }, 600); }); }); } if (doSlowTests) { it('should be able to pulse the color', function (done) { var mySphero = getMockSphero(); state.color = 0xffffff; execute(mySphero, parse('pulse "green"'), function () { mySphero.setColor.calledOnce.should.equal(true); setTimeout(function () { mySphero.setColor.callCount.should.equal(18); mySphero.setColor.calledWith(0xffffff).should.equal(true); mySphero.setColor.calledWith(0x00ff00).should.equal(true); state.color.should.equal(0xffffff); done(); }, 1100); }); }); } }); describe('wait', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; if (doSlowTests) { it('should be able to wait 1 second', function (done) { var mySphero = getMockSphero(); var now = Date.now(); execute(mySphero, parse('wait 1'), function () { var now2 = Date.now(); now2.should.be.above(now + 1000); now2.should.not.be.above(now + 1250); // 250ms wiggle room for other code execution time mySphero.roll.callCount.should.equal(1); done(); }); }); } }); describe('command aliases', function () { var commands = require('../lib/rolloExec').commands; it('should use delay as an alias for wait', function () { commands.wait.should.equal(commands.delay); }); it('should use turnRight as an alias for right', function () { commands.right.should.equal(commands.turnright); }); it('should use turnLeft as an alias for left', function () { commands.left.should.equal(commands.turnleft); }); it('should use log as an alias for say', function () { commands.log.should.equal(commands.say); }); it('should use waitForHit as an alias for waitForTap', function () { commands.waitforhit.should.equal(commands.waitfortap); }); it('should use turnAround as an alias for reverse', function () { commands.turnaround.should.equal(commands.reverse); }); it('should use loop as an alias for repeat', function () { commands.repeat.should.equal(commands.loop); }); it('should use call as an alias for gosub', function () { commands.gosub.should.equal(commands.call); }); }); describe('go', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; it('should be able to go', function (done) { var mySphero = getMockSphero(); state.heading = 75; state.defaultSpeed = 35; execute(mySphero, parse('go'), function () { mySphero.roll.callCount.should.equal(2); state.speed.should.equal(35); state.heading.should.equal(75); done(); }); }); if (doSlowTests) { it('should be able to go for 1 seconds and stop', function (done) { var mySphero = getMockSphero(); state.heading = 45; var now = Date.now(); execute(mySphero, parse('go 1'), function () { var now2 = Date.now(); now2.should.be.above(now + 1000); now2.should.not.be.above(now + 1250); // 250ms wiggle room for other code execution time mySphero.roll.callCount.should.equal(3); state.speed.should.equal(0); state.heading.should.equal(45); done(); }); }); } }); describe('turn', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; it('should be able to turn right with no parameter', function (done) { var mySphero = getMockSphero(); state.heading = 0; execute(mySphero, parse('right'), function () { state.heading.should.equal(90); mySphero.roll.calledOnce.should.equal(false); done(); }); }); it('should be able to turn right with a parameter', function (done) { var mySphero = getMockSphero(); state.heading = 0; execute(mySphero, parse('right 45'), function () { state.heading.should.equal(45); mySphero.roll.calledOnce.should.equal(false); done(); }); }); it('should be able to turn left with no parameter', function (done) { var mySphero = getMockSphero(); state.heading = 0; execute(mySphero, parse('left'), function () { state.heading.should.equal(270); mySphero.roll.calledOnce.should.equal(false); done(); }); }); it('should be able to turn left with a parameter', function (done) { var mySphero = getMockSphero(); state.heading = 0; execute(mySphero, parse('left 30'), function () { state.heading.should.equal(330); mySphero.roll.calledOnce.should.equal(false); done(); }); }); it('should be able to turn negative degrees', function (done) { var mySphero = getMockSphero(); state.heading = 0; execute(mySphero, parse('turn -90'), function () { state.heading.should.equal(270); mySphero.roll.calledOnce.should.equal(false); done(); }); }); it('should be able to turn positive 45', function (done) { var mySphero = getMockSphero(); state.heading = 0; execute(mySphero, parse('turn 45'), function () { state.heading.should.equal(45); mySphero.roll.calledOnce.should.equal(false); done(); }); }); it('should be able to reverse heading', function (done) { var mySphero = getMockSphero(); state.heading = 45; execute(mySphero, parse('reverse'), function () { state.heading.should.equal(225); mySphero.roll.calledOnce.should.equal(false); done(); }); }); it('should be able to reverse heading and wrap degrees properly to 0 to 359', function (done) { var mySphero = getMockSphero(); state.heading = 225; execute(mySphero, parse('reverse'), function () { state.heading.should.equal(45); mySphero.roll.calledOnce.should.equal(false); done(); }); }); }); describe('speed', function () { var execute = require('../lib/rolloExec').execute; var state = require('../lib/rolloExec').state; it('should be able to set various default speeds', function (done) { var mySphero = getMockSphero(); state.speed = 0; state.defaultSpeed = 50; execute(mySphero, parse('speed 10'), function () { state.defaultSpeed.should.equal(25); state.speed.should.equal(0); mySphero.roll.calledOnce.should.equal(true); done(); }); }); it('should be able to set various default speeds', function (done) { var mySphero = getMockSphero(); execute(mySphero, parse('speed 100'), function () { state.defaultSpeed.should.equal(255); state.speed.should.equal(0); mySphero.roll.calledOnce.should.equal(true); done(); }); }) });