UNPKG

@stoprocent/bleno

Version:

A Node.js module for implementing BLE (Bluetooth Low Energy) peripherals

322 lines (255 loc) 10.9 kB
/* jshint mocha: true */ const should = require('should'); const Characteristic = require('../lib/characteristic'); Characteristic.RESULT_SUCCESS = 0x99; // override default value as 0x00 isnt the best value for this test describe('Characteristic', function () { const mockUuid = 'mockuuid'; const mockProperties = ['property1', 'property2', 'property3']; const mockSecure = ['secure1', 'secure2', 'secure3']; const mockValue = Buffer.from('mock value'); const mockDescriptors = [{}, {}, {}]; const mockOnReadRequest = function () {}; const mockOnWriteRequest = function () {}; const mockOnSubscribe = function () {}; const mockOnUnsubscribe = function () {}; const mockOnNotify = function () {}; const mockOnIndicate = function () {}; const mockMaxValueSize = 20; const mockUpdateValueCallback = function () {}; it('should create with uuid option', function () { const characteristic = new Characteristic({ uuid: mockUuid }); characteristic.uuid.should.equal(mockUuid); Array.isArray(characteristic.properties).should.equal(true); characteristic.properties.length.should.equal(0); Array.isArray(characteristic.secure).should.equal(true); characteristic.secure.length.should.equal(0); should(characteristic.value).equal(null); Array.isArray(characteristic.descriptors).should.equal(true); characteristic.descriptors.length.should.equal(0); }); it('should create with properties option', function () { const characteristic = new Characteristic({ properties: mockProperties }); characteristic.properties.should.equal(mockProperties); }); it('should create with secure option', function () { const characteristic = new Characteristic({ secure: mockSecure }); characteristic.secure.should.equal(mockSecure); }); it('should create with value option', function () { const characteristic = new Characteristic({ properties: ['read'], value: mockValue }); characteristic.value.should.equal(mockValue); }); it('should not create with value option and non-read properties', function () { (function () { // eslint-disable-next-line no-unused-vars const characteristic = new Characteristic({ properties: ['write'], value: mockValue }); }).should.throw(); }); it('should create with descriptors option', function () { const characteristic = new Characteristic({ descriptors: mockDescriptors }); characteristic.descriptors.should.equal(mockDescriptors); }); it('should create with onReadRequest option', function () { const characteristic = new Characteristic({ onReadRequest: mockOnReadRequest }); characteristic.onReadRequest.should.equal(mockOnReadRequest); }); it('should create with onWriteRequest option', function () { const characteristic = new Characteristic({ onWriteRequest: mockOnWriteRequest }); characteristic.onWriteRequest.should.equal(mockOnWriteRequest); }); it('should create with onSubscribe option', function () { const characteristic = new Characteristic({ onSubscribe: mockOnSubscribe }); characteristic.onSubscribe.should.equal(mockOnSubscribe); }); it('should create with onUnsubscribe option', function () { const characteristic = new Characteristic({ onUnsubscribe: mockOnUnsubscribe }); characteristic.onUnsubscribe.should.equal(mockOnUnsubscribe); }); it('should create with onNotify option', function () { const characteristic = new Characteristic({ onNotify: mockOnNotify }); characteristic.onNotify.should.equal(mockOnNotify); }); it('should create with onIndicate option', function () { const characteristic = new Characteristic({ onIndicate: mockOnIndicate }); characteristic.onIndicate.should.equal(mockOnIndicate); }); it('should toString', function () { const characteristic = new Characteristic({ uuid: mockUuid }); characteristic.toString().should.equal('{"uuid":"mockuuid","properties":[],"secure":[],"value":null,"descriptors":[]}'); }); it('should handle read request', function (done) { const characteristic = new Characteristic({}); const handle = 0; characteristic.emit('readRequest', handle, 0, function (result, data) { result.should.equal(Characteristic.RESULT_UNLIKELY_ERROR); should(data).equal(null); done(); }); }); it('should handle write request', function (done) { const characteristic = new Characteristic({}); const handle = 0; characteristic.emit('writeRequest', handle, Buffer.alloc(0), 0, false, function (result) { result.should.equal(Characteristic.RESULT_UNLIKELY_ERROR); done(); }); }); it('should handle unsubscribe', function () { const characteristic = new Characteristic({}); const handle = 0; characteristic._maxValueSizes.set(handle, mockMaxValueSize); characteristic._updateValueCallbacks.set(handle, mockUpdateValueCallback); characteristic.emit('unsubscribe', handle); should(characteristic.getMaxValueSize(handle)).equal(undefined); should(characteristic._maxValueSizes.has(handle)).equal(false); should(characteristic._updateValueCallbacks.has(handle)).equal(false); }); describe('Handle-based updates', function () { it('should handle subscribe with different handles', function () { const characteristic = new Characteristic({}); const handle1 = 1; const handle2 = 2; const maxValueSize1 = 20; const maxValueSize2 = 30; let updateCallback1Called = false; let updateCallback2Called = false; const updateCallback1 = (data) => { updateCallback1Called = true; should(data).equal('test1'); }; const updateCallback2 = (data) => { updateCallback2Called = true; should(data).equal('test2'); }; // Subscribe first client characteristic.emit('subscribe', handle1, maxValueSize1, updateCallback1); should(characteristic.getMaxValueSize(handle1)).equal(maxValueSize1); should(characteristic._updateValueCallbacks.has(handle1)).equal(true); should(characteristic._updateValueCallbacks.get(handle1)).equal(updateCallback1); // Subscribe second client characteristic.emit('subscribe', handle2, maxValueSize2, updateCallback2); should(characteristic.getMaxValueSize(handle2)).equal(maxValueSize2); should(characteristic._updateValueCallbacks.has(handle2)).equal(true); should(characteristic._updateValueCallbacks.get(handle2)).equal(updateCallback2); // Test updates for each handle characteristic._updateValueCallbacks.get(handle1)('test1'); should(updateCallback1Called).equal(true); characteristic._updateValueCallbacks.get(handle2)('test2'); should(updateCallback2Called).equal(true); }); it('should handle unsubscribe for specific handle', function () { const characteristic = new Characteristic({}); const handle1 = 1; const handle2 = 2; const maxValueSize = 20; // Subscribe both clients characteristic.emit('subscribe', handle1, maxValueSize, () => {}); characteristic.emit('subscribe', handle2, maxValueSize, () => {}); // Unsubscribe first client characteristic.emit('unsubscribe', handle1); // First client should be removed should(characteristic.getMaxValueSize(handle1)).equal(undefined); should(characteristic._updateValueCallbacks.has(handle1)).equal(false); // Second client should still be subscribed should(characteristic.getMaxValueSize(handle2)).equal(maxValueSize); should(characteristic._updateValueCallbacks.has(handle2)).equal(true); // Unsubscribe second client characteristic.emit('unsubscribe', handle2); // Both clients should be removed should(characteristic.getMaxValueSize(handle1)).equal(undefined); should(characteristic.getMaxValueSize(handle2)).equal(undefined); should(characteristic._updateValueCallbacks.has(handle1)).equal(false); should(characteristic._updateValueCallbacks.has(handle2)).equal(false); }); it('should handle read requests for different handles', function (done) { const handle1 = 1; const handle2 = 2; let readCallback1Called = false; let readCallback2Called = false; const characteristic = new Characteristic({ onReadRequest: (handle, offset, callback) => { if (handle === handle1) { readCallback1Called = true; callback(Characteristic.RESULT_SUCCESS, Buffer.from('test1')); } else if (handle === handle2) { readCallback2Called = true; callback(Characteristic.RESULT_SUCCESS, Buffer.from('test2')); } } }); // Test read request for first handle characteristic.emit('readRequest', handle1, 0, (result, data) => { should(result).equal(Characteristic.RESULT_SUCCESS); should(data.toString()).equal('test1'); should(readCallback1Called).equal(true); }); // Test read request for second handle characteristic.emit('readRequest', handle2, 0, (result, data) => { should(result).equal(Characteristic.RESULT_SUCCESS); should(data.toString()).equal('test2'); should(readCallback2Called).equal(true); done(); }); }); it('should handle write requests for different handles', function (done) { const handle1 = 1; const handle2 = 2; const data1 = Buffer.from('test1'); const data2 = Buffer.from('test2'); let writeCallback1Called = false; let writeCallback2Called = false; const characteristic = new Characteristic({ onWriteRequest: (handle, data, offset, withoutResponse, callback) => { if (handle === handle1) { writeCallback1Called = true; should(data).equal(data1); callback(Characteristic.RESULT_SUCCESS); } else if (handle === handle2) { writeCallback2Called = true; should(data).equal(data2); callback(Characteristic.RESULT_SUCCESS); } } }); // Test write request for first handle characteristic.emit('writeRequest', handle1, data1, 0, false, (result) => { should(result).equal(Characteristic.RESULT_SUCCESS); should(writeCallback1Called).equal(true); }); // Test write request for second handle characteristic.emit('writeRequest', handle2, data2, 0, false, (result) => { should(result).equal(Characteristic.RESULT_SUCCESS); should(writeCallback2Called).equal(true); done(); }); }); }); });