mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-12 17:45:22 +00:00
ble-pybricks-service: add some tests
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
import { Status, statusToFlag } from './protocol';
|
||||
|
||||
describe('status flags should fit in 32 bits', () => {
|
||||
test.each(Object.values(Status).filter((x) => typeof x === 'number'))(
|
||||
'%s',
|
||||
(status) => {
|
||||
expect(Math.log2(statusToFlag(status as Status))).toBe(status);
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,146 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2021 The Pybricks Authors
|
||||
|
||||
import { AsyncSaga } from '../../test';
|
||||
import {
|
||||
didFailToSendCommand,
|
||||
didFailToWriteCommand,
|
||||
didNotifyEvent,
|
||||
didSendCommand,
|
||||
didWriteCommand,
|
||||
eventProtocolError,
|
||||
sendStopUserProgramCommand,
|
||||
statusReportEvent,
|
||||
writeCommand,
|
||||
} from './actions';
|
||||
import { CommandType, ProtocolError } from './protocol';
|
||||
import blePybricksService from './sagas';
|
||||
|
||||
describe('command encoder', () => {
|
||||
test.each([
|
||||
[
|
||||
'stop user program',
|
||||
sendStopUserProgramCommand(0),
|
||||
[
|
||||
0x00, // stop user program command
|
||||
],
|
||||
],
|
||||
])('encode %s request', async (_n, request, expected) => {
|
||||
const saga = new AsyncSaga(blePybricksService);
|
||||
saga.put(request);
|
||||
const message = new Uint8Array(expected);
|
||||
const action = await saga.take();
|
||||
expect(action).toEqual(writeCommand(0, message));
|
||||
await saga.end();
|
||||
});
|
||||
|
||||
test('commands are serialized', async () => {
|
||||
const saga = new AsyncSaga(blePybricksService);
|
||||
|
||||
// we send 4 commands
|
||||
saga.put(sendStopUserProgramCommand(0));
|
||||
saga.put(sendStopUserProgramCommand(1));
|
||||
saga.put(sendStopUserProgramCommand(2));
|
||||
saga.put(sendStopUserProgramCommand(3));
|
||||
|
||||
// but only two didSendCommand actions meaning only the first two completed
|
||||
saga.put(didWriteCommand(0));
|
||||
saga.put(didWriteCommand(1));
|
||||
|
||||
// So only 3 commands were actually sent and two didSendCommand were
|
||||
// dispatched (making 5 total dispatches). The last request is still
|
||||
// buffered and has not been dispatched.
|
||||
const numPending = saga.numPending();
|
||||
expect(numPending).toEqual(5);
|
||||
|
||||
const message = new Uint8Array([CommandType.StopUserProgram]);
|
||||
|
||||
// every other action is the "write command" action
|
||||
// and the interleaving actions are "did send command" actions
|
||||
const action0 = await saga.take();
|
||||
expect(action0).toEqual(writeCommand(0, message));
|
||||
const action1 = await saga.take();
|
||||
expect(action1).toEqual(didSendCommand(0));
|
||||
const action2 = await saga.take();
|
||||
expect(action2).toEqual(writeCommand(1, message));
|
||||
const action3 = await saga.take();
|
||||
expect(action3).toEqual(didSendCommand(1));
|
||||
const action4 = await saga.take();
|
||||
expect(action4).toEqual(writeCommand(2, message));
|
||||
|
||||
await saga.end();
|
||||
});
|
||||
|
||||
test('fail to send triggers fail to write', async () => {
|
||||
const saga = new AsyncSaga(blePybricksService);
|
||||
|
||||
saga.put(sendStopUserProgramCommand(0));
|
||||
|
||||
const message = new Uint8Array([0x00]);
|
||||
const action1 = await saga.take();
|
||||
expect(action1).toEqual(writeCommand(0, message));
|
||||
|
||||
const err = new Error('test error');
|
||||
saga.put(didFailToWriteCommand(0, err));
|
||||
|
||||
const action2 = await saga.take();
|
||||
expect(action2).toEqual(didFailToSendCommand(0, err));
|
||||
|
||||
await saga.end();
|
||||
});
|
||||
});
|
||||
|
||||
describe('event decoder', () => {
|
||||
test.each([
|
||||
[
|
||||
'status report',
|
||||
[
|
||||
0x00, // status report event
|
||||
0x01, // flags count LSB
|
||||
0x00, // .
|
||||
0x00, // .
|
||||
0x00, // flags count MSB
|
||||
],
|
||||
statusReportEvent(0x00000001),
|
||||
],
|
||||
])('decode %s event', async (_n, message, expected) => {
|
||||
const saga = new AsyncSaga(blePybricksService);
|
||||
const notification = new Uint8Array(message);
|
||||
|
||||
saga.put(didNotifyEvent(new DataView(notification.buffer)));
|
||||
|
||||
const action = await saga.take();
|
||||
expect(action).toEqual(expected);
|
||||
|
||||
await saga.end();
|
||||
});
|
||||
|
||||
test.each([
|
||||
[
|
||||
'unknown event',
|
||||
[
|
||||
0xff, // **bad event**
|
||||
0x01, // **junk**
|
||||
0x02, // **junk**
|
||||
0x03, // **junk**
|
||||
0x04, // **junk**
|
||||
],
|
||||
eventProtocolError(
|
||||
new ProtocolError(
|
||||
'unknown pybricks event type: 0xff',
|
||||
new DataView(new Uint8Array().buffer),
|
||||
),
|
||||
),
|
||||
],
|
||||
])('protocol error', async (_n, message, expected) => {
|
||||
const saga = new AsyncSaga(blePybricksService);
|
||||
const notification = new Uint8Array(message);
|
||||
|
||||
saga.put(didNotifyEvent(new DataView(notification.buffer)));
|
||||
|
||||
const action = await saga.take();
|
||||
expect(action).toEqual(expected);
|
||||
|
||||
await saga.end();
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,7 @@
|
||||
// Copyright (c) 2020 The Pybricks Authors
|
||||
|
||||
import { AsyncSaga } from '../../test';
|
||||
import { eventProtocolError } from '../ble-pybricks-service/actions';
|
||||
import { didFailToWrite } from '../ble-uart/actions';
|
||||
import {
|
||||
BleDeviceFailToConnectReasonType,
|
||||
@@ -46,6 +47,16 @@ test('bleDataDidFailToWrite', async () => {
|
||||
await saga.end();
|
||||
});
|
||||
|
||||
test('eventProtocolError', async () => {
|
||||
const saga = new AsyncSaga(errorLog);
|
||||
|
||||
console.error = jest.fn();
|
||||
saga.put(eventProtocolError(new Error('test error')));
|
||||
expect(console.error).toHaveBeenCalledTimes(1);
|
||||
|
||||
await saga.end();
|
||||
});
|
||||
|
||||
test('bootloaderDidFailToConnect', async () => {
|
||||
const saga = new AsyncSaga(errorLog);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user