sphero-pwn
Version:
Driver for Sphero robots
411 lines (379 loc) • 16.2 kB
text/coffeescript
Robot = SpheroPwn.Robot
describe 'Robot', ->
describe '._macroStatusFromData', ->
it 'parses a no-macro response correctly', ->
data = new Buffer [0x00, 0xAA, 0xBB]
expect(Robot._macroStatusFromData(data)).to.equal null
it 'parses a system macro response correctly', ->
data = new Buffer [0x02, 0x12, 0x34]
expect(Robot._macroStatusFromData(data)).to.deep.equal(
macroId: 2, commandId: 0x1234, type: 'system')
it 'parses a user macro response correctly', ->
data = new Buffer [0x28, 0x12, 0x34]
expect(Robot._macroStatusFromData(data)).to.deep.equal(
macroId: 40, commandId: 0x1234, type: 'user')
it 'parses a streaming macro response correctly', ->
data = new Buffer [0xFE, 0x12, 0x34]
expect(Robot._macroStatusFromData(data)).to.deep.equal(
macroId: 254, commandId: 0x1234, type: 'streaming')
it 'parses a temporary macro response correctly', ->
data = new Buffer [0xFF, 0x12, 0x34]
expect(Robot._macroStatusFromData(data)).to.deep.equal(
macroId: 255, commandId: 0x1234, type: 'temporary')
describe '#_saveMacro with short macro', ->
beforeEach ->
testRecordingChannel('macro-markers')
.then (channel) =>
@channel = channel
@robot = new Robot @channel
afterEach ->
@robot.resetMacros()
it 'creates a macro runnable by #runMacro', ->
macroBytes = new Buffer([
0x14, # MF_ALLOW_SOD | MF_ENDSIG
0x15, 0xAA, # emit marker 0xAA
0x15, 0xBB, # emit marker 0xBB
0x00 # end
])
@robot.resetMacros()
.then (result) =>
expect(result).to.equal true
@robot.abortMacro()
.then (result) =>
expect(result).to.equal null
@robot._saveMacro 0xFF, macroBytes
.then (result) =>
expect(result).to.equal true
new Promise (resolve, reject) =>
events = []
@robot.on 'macro', (event) ->
events.push event
resolve events if events.length is 3
@robot.runMacro 0xFF
.then (events) =>
expect(events.length).to.equal 3
expect(events[0]).to.deep.equal(
markerId: 0xAA, macroId: 0xFF, commandId: 1)
expect(events[1]).to.deep.equal(
markerId: 0xBB, macroId: 0xFF, commandId: 2)
expect(events[2]).to.deep.equal(
markerId: 0x00, macroId: 0xFF, commandId: 3)
describe '#_saveMacro with long macro', ->
beforeEach ->
testRecordingChannel('macro-long-markers')
.then (channel) =>
@channel = channel
@robot = new Robot @channel
afterEach ->
@robot.resetMacros()
it 'creates a macro runnable by #runMacro', ->
macroBytes = new Buffer([
0x14, # MF_ALLOW_SOD | MF_ENDSIG
0x20, 0x00, 0x20, # 32-byte comment
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x15, 0xAA, # emit marker 0xAA
0x15, 0xBB, # emit marker 0xBB
0x00 # end
])
@robot.resetMacros()
.then (result) =>
expect(result).to.equal true
@robot.abortMacro()
.then (result) =>
expect(result).to.equal null
@robot._saveMacro 0xFF, macroBytes
.then (result) =>
expect(result).to.equal true
new Promise (resolve, reject) =>
events = []
@robot.on 'macro', (event) ->
events.push event
resolve events if events.length is 3
@robot.runMacro 0xFF
.then (events) =>
expect(events.length).to.equal 3
expect(events[0]).to.deep.equal(
markerId: 0xAA, macroId: 0xFF, commandId: 2)
expect(events[1]).to.deep.equal(
markerId: 0xBB, macroId: 0xFF, commandId: 3)
expect(events[2]).to.deep.equal(
markerId: 0x00, macroId: 0xFF, commandId: 4)
describe '#_saveMacro with macro that exceeds maximum length', ->
beforeEach ->
testRecordingChannel('macro-too-long')
.then (channel) =>
@channel = channel
@robot = new Robot @channel
afterEach ->
@robot.resetMacros()
it 'returns a rejected promise', ->
macroBytes = new Buffer(0x00 for i in [0...1042])
@robot._saveMacro 0xFF, macroBytes
.then (result) =>
expect(false).to.equal '_saveMacro promise not rejected'
.catch (error) =>
expect(error).to.be.an.instanceOf Error
expect(error).to.have.property 'message',
'Macro length 1042 exceeds maximum of 253 bytes'
describe '#_appendMacroFragment', ->
beforeEach ->
testRecordingChannel('macro-append')
.then (channel) =>
@channel = channel
@robot = new Robot @channel
afterEach ->
@robot.resetMacros()
it 'creates a macro runnable by #runMacro', ->
macroBytes = new Buffer([
0x14, # MF_ALLOW_SOD | MF_ENDSIG
0x20, 0x00, 0x20, # 32-byte comment
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x15, 0xAA, # emit marker 0xAA
0x15, 0xBB, # emit marker 0xBB
0x00 # end
])
@robot.resetMacros()
.then (result) =>
expect(result).to.equal true
@robot.abortMacro()
.then (result) =>
expect(result).to.equal null
@robot._appendMacroFragment true, macroBytes.slice(0, 16)
.then (result) =>
expect(result).to.equal true
@robot._appendMacroFragment false, macroBytes.slice(16)
.then (result) =>
expect(result).to.equal true
new Promise (resolve, reject) =>
events = []
@robot.on 'macro', (event) ->
events.push event
resolve events if events.length is 3
@robot.runMacro 0xFF
.then (events) =>
expect(events.length).to.equal 3
expect(events[0]).to.deep.equal(
markerId: 0xAA, macroId: 0xFF, commandId: 2)
expect(events[1]).to.deep.equal(
markerId: 0xBB, macroId: 0xFF, commandId: 3)
expect(events[2]).to.deep.equal(
markerId: 0x00, macroId: 0xFF, commandId: 4)
describe '#loadMacro with short user macro', ->
beforeEach ->
testRecordingChannel('macro-load-short-user')
.then (channel) =>
@channel = channel
@robot = new Robot @channel
afterEach ->
@robot.resetMacros()
it 'creates a macro runnable by #runMacro', ->
macroBytes = new Buffer([
0x14, # MF_ALLOW_SOD | MF_ENDSIG
0x15, 0xAA, # emit marker 0xAA
0x15, 0xBB, # emit marker 0xBB
0x00 # end
])
@robot.resetMacros()
.then (result) =>
expect(result).to.equal true
@robot.abortMacro()
.then (result) =>
expect(result).to.equal null
@robot.loadMacro 0x40, macroBytes
.then (result) =>
expect(result).to.equal true
new Promise (resolve, reject) =>
events = []
@robot.on 'macro', (event) ->
events.push event
resolve events if events.length is 3
@robot.runMacro 0x40
.then (events) =>
expect(events.length).to.equal 3
expect(events[0]).to.deep.equal(
markerId: 0xAA, macroId: 0x40, commandId: 1)
expect(events[1]).to.deep.equal(
markerId: 0xBB, macroId: 0x40, commandId: 2)
expect(events[2]).to.deep.equal(
markerId: 0x00, macroId: 0x40, commandId: 3)
describe '#loadMacro with long user macro', ->
beforeEach ->
testRecordingChannel('macro-load-long-user')
.then (channel) =>
@channel = channel
@robot = new Robot @channel
afterEach ->
@robot.resetMacros()
it 'returns a rejected promise', ->
macroBytes = new Buffer(0x00 for i in [0...1042])
@robot.loadMacro 0x40, macroBytes
.then (result) =>
expect(false).to.equal 'loadMacro promise not rejected'
.catch (error) =>
expect(error).to.be.an.instanceOf Error
expect(error).to.have.property 'message',
'Macro length 1042 exceeds maximum of 253 bytes; ' +
'only the temporary macro be longer'
describe '#loadMacro with short temporary macro', ->
beforeEach ->
testRecordingChannel('macro-load-short-temp')
.then (channel) =>
@channel = channel
@robot = new Robot @channel
afterEach ->
@robot.resetMacros()
it 'creates a macro runnable by #runMacro', ->
macroBytes = new Buffer([
0x14, # MF_ALLOW_SOD | MF_ENDSIG
0x15, 0xAA, # emit marker 0xAA
0x15, 0xBB, # emit marker 0xBB
0x00 # end
])
@robot.resetMacros()
.then (result) =>
expect(result).to.equal true
@robot.abortMacro()
.then (result) =>
expect(result).to.equal null
@robot.loadMacro 0xFF, macroBytes
.then (result) =>
expect(result).to.equal true
new Promise (resolve, reject) =>
events = []
@robot.on 'macro', (event) ->
events.push event
resolve events if events.length is 3
@robot.runMacro 0xFF
.then (events) =>
expect(events.length).to.equal 3
expect(events[0]).to.deep.equal(
markerId: 0xAA, macroId: 0xFF, commandId: 1)
expect(events[1]).to.deep.equal(
markerId: 0xBB, macroId: 0xFF, commandId: 2)
expect(events[2]).to.deep.equal(
markerId: 0x00, macroId: 0xFF, commandId: 3)
describe '#loadMacro with long macro', ->
beforeEach ->
testRecordingChannel('macro-load-long-temp')
.then (channel) =>
@channel = channel
@robot = new Robot @channel
afterEach ->
@robot.resetMacros()
it 'creates a macro runnable by #runMacro', ->
macroBytes = new Buffer([
0x14, # MF_ALLOW_SOD | MF_ENDSIG
0x20, 0x00, 0x40, # 64-byte comment A
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x20, 0x00, 0x40, # 64-byte comment B
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x20, 0x00, 0x40, # 64-byte comment A
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x15, 0xAA, # emit marker 0xAA
0x20, 0x00, 0x40, # 64-byte comment B
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x20, 0x00, 0x40, # 64-byte comment A
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x20, 0x00, 0x40, # 64-byte comment B
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x15, 0xBB, # emit marker 0xBB
0x20, 0x00, 0x40, # 64-byte comment A
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x20, 0x00, 0x40, # 64-byte comment B
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x20, 0x00, 0x40, # 64-byte comment A
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x00 # end
])
@robot.resetMacros()
.then (result) =>
expect(result).to.equal true
@robot.abortMacro()
.then (result) =>
expect(result).to.equal null
@robot.loadMacro 0xFF, macroBytes
.then (result) =>
expect(result).to.equal true
new Promise (resolve, reject) =>
events = []
@robot.on 'macro', (event) ->
events.push event
resolve events if events.length is 3
@robot.runMacro 0xFF
.then (events) =>
expect(events.length).to.equal 3
expect(events[0]).to.deep.equal(
markerId: 0xAA, macroId: 0xFF, commandId: 4)
expect(events[1]).to.deep.equal(
markerId: 0xBB, macroId: 0xFF, commandId: 8)
expect(events[2]).to.deep.equal(
markerId: 0x00, macroId: 0xFF, commandId: 12)