@stoprocent/noble 1.9.2-16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/.editorconfig +11 -0
  2. package/.eslintrc.js +25 -0
  3. package/.github/FUNDING.yml +2 -0
  4. package/.github/workflows/fediverse-action.yml +16 -0
  5. package/.github/workflows/nodepackage.yml +77 -0
  6. package/.github/workflows/npm-publish.yml +26 -0
  7. package/.github/workflows/prebuild.yml +65 -0
  8. package/.nycrc.json +4 -0
  9. package/CHANGELOG.md +119 -0
  10. package/LICENSE +20 -0
  11. package/MAINTAINERS.md +1 -0
  12. package/README.md +833 -0
  13. package/assets/noble-logo.png +0 -0
  14. package/assets/noble-logo.svg +13 -0
  15. package/binding.gyp +19 -0
  16. package/codecov.yml +5 -0
  17. package/examples/advertisement-discovery.js +65 -0
  18. package/examples/cache-gatt-discovery.js +198 -0
  19. package/examples/cache-gatt-reconnect.js +164 -0
  20. package/examples/echo.js +104 -0
  21. package/examples/enter-exit.js +78 -0
  22. package/examples/peripheral-explorer-async.js +133 -0
  23. package/examples/peripheral-explorer.js +225 -0
  24. package/examples/pizza/README.md +15 -0
  25. package/examples/pizza/central.js +194 -0
  26. package/examples/pizza/pizza.js +60 -0
  27. package/index.d.ts +203 -0
  28. package/index.js +6 -0
  29. package/lib/characteristic.js +161 -0
  30. package/lib/characteristics.json +449 -0
  31. package/lib/descriptor.js +72 -0
  32. package/lib/descriptors.json +47 -0
  33. package/lib/distributed/bindings.js +326 -0
  34. package/lib/hci-socket/acl-stream.js +60 -0
  35. package/lib/hci-socket/bindings.js +788 -0
  36. package/lib/hci-socket/crypto.js +74 -0
  37. package/lib/hci-socket/gap.js +432 -0
  38. package/lib/hci-socket/gatt.js +809 -0
  39. package/lib/hci-socket/hci-status.json +71 -0
  40. package/lib/hci-socket/hci.js +1264 -0
  41. package/lib/hci-socket/signaling.js +76 -0
  42. package/lib/hci-socket/smp.js +140 -0
  43. package/lib/hci-uart/bindings.js +569 -0
  44. package/lib/hci-uart/hci-serial-parser.js +70 -0
  45. package/lib/hci-uart/hci.js +1336 -0
  46. package/lib/mac/binding.gyp +26 -0
  47. package/lib/mac/bindings.js +11 -0
  48. package/lib/mac/src/ble_manager.h +41 -0
  49. package/lib/mac/src/ble_manager.mm +435 -0
  50. package/lib/mac/src/callbacks.cc +222 -0
  51. package/lib/mac/src/callbacks.h +84 -0
  52. package/lib/mac/src/napi_objc.h +12 -0
  53. package/lib/mac/src/napi_objc.mm +50 -0
  54. package/lib/mac/src/noble_mac.h +34 -0
  55. package/lib/mac/src/noble_mac.mm +264 -0
  56. package/lib/mac/src/objc_cpp.h +26 -0
  57. package/lib/mac/src/objc_cpp.mm +126 -0
  58. package/lib/mac/src/peripheral.h +23 -0
  59. package/lib/manufacture.js +48 -0
  60. package/lib/noble.js +593 -0
  61. package/lib/peripheral.js +219 -0
  62. package/lib/resolve-bindings-web.js +9 -0
  63. package/lib/resolve-bindings.js +44 -0
  64. package/lib/service.js +72 -0
  65. package/lib/services.json +92 -0
  66. package/lib/webbluetooth/bindings.js +368 -0
  67. package/lib/websocket/bindings.js +321 -0
  68. package/lib/win/binding.gyp +23 -0
  69. package/lib/win/bindings.js +11 -0
  70. package/lib/win/src/ble_manager.cc +802 -0
  71. package/lib/win/src/ble_manager.h +77 -0
  72. package/lib/win/src/callbacks.cc +274 -0
  73. package/lib/win/src/callbacks.h +33 -0
  74. package/lib/win/src/napi_winrt.cc +76 -0
  75. package/lib/win/src/napi_winrt.h +12 -0
  76. package/lib/win/src/noble_winrt.cc +308 -0
  77. package/lib/win/src/noble_winrt.h +34 -0
  78. package/lib/win/src/notify_map.cc +62 -0
  79. package/lib/win/src/notify_map.h +50 -0
  80. package/lib/win/src/peripheral.h +23 -0
  81. package/lib/win/src/peripheral_winrt.cc +296 -0
  82. package/lib/win/src/peripheral_winrt.h +82 -0
  83. package/lib/win/src/radio_watcher.cc +125 -0
  84. package/lib/win/src/radio_watcher.h +61 -0
  85. package/lib/win/src/winrt_cpp.cc +82 -0
  86. package/lib/win/src/winrt_cpp.h +11 -0
  87. package/lib/win/src/winrt_guid.cc +12 -0
  88. package/lib/win/src/winrt_guid.h +13 -0
  89. package/misc/nrf52840dk.hex +6921 -0
  90. package/misc/prj.conf +43 -0
  91. package/package.json +96 -0
  92. package/test/lib/characteristic.test.js +791 -0
  93. package/test/lib/descriptor.test.js +249 -0
  94. package/test/lib/distributed/bindings.test.js +918 -0
  95. package/test/lib/hci-socket/acl-stream.test.js +188 -0
  96. package/test/lib/hci-socket/bindings.test.js +1756 -0
  97. package/test/lib/hci-socket/crypto.test.js +55 -0
  98. package/test/lib/hci-socket/gap.test.js +1089 -0
  99. package/test/lib/hci-socket/gatt.test.js +2392 -0
  100. package/test/lib/hci-socket/hci.test.js +1891 -0
  101. package/test/lib/hci-socket/signaling.test.js +94 -0
  102. package/test/lib/hci-socket/smp.test.js +268 -0
  103. package/test/lib/manufacture.test.js +77 -0
  104. package/test/lib/peripheral.test.js +623 -0
  105. package/test/lib/resolve-bindings.test.js +102 -0
  106. package/test/lib/service.test.js +195 -0
  107. package/test/lib/webbluetooth/bindings.test.js +190 -0
  108. package/test/lib/websocket/bindings.test.js +456 -0
  109. package/test/noble.test.js +1565 -0
  110. package/test.js +131 -0
  111. package/with-bindings.js +5 -0
  112. package/ws-slave.js +404 -0
@@ -0,0 +1,1756 @@
1
+ const proxyquire = require('proxyquire').noCallThru();
2
+ const should = require('should');
3
+ const sinon = require('sinon');
4
+ const { assert, fake } = sinon;
5
+
6
+ describe('hci-socket bindings', () => {
7
+ const AclStream = sinon.stub();
8
+ const Gap = sinon.stub();
9
+
10
+ const gattOnSpy = sinon.spy();
11
+ const gattExchangeMtuSpy = sinon.spy();
12
+ const Gatt = sinon.stub();
13
+ Gatt.prototype.on = gattOnSpy;
14
+ Gatt.prototype.exchangeMtu = gattExchangeMtuSpy;
15
+
16
+ const createLeConnSpy = sinon.spy();
17
+ const Hci = sinon.stub();
18
+ Hci.prototype.createLeConn = createLeConnSpy;
19
+ Hci.STATUS_MAPPER = { 1: 'custom mapper' };
20
+
21
+ const signalingOnSpy = sinon.spy();
22
+
23
+ const Signaling = sinon.stub();
24
+ Signaling.prototype.on = signalingOnSpy;
25
+
26
+ const Bindings = proxyquire('../../../lib/hci-socket/bindings', {
27
+ './acl-stream': AclStream,
28
+ './gap': Gap,
29
+ './gatt': Gatt,
30
+ './hci': Hci,
31
+ './signaling': Signaling
32
+ });
33
+
34
+ let bindings;
35
+ let clock;
36
+ const options = {};
37
+
38
+ beforeEach(() => {
39
+ sinon.stub(process, 'on');
40
+ sinon.stub(process, 'exit');
41
+
42
+ bindings = new Bindings(options);
43
+ clock = sinon.useFakeTimers();
44
+ });
45
+
46
+ afterEach(() => {
47
+ process.on.restore();
48
+ process.exit.restore();
49
+ clock.restore();
50
+ sinon.reset();
51
+ });
52
+
53
+ it('constructor', () => {
54
+ should(bindings._state).eql(null);
55
+
56
+ should(bindings._addresses).deepEqual({});
57
+ should(bindings._addresseTypes).deepEqual({});
58
+ should(bindings._connectable).deepEqual({});
59
+
60
+ should(bindings._pendingConnectionUuid).eql(null);
61
+ should(bindings._connectionQueue).deepEqual([]);
62
+
63
+ should(bindings._handles).deepEqual({});
64
+ should(bindings._gatts).deepEqual({});
65
+ should(bindings._aclStreams).deepEqual({});
66
+ should(bindings._signalings).deepEqual({});
67
+
68
+ should(bindings._hci).instanceOf(Hci);
69
+ should(bindings._gap).instanceOf(Gap);
70
+
71
+ assert.calledOnce(Hci);
72
+ assert.calledWith(Hci, options);
73
+
74
+ assert.calledOnce(Gap);
75
+ assert.calledWith(Gap, bindings._hci);
76
+ });
77
+
78
+ describe('onSigInt', () => {
79
+ it('should exit', () => {
80
+ const sigIntListeners = process.listeners('SIGINT');
81
+ bindings.onSigIntBinded = sigIntListeners[sigIntListeners.length - 1];
82
+ bindings.onSigInt();
83
+ assert.calledOnceWithExactly(process.exit, 1);
84
+ });
85
+
86
+ it('should not exit', () => {
87
+ bindings.onSigIntBinded = sinon.spy();
88
+ bindings.onSigInt();
89
+ assert.notCalled(process.exit);
90
+ });
91
+ });
92
+
93
+ it('setScanParameters', () => {
94
+ bindings._gap.setScanParameters = fake.resolves(null);
95
+
96
+ bindings.setScanParameters('interval', 'window');
97
+
98
+ assert.calledOnce(bindings._gap.setScanParameters);
99
+ assert.calledWith(bindings._gap.setScanParameters, 'interval', 'window');
100
+ });
101
+
102
+ describe('startScanning', () => {
103
+ it('no args', () => {
104
+ bindings._gap.startScanning = fake.resolves(null);
105
+
106
+ bindings.startScanning();
107
+
108
+ should(bindings._scanServiceUuids).deepEqual([]);
109
+
110
+ assert.calledOnce(bindings._gap.startScanning);
111
+ assert.calledWith(bindings._gap.startScanning, undefined);
112
+ });
113
+
114
+ it('with args', () => {
115
+ bindings._gap.startScanning = fake.resolves(null);
116
+
117
+ bindings.startScanning(['uuid'], true);
118
+
119
+ should(bindings._scanServiceUuids).deepEqual(['uuid']);
120
+
121
+ assert.calledOnce(bindings._gap.startScanning);
122
+ assert.calledWith(bindings._gap.startScanning, true);
123
+ });
124
+ });
125
+
126
+ it('stopScanning', () => {
127
+ bindings._gap.stopScanning = fake.resolves(null);
128
+
129
+ bindings.stopScanning();
130
+
131
+ assert.calledOnce(bindings._gap.stopScanning);
132
+ });
133
+
134
+ describe('connect', () => {
135
+ it('missing peripheral, no queue', () => {
136
+ bindings._hci.createLeConn = fake.resolves(null);
137
+
138
+ bindings.connect('peripheralUuid', 'parameters');
139
+
140
+ should(bindings._pendingConnectionUuid).eql('peripheralUuid');
141
+
142
+ assert.calledOnce(bindings._hci.createLeConn);
143
+ assert.calledWith(bindings._hci.createLeConn, undefined, undefined, 'parameters');
144
+ });
145
+
146
+ it('existing peripheral, no queue', () => {
147
+ bindings._hci.createLeConn = fake.resolves(null);
148
+ bindings._addresses = {
149
+ peripheralUuid: 'address'
150
+ };
151
+ bindings._addresseTypes = {
152
+ peripheralUuid: 'addressType'
153
+ };
154
+
155
+ bindings.connect('peripheralUuid', 'parameters');
156
+
157
+ should(bindings._pendingConnectionUuid).eql('peripheralUuid');
158
+
159
+ assert.calledOnce(bindings._hci.createLeConn);
160
+ assert.calledWith(bindings._hci.createLeConn, 'address', 'addressType', 'parameters');
161
+ });
162
+
163
+ it('missing peripheral, with queue', () => {
164
+ bindings._pendingConnectionUuid = 'pending-uuid';
165
+
166
+ bindings.connect('peripheralUuid', 'parameters');
167
+
168
+ should(bindings._connectionQueue).deepEqual([{ id: 'peripheralUuid', params: 'parameters' }]);
169
+ });
170
+ });
171
+
172
+ describe('disconnect', () => {
173
+ it('missing handle', () => {
174
+ bindings._hci.disconnect = fake.resolves(null);
175
+
176
+ bindings.disconnect('peripheralUuid');
177
+
178
+ assert.calledOnce(bindings._hci.disconnect);
179
+ assert.calledWith(bindings._hci.disconnect, undefined);
180
+ });
181
+
182
+ it('existing handle', () => {
183
+ bindings._handles = {
184
+ peripheralUuid: 'handle'
185
+ };
186
+ bindings._hci.disconnect = fake.resolves(null);
187
+
188
+ bindings.disconnect('peripheralUuid');
189
+
190
+ assert.calledOnce(bindings._hci.disconnect);
191
+ assert.calledWith(bindings._hci.disconnect, 'handle');
192
+ });
193
+ });
194
+
195
+ describe('cancel', () => {
196
+ it('missing handle', () => {
197
+ bindings._connectionQueue.push({ id: 'anotherPeripheralUuid' });
198
+
199
+ bindings._hci.cancelConnect = fake.resolves(null);
200
+
201
+ bindings.cancelConnect('peripheralUuid');
202
+
203
+ should(bindings._connectionQueue).size(1);
204
+
205
+ assert.calledOnce(bindings._hci.cancelConnect);
206
+ assert.calledWith(bindings._hci.cancelConnect, undefined);
207
+ });
208
+
209
+ it('existing handle', () => {
210
+ bindings._handles = {
211
+ peripheralUuid: 'handle'
212
+ };
213
+ bindings._connectionQueue.push({ id: 'anotherPeripheralUuid' });
214
+ bindings._connectionQueue.push({ id: 'peripheralUuid' });
215
+ bindings._hci.cancelConnect = fake.resolves(null);
216
+
217
+ bindings.cancelConnect('peripheralUuid');
218
+
219
+ should(bindings._connectionQueue).size(1);
220
+
221
+ assert.calledOnce(bindings._hci.cancelConnect);
222
+ assert.calledWith(bindings._hci.cancelConnect, 'handle');
223
+ });
224
+ });
225
+
226
+ it('reset', () => {
227
+ bindings._hci.reset = fake.resolves(null);
228
+
229
+ bindings.reset();
230
+
231
+ assert.calledOnce(bindings._hci.reset);
232
+ });
233
+
234
+ describe('updateRssi', () => {
235
+ it('missing handle', () => {
236
+ bindings._hci.readRssi = fake.resolves(null);
237
+
238
+ bindings.updateRssi('peripheralUuid');
239
+
240
+ assert.calledOnce(bindings._hci.readRssi);
241
+ assert.calledWith(bindings._hci.readRssi, undefined);
242
+ });
243
+
244
+ it('existing handle', () => {
245
+ bindings._handles = {
246
+ peripheralUuid: 'handle'
247
+ };
248
+ bindings._hci.readRssi = fake.resolves(null);
249
+
250
+ bindings.updateRssi('peripheralUuid');
251
+
252
+ assert.calledOnce(bindings._hci.readRssi);
253
+ assert.calledWith(bindings._hci.readRssi, 'handle');
254
+ });
255
+ });
256
+
257
+ it('init', () => {
258
+ bindings._gap.on = fake.resolves(null);
259
+ bindings._hci.on = fake.resolves(null);
260
+ bindings._hci.init = fake.resolves(null);
261
+
262
+ bindings.init();
263
+
264
+ assert.callCount(bindings._gap.on, 4);
265
+ assert.callCount(bindings._hci.on, 8);
266
+ assert.calledOnce(bindings._hci.init);
267
+
268
+ assert.calledTwice(process.on);
269
+ });
270
+
271
+ describe('onExit', () => {
272
+ it('no handles', () => {
273
+ bindings._gap.stopScanning = fake.resolves(null);
274
+
275
+ bindings.onExit();
276
+
277
+ assert.calledOnce(bindings._gap.stopScanning);
278
+ });
279
+
280
+ it('with handles', () => {
281
+ bindings._gap.stopScanning = fake.resolves(null);
282
+ bindings._hci.disconnect = fake.resolves(null);
283
+
284
+ bindings._aclStreams = [1, 2, 3];
285
+
286
+ bindings.onExit();
287
+
288
+ assert.calledOnce(bindings._gap.stopScanning);
289
+ assert.calledThrice(bindings._hci.disconnect);
290
+ });
291
+ });
292
+
293
+ describe('onStateChange', () => {
294
+ it('same state', () => {
295
+ const stateChange = fake.resolves(null);
296
+
297
+ bindings._state = 'state';
298
+ bindings.on('stateChange', stateChange);
299
+
300
+ bindings.onStateChange('state');
301
+
302
+ assert.notCalled(stateChange);
303
+ });
304
+
305
+ it('new state', () => {
306
+ const stateChange = fake.resolves(null);
307
+
308
+ bindings._state = 'state';
309
+ bindings.on('stateChange', stateChange);
310
+
311
+ bindings.onStateChange('newState');
312
+
313
+ assert.calledOnce(stateChange);
314
+ assert.calledWith(stateChange, 'newState');
315
+ });
316
+
317
+ it('unauthorized', () => {
318
+ const stateChange = fake.resolves(null);
319
+
320
+ bindings._state = 'state';
321
+ bindings.on('stateChange', stateChange);
322
+
323
+ bindings.onStateChange('unauthorized');
324
+
325
+ assert.calledOnce(stateChange);
326
+ assert.calledWith(stateChange, 'unauthorized');
327
+ });
328
+
329
+ it('unsupported', () => {
330
+ const stateChange = fake.resolves(null);
331
+
332
+ bindings._state = 'state';
333
+ bindings.on('stateChange', stateChange);
334
+
335
+ bindings.onStateChange('unsupported');
336
+
337
+ assert.calledOnce(stateChange);
338
+ assert.calledWith(stateChange, 'unsupported');
339
+ });
340
+ });
341
+
342
+ it('onAddressChange', () => {
343
+ const onAddressChange = fake.resolves(null);
344
+
345
+ bindings.on('addressChange', onAddressChange);
346
+
347
+ bindings.onAddressChange('newAddress');
348
+
349
+ assert.calledOnce(onAddressChange);
350
+ assert.calledWith(onAddressChange, 'newAddress');
351
+ });
352
+
353
+ it('onScanParametersSet', () => {
354
+ const onScanParametersSet = fake.resolves(null);
355
+
356
+ bindings.on('scanParametersSet', onScanParametersSet);
357
+
358
+ bindings.onScanParametersSet();
359
+
360
+ assert.calledOnce(onScanParametersSet);
361
+ });
362
+
363
+ it('onScanStart', () => {
364
+ const onScanStart = fake.resolves(null);
365
+
366
+ bindings.on('scanStart', onScanStart);
367
+
368
+ bindings.onScanStart('filterDuplicates');
369
+
370
+ assert.calledOnce(onScanStart);
371
+ assert.calledWith(onScanStart, 'filterDuplicates');
372
+ });
373
+
374
+ it('onScanStop', () => {
375
+ const onScanStop = fake.resolves(null);
376
+
377
+ bindings.on('scanStop', onScanStop);
378
+
379
+ bindings.onScanStop();
380
+
381
+ assert.calledOnce(onScanStop);
382
+ });
383
+
384
+ describe('onDiscover', () => {
385
+ it('new device, no scanServiceUuids', () => {
386
+ const onDiscover = fake.resolves(null);
387
+
388
+ bindings.on('discover', onDiscover);
389
+
390
+ bindings._scanServiceUuids = [];
391
+
392
+ const status = 'status';
393
+ const address = 'address:as:mac';
394
+ const addressType = 'addressType';
395
+ const connectable = 'connectable';
396
+ const advertisement = 'advertisement';
397
+ const rssi = 'rssi';
398
+ bindings.onDiscover(status, address, addressType, connectable, advertisement, rssi);
399
+
400
+ const uuid = 'addressasmac';
401
+ should(bindings._addresses).deepEqual({ [uuid]: address });
402
+ should(bindings._addresseTypes).deepEqual({ [uuid]: addressType });
403
+ should(bindings._connectable).deepEqual({ [uuid]: connectable });
404
+
405
+ assert.calledOnce(onDiscover);
406
+ assert.calledWith(onDiscover, uuid, address, addressType, connectable, advertisement, rssi);
407
+ });
408
+
409
+ it('new device, with matching scanServiceUuids', () => {
410
+ const onDiscover = fake.resolves(null);
411
+
412
+ bindings.on('discover', onDiscover);
413
+
414
+ bindings._scanServiceUuids = ['service-uuid'];
415
+
416
+ const status = 'status';
417
+ const address = 'address:as:mac';
418
+ const addressType = 'addressType';
419
+ const connectable = 'connectable';
420
+ const advertisement = {
421
+ serviceUuids: ['service-uuid']
422
+ };
423
+ const rssi = 'rssi';
424
+ bindings.onDiscover(status, address, addressType, connectable, advertisement, rssi);
425
+
426
+ const uuid = 'addressasmac';
427
+ should(bindings._addresses).deepEqual({ [uuid]: address });
428
+ should(bindings._addresseTypes).deepEqual({ [uuid]: addressType });
429
+ should(bindings._connectable).deepEqual({ [uuid]: connectable });
430
+
431
+ assert.calledOnce(onDiscover);
432
+ assert.calledWith(onDiscover, uuid, address, addressType, connectable, advertisement, rssi);
433
+ });
434
+
435
+ it('new device, with non-matching scanServiceUuids', () => {
436
+ const onDiscover = fake.resolves(null);
437
+
438
+ bindings.on('discover', onDiscover);
439
+
440
+ bindings._scanServiceUuids = ['service-uuid'];
441
+
442
+ const status = 'status';
443
+ const address = 'address:as:mac';
444
+ const addressType = 'addressType';
445
+ const connectable = 'connectable';
446
+ const advertisement = {
447
+ serviceUuids: ['another-service-uuid']
448
+ };
449
+ const rssi = 'rssi';
450
+ bindings.onDiscover(status, address, addressType, connectable, advertisement, rssi);
451
+
452
+ should(bindings._addresses).deepEqual({});
453
+ should(bindings._addresseTypes).deepEqual({});
454
+ should(bindings._connectable).deepEqual({});
455
+
456
+ assert.notCalled(onDiscover);
457
+ });
458
+
459
+ it('new device, with service data on advertisement', () => {
460
+ const onDiscover = fake.resolves(null);
461
+
462
+ bindings.on('discover', onDiscover);
463
+
464
+ bindings._scanServiceUuids = ['service-uuid'];
465
+
466
+ const status = 'status';
467
+ const address = 'address:as:mac';
468
+ const addressType = 'addressType';
469
+ const connectable = 'connectable';
470
+ const advertisement = {
471
+ serviceData: [{ uuid: 'service-uuid' }]
472
+ };
473
+ const rssi = 'rssi';
474
+ bindings.onDiscover(status, address, addressType, connectable, advertisement, rssi);
475
+
476
+ const uuid = 'addressasmac';
477
+ should(bindings._addresses).deepEqual({ [uuid]: address });
478
+ should(bindings._addresseTypes).deepEqual({ [uuid]: addressType });
479
+ should(bindings._connectable).deepEqual({ [uuid]: connectable });
480
+
481
+ assert.calledOnce(onDiscover);
482
+ assert.calledWith(onDiscover, uuid, address, addressType, connectable, advertisement, rssi);
483
+ });
484
+
485
+ it('new device, non matching service data on advertisement', () => {
486
+ const onDiscover = fake.resolves(null);
487
+
488
+ bindings.on('discover', onDiscover);
489
+
490
+ bindings._scanServiceUuids = ['service-uuid'];
491
+
492
+ const status = 'status';
493
+ const address = 'address:as:mac';
494
+ const addressType = 'addressType';
495
+ const connectable = 'connectable';
496
+ const advertisement = {
497
+ serviceData: [{ uuid: 'another-service-uuid' }]
498
+ };
499
+ const rssi = 'rssi';
500
+ bindings.onDiscover(status, address, addressType, connectable, advertisement, rssi);
501
+
502
+ should(bindings._addresses).deepEqual({});
503
+ should(bindings._addresseTypes).deepEqual({});
504
+ should(bindings._connectable).deepEqual({});
505
+
506
+ assert.notCalled(onDiscover);
507
+ });
508
+
509
+ it('new device, no services on advertisement', () => {
510
+ const onDiscover = fake.resolves(null);
511
+
512
+ bindings.on('discover', onDiscover);
513
+
514
+ bindings._scanServiceUuids = ['service-uuid'];
515
+
516
+ const status = 'status';
517
+ const address = 'address:as:mac';
518
+ const addressType = 'addressType';
519
+ const connectable = 'connectable';
520
+ const advertisement = {};
521
+ const rssi = 'rssi';
522
+ bindings.onDiscover(status, address, addressType, connectable, advertisement, rssi);
523
+
524
+ should(bindings._addresses).deepEqual({});
525
+ should(bindings._addresseTypes).deepEqual({});
526
+ should(bindings._connectable).deepEqual({});
527
+
528
+ assert.notCalled(onDiscover);
529
+ });
530
+
531
+ it('new device, undefined _scanServiceUuids', () => {
532
+ const onDiscover = fake.resolves(null);
533
+
534
+ bindings.on('discover', onDiscover);
535
+
536
+ bindings._scanServiceUuids = undefined;
537
+
538
+ const status = 'status';
539
+ const address = 'address:as:mac';
540
+ const addressType = 'addressType';
541
+ const connectable = 'connectable';
542
+ const advertisement = {
543
+ serviceData: [{ uuid: 'service-uuid' }]
544
+ };
545
+ const rssi = 'rssi';
546
+ bindings.onDiscover(status, address, addressType, connectable, advertisement, rssi);
547
+
548
+ should(bindings._addresses).deepEqual({});
549
+ should(bindings._addresseTypes).deepEqual({});
550
+ should(bindings._connectable).deepEqual({});
551
+
552
+ assert.notCalled(onDiscover);
553
+ });
554
+ });
555
+
556
+ describe('onLeConnComplete', () => {
557
+ it('not on master node', () => {
558
+ const status = 1;
559
+ const handle = 'handle';
560
+ const role = 'not-master';
561
+ const addressType = 'addressType';
562
+ const address = 'address';
563
+
564
+ const connectCallback = sinon.spy();
565
+
566
+ bindings.on('connect', connectCallback);
567
+ bindings.onLeConnComplete(status, handle, role, addressType, address);
568
+
569
+ assert.notCalled(connectCallback);
570
+ });
571
+
572
+ it('with right status on master node', () => {
573
+ const status = 0;
574
+ const handle = 'handle';
575
+ const role = 0;
576
+ const addressType = 'addressType';
577
+ const address = 'address:split:by:separator';
578
+
579
+ const connectCallback = sinon.spy();
580
+
581
+ bindings.on('connect', connectCallback);
582
+ bindings.onLeConnComplete(status, handle, role, addressType, address);
583
+
584
+ clock.tick(0);
585
+
586
+ assert.calledOnce(AclStream);
587
+ assert.calledOnce(Gatt);
588
+ assert.calledOnce(Signaling);
589
+
590
+ assert.callCount(gattOnSpy, 17);
591
+ assert.calledWithMatch(gattOnSpy, 'mtu', sinon.match.func);
592
+ assert.calledWithMatch(gattOnSpy, 'servicesDiscover', sinon.match.func);
593
+ assert.calledWithMatch(gattOnSpy, 'servicesDiscovered', sinon.match.func);
594
+ assert.calledWithMatch(gattOnSpy, 'includedServicesDiscover', sinon.match.func);
595
+ assert.calledWithMatch(gattOnSpy, 'characteristicsDiscover', sinon.match.func);
596
+ assert.calledWithMatch(gattOnSpy, 'characteristicsDiscovered', sinon.match.func);
597
+ assert.calledWithMatch(gattOnSpy, 'read', sinon.match.func);
598
+ assert.calledWithMatch(gattOnSpy, 'write', sinon.match.func);
599
+ assert.calledWithMatch(gattOnSpy, 'broadcast', sinon.match.func);
600
+ assert.calledWithMatch(gattOnSpy, 'notify', sinon.match.func);
601
+ assert.calledWithMatch(gattOnSpy, 'notification', sinon.match.func);
602
+ assert.calledWithMatch(gattOnSpy, 'descriptorsDiscover', sinon.match.func);
603
+ assert.calledWithMatch(gattOnSpy, 'valueRead', sinon.match.func);
604
+ assert.calledWithMatch(gattOnSpy, 'valueWrite', sinon.match.func);
605
+ assert.calledWithMatch(gattOnSpy, 'handleRead', sinon.match.func);
606
+ assert.calledWithMatch(gattOnSpy, 'handleWrite', sinon.match.func);
607
+ assert.calledWithMatch(gattOnSpy, 'handleNotify', sinon.match.func);
608
+
609
+ assert.calledOnceWithMatch(signalingOnSpy, 'connectionParameterUpdateRequest', sinon.match.func);
610
+
611
+ assert.calledOnceWithExactly(gattExchangeMtuSpy);
612
+
613
+ assert.calledOnceWithExactly(connectCallback, 'addresssplitbyseparator', null);
614
+
615
+ should(bindings._pendingConnectionUuid).equal(null);
616
+ });
617
+
618
+ it('with invalid status on master node', () => {
619
+ const status = 1;
620
+ const handle = 'handle';
621
+ const role = 0;
622
+ const addressType = 'addressType';
623
+ const address = 'address:split:by:separator';
624
+
625
+ const connectCallback = sinon.spy();
626
+
627
+ bindings._pendingConnectionUuid = 'pending_uuid';
628
+ bindings.on('connect', connectCallback);
629
+ bindings.onLeConnComplete(status, handle, role, addressType, address);
630
+
631
+ assert.notCalled(AclStream);
632
+ assert.notCalled(Gatt);
633
+ assert.notCalled(Signaling);
634
+
635
+ assert.calledOnceWithMatch(connectCallback, 'pending_uuid', sinon.match({ message: 'custom mapper (0x1)' }));
636
+
637
+ should(bindings._pendingConnectionUuid).equal(null);
638
+ });
639
+
640
+ it('with unmapped status on master node', () => {
641
+ const status = 2;
642
+ const handle = 'handle';
643
+ const role = 0;
644
+ const addressType = 'addressType';
645
+ const address = 'address:split:by:separator';
646
+
647
+ const connectCallback = sinon.spy();
648
+
649
+ bindings._pendingConnectionUuid = 'pending_uuid';
650
+ bindings.on('connect', connectCallback);
651
+ bindings.onLeConnComplete(status, handle, role, addressType, address);
652
+
653
+ assert.notCalled(AclStream);
654
+ assert.notCalled(Gatt);
655
+ assert.notCalled(Signaling);
656
+
657
+ assert.calledOnceWithExactly(connectCallback, 'pending_uuid', sinon.match({ message: 'HCI Error: Unknown (0x2)' }));
658
+
659
+ should(bindings._pendingConnectionUuid).equal(null);
660
+ });
661
+
662
+ it('with connection queue', () => {
663
+ const status = 0;
664
+ const handle = 'handle';
665
+ const role = 0;
666
+ const addressType = 'addressType';
667
+ const address = 'address:split:by:separator';
668
+
669
+ const connectCallback = sinon.spy();
670
+
671
+ bindings._connectionQueue = [{ id: 'queuedId', params: { p1: 'p1' } }];
672
+ bindings._addresses = { queuedId: 'queuedAddress' };
673
+ bindings._addresseTypes = { queuedId: 'queuedAddressType' };
674
+ bindings.on('connect', connectCallback);
675
+ bindings.onLeConnComplete(status, handle, role, addressType, address);
676
+
677
+ assert.calledOnceWithExactly(connectCallback, 'addresssplitbyseparator', null);
678
+
679
+ assert.calledOnceWithExactly(createLeConnSpy, 'queuedAddress', 'queuedAddressType', { p1: 'p1' });
680
+
681
+ should(bindings._pendingConnectionUuid).equal('queuedId');
682
+ });
683
+ });
684
+
685
+ describe('onDisconnComplete', () => {
686
+ it('handle not found', () => {
687
+ const disconnectCallback = sinon.spy();
688
+
689
+ bindings.on('disconnect', disconnectCallback);
690
+ bindings.onDisconnComplete('missing', 'reason');
691
+
692
+ assert.notCalled(disconnectCallback);
693
+ });
694
+
695
+ it('existing handle', () => {
696
+ const disconnectCallback = sinon.spy();
697
+ const handle = 'handle';
698
+ const anotherHandle = 'another_handle';
699
+ const uuid = 'uuid';
700
+ const anotherUuid = 'another_uuid';
701
+ const reason = 'reason';
702
+
703
+ const gattSpy = {
704
+ removeAllListeners: sinon.spy()
705
+ };
706
+ const signalingSpy = {
707
+ removeAllListeners: sinon.spy()
708
+ };
709
+
710
+ // Init expected
711
+ bindings._handles[uuid] = uuid;
712
+ bindings._handles[handle] = uuid;
713
+ bindings._handles[anotherUuid] = uuid;
714
+ bindings._handles[anotherHandle] = anotherUuid;
715
+ bindings._aclStreams[handle] = [];
716
+ bindings._aclStreams[anotherHandle] = [];
717
+ bindings._gatts[handle] = gattSpy;
718
+ bindings._gatts[uuid] = gattSpy;
719
+ bindings._gatts[anotherHandle] = gattSpy;
720
+ bindings._gatts[anotherUuid] = gattSpy;
721
+ bindings._signalings[uuid] = signalingSpy;
722
+ bindings._signalings[handle] = signalingSpy;
723
+ bindings._signalings[anotherUuid] = signalingSpy;
724
+ bindings._signalings[anotherHandle] = signalingSpy;
725
+
726
+ bindings.on('disconnect', disconnectCallback);
727
+ bindings.onDisconnComplete(handle, reason);
728
+
729
+ assert.calledOnceWithExactly(disconnectCallback, uuid, reason);
730
+ assert.calledOnceWithExactly(gattSpy.removeAllListeners);
731
+ assert.calledOnceWithExactly(signalingSpy.removeAllListeners);
732
+
733
+ should(bindings._handles).not.have.keys(uuid, handle);
734
+ should(bindings._aclStreams).not.have.keys(handle);
735
+ should(bindings._gatts).not.have.keys(uuid, handle);
736
+ should(bindings._signalings).not.have.keys(uuid, handle);
737
+ });
738
+ });
739
+
740
+ describe('onEncryptChange', () => {
741
+ it('missing handle', () => {
742
+ const handle = 'handle';
743
+ const anotherHandle = 'another_handle';
744
+ const encrypt = 'encrypt';
745
+ const aclSpy = {
746
+ pushEncrypt: sinon.spy()
747
+ };
748
+
749
+ bindings._aclStreams[handle] = aclSpy;
750
+ bindings.onEncryptChange(anotherHandle, encrypt);
751
+
752
+ assert.notCalled(aclSpy.pushEncrypt);
753
+ });
754
+
755
+ it('existing handle', () => {
756
+ const handle = 'handle';
757
+ const encrypt = 'encrypt';
758
+ const aclSpy = {
759
+ pushEncrypt: sinon.spy()
760
+ };
761
+
762
+ bindings._aclStreams[handle] = aclSpy;
763
+ bindings.onEncryptChange(handle, encrypt);
764
+
765
+ assert.calledOnceWithExactly(aclSpy.pushEncrypt, encrypt);
766
+ });
767
+
768
+ it('existing handle no encrypt', () => {
769
+ const handle = 'handle';
770
+ const aclSpy = {
771
+ pushEncrypt: sinon.spy()
772
+ };
773
+
774
+ bindings._aclStreams[handle] = aclSpy;
775
+ bindings.onEncryptChange(handle);
776
+
777
+ assert.calledOnceWithExactly(aclSpy.pushEncrypt, undefined);
778
+ });
779
+ });
780
+
781
+ it('onMtu', () => {
782
+ const address = 'this:is:an:address';
783
+ const rssi = 'rssi';
784
+ const callback = sinon.spy();
785
+
786
+ bindings.on('onMtu', callback);
787
+ bindings.onMtu(address, rssi);
788
+
789
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', rssi);
790
+ });
791
+
792
+ it('onRssiRead', () => {
793
+ const handle = 'handle';
794
+ const rssi = 'rssi';
795
+ const callback = sinon.spy();
796
+
797
+ bindings._handles[handle] = 'binding_handle';
798
+ bindings.on('rssiUpdate', callback);
799
+ bindings.onRssiRead(handle, rssi);
800
+
801
+ assert.calledOnceWithExactly(callback, 'binding_handle', rssi);
802
+ });
803
+
804
+ describe('onAclDataPkt', () => {
805
+ it('missing handle', () => {
806
+ const handle = 'handle';
807
+ const anotherHandle = 'another_handle';
808
+ const cid = 'cid';
809
+ const data = 'data';
810
+ const aclSpy = {
811
+ push: sinon.spy()
812
+ };
813
+
814
+ bindings._aclStreams[handle] = aclSpy;
815
+ bindings.onAclDataPkt(anotherHandle, cid, data);
816
+
817
+ assert.notCalled(aclSpy.push);
818
+ });
819
+
820
+ it('existing handle', () => {
821
+ const handle = 'handle';
822
+ const cid = 'cid';
823
+ const data = 'data';
824
+ const aclSpy = {
825
+ push: sinon.spy()
826
+ };
827
+
828
+ bindings._aclStreams[handle] = aclSpy;
829
+ bindings.onAclDataPkt(handle, cid, data);
830
+
831
+ assert.calledOnceWithExactly(aclSpy.push, cid, data);
832
+ });
833
+
834
+ it('existing handle no cid no data', () => {
835
+ const handle = 'handle';
836
+ const aclSpy = {
837
+ push: sinon.spy()
838
+ };
839
+
840
+ bindings._aclStreams[handle] = aclSpy;
841
+ bindings.onAclDataPkt(handle);
842
+
843
+ assert.calledOnceWithExactly(aclSpy.push, undefined, undefined);
844
+ });
845
+ });
846
+
847
+ describe('addService', () => {
848
+ it('missing gatt', () => {
849
+ const peripheralUuid = 'uuid';
850
+ const handle = 'handle';
851
+ const anotherHandle = 'another_handle';
852
+ const service = 'service';
853
+ const gatt = {
854
+ addService: sinon.spy()
855
+ };
856
+
857
+ bindings._handles[peripheralUuid] = anotherHandle;
858
+ bindings._gatts[handle] = gatt;
859
+ bindings.addService(peripheralUuid, service);
860
+
861
+ assert.notCalled(gatt.addService);
862
+ });
863
+
864
+ it('existing gatt', () => {
865
+ const peripheralUuid = 'uuid';
866
+ const handle = 'handle';
867
+ const service = 'service';
868
+ const gatt = {
869
+ addService: sinon.spy()
870
+ };
871
+
872
+ bindings._handles[peripheralUuid] = handle;
873
+ bindings._gatts[handle] = gatt;
874
+ bindings.addService(peripheralUuid, service);
875
+
876
+ assert.calledOnceWithExactly(gatt.addService, service);
877
+ });
878
+
879
+ it('existing gatt no service', () => {
880
+ const peripheralUuid = 'uuid';
881
+ const handle = 'handle';
882
+ const gatt = {
883
+ addService: sinon.spy()
884
+ };
885
+
886
+ bindings._handles[peripheralUuid] = handle;
887
+ bindings._gatts[handle] = gatt;
888
+ bindings.addService(peripheralUuid);
889
+
890
+ assert.calledOnceWithExactly(gatt.addService, undefined);
891
+ });
892
+ });
893
+
894
+ describe('discoverServices', () => {
895
+ it('missing gatt', () => {
896
+ const peripheralUuid = 'uuid';
897
+ const handle = 'handle';
898
+ const anotherHandle = 'another_handle';
899
+ const uuids = 'uuids';
900
+ const gatt = {
901
+ discoverServices: sinon.spy()
902
+ };
903
+
904
+ bindings._handles[peripheralUuid] = anotherHandle;
905
+ bindings._gatts[handle] = gatt;
906
+ bindings.discoverServices(peripheralUuid, uuids);
907
+
908
+ assert.notCalled(gatt.discoverServices);
909
+ });
910
+
911
+ it('existing gatt', () => {
912
+ const peripheralUuid = 'uuid';
913
+ const handle = 'handle';
914
+ const uuids = 'uuids';
915
+ const gatt = {
916
+ discoverServices: sinon.spy()
917
+ };
918
+
919
+ bindings._handles[peripheralUuid] = handle;
920
+ bindings._gatts[handle] = gatt;
921
+ bindings.discoverServices(peripheralUuid, uuids);
922
+
923
+ assert.calledOnceWithExactly(gatt.discoverServices, uuids);
924
+ });
925
+
926
+ it('existing gatt no uuids', () => {
927
+ const peripheralUuid = 'uuid';
928
+ const handle = 'handle';
929
+ const gatt = {
930
+ discoverServices: sinon.spy()
931
+ };
932
+
933
+ bindings._handles[peripheralUuid] = handle;
934
+ bindings._gatts[handle] = gatt;
935
+ bindings.discoverServices(peripheralUuid);
936
+
937
+ assert.calledOnceWithExactly(gatt.discoverServices, []);
938
+ });
939
+ });
940
+
941
+ it('onServicesDiscovered', () => {
942
+ const address = 'this:is:an:address';
943
+ const serviceUuids = 'serviceUuids';
944
+ const callback = sinon.spy();
945
+
946
+ bindings.on('servicesDiscover', callback);
947
+ bindings.onServicesDiscovered(address, serviceUuids);
948
+
949
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', serviceUuids);
950
+ });
951
+
952
+ it('onServicesDiscoveredEX', () => {
953
+ const address = 'this:is:an:address';
954
+ const serviceUuids = 'serviceUuids';
955
+ const callback = sinon.spy();
956
+
957
+ bindings.on('servicesDiscovered', callback);
958
+ bindings.onServicesDiscoveredEX(address, serviceUuids);
959
+
960
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', serviceUuids);
961
+ });
962
+
963
+ describe('discoverIncludedServices', () => {
964
+ it('missing gatt', () => {
965
+ const peripheralUuid = 'uuid';
966
+ const handle = 'handle';
967
+ const anotherHandle = 'another_handle';
968
+ const serviceUuid = 'service-uuid';
969
+ const serviceUuids = 'serviceUuids';
970
+ const gatt = {
971
+ discoverIncludedServices: sinon.spy()
972
+ };
973
+
974
+ bindings._handles[peripheralUuid] = anotherHandle;
975
+ bindings._gatts[handle] = gatt;
976
+ bindings.discoverIncludedServices(peripheralUuid, serviceUuid, serviceUuids);
977
+
978
+ assert.notCalled(gatt.discoverIncludedServices);
979
+ });
980
+
981
+ it('existing gatt', () => {
982
+ const peripheralUuid = 'uuid';
983
+ const handle = 'handle';
984
+ const serviceUuid = 'service-uuid';
985
+ const serviceUuids = 'serviceUuids';
986
+ const gatt = {
987
+ discoverIncludedServices: sinon.spy()
988
+ };
989
+
990
+ bindings._handles[peripheralUuid] = handle;
991
+ bindings._gatts[handle] = gatt;
992
+ bindings.discoverIncludedServices(peripheralUuid, serviceUuid, serviceUuids);
993
+
994
+ assert.calledOnceWithExactly(gatt.discoverIncludedServices, serviceUuid, serviceUuids);
995
+ });
996
+
997
+ it('existing gatt no uuids', () => {
998
+ const peripheralUuid = 'uuid';
999
+ const handle = 'handle';
1000
+ const serviceUuid = 'service-uuid';
1001
+ const gatt = {
1002
+ discoverIncludedServices: sinon.spy()
1003
+ };
1004
+
1005
+ bindings._handles[peripheralUuid] = handle;
1006
+ bindings._gatts[handle] = gatt;
1007
+ bindings.discoverIncludedServices(peripheralUuid, serviceUuid);
1008
+
1009
+ assert.calledOnceWithExactly(gatt.discoverIncludedServices, serviceUuid, []);
1010
+ });
1011
+ });
1012
+
1013
+ it('onIncludedServicesDiscovered', () => {
1014
+ const address = 'this:is:an:address';
1015
+ const serviceUuid = 'serviceUuid';
1016
+ const includedServiceUuids = 'includedServiceUuids';
1017
+ const callback = sinon.spy();
1018
+
1019
+ bindings.on('includedServicesDiscover', callback);
1020
+ bindings.onIncludedServicesDiscovered(address, serviceUuid, includedServiceUuids);
1021
+
1022
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', serviceUuid, includedServiceUuids);
1023
+ });
1024
+
1025
+ describe('addCharacteristics', () => {
1026
+ it('missing gatt', () => {
1027
+ const peripheralUuid = 'uuid';
1028
+ const handle = 'handle';
1029
+ const anotherHandle = 'another_handle';
1030
+ const serviceUuid = 'serviceUuid';
1031
+ const characteristics = 'characteristics';
1032
+ const gatt = {
1033
+ addCharacteristics: sinon.spy()
1034
+ };
1035
+
1036
+ bindings._handles[peripheralUuid] = anotherHandle;
1037
+ bindings._gatts[handle] = gatt;
1038
+ bindings.addCharacteristics(peripheralUuid, serviceUuid, characteristics);
1039
+
1040
+ assert.notCalled(gatt.addCharacteristics);
1041
+ });
1042
+
1043
+ it('existing gatt', () => {
1044
+ const peripheralUuid = 'uuid';
1045
+ const handle = 'handle';
1046
+ const serviceUuid = 'serviceUuid';
1047
+ const characteristics = 'characteristics';
1048
+ const gatt = {
1049
+ addCharacteristics: sinon.spy()
1050
+ };
1051
+
1052
+ bindings._handles[peripheralUuid] = handle;
1053
+ bindings._gatts[handle] = gatt;
1054
+ bindings.addCharacteristics(peripheralUuid, serviceUuid, characteristics);
1055
+
1056
+ assert.calledOnceWithExactly(gatt.addCharacteristics, serviceUuid, characteristics);
1057
+ });
1058
+
1059
+ it('existing gatt no serviceUuid no characteristics', () => {
1060
+ const peripheralUuid = 'uuid';
1061
+ const handle = 'handle';
1062
+ const gatt = {
1063
+ addCharacteristics: sinon.spy()
1064
+ };
1065
+
1066
+ bindings._handles[peripheralUuid] = handle;
1067
+ bindings._gatts[handle] = gatt;
1068
+ bindings.addCharacteristics(peripheralUuid);
1069
+
1070
+ assert.calledOnceWithExactly(gatt.addCharacteristics, undefined, undefined);
1071
+ });
1072
+ });
1073
+
1074
+ describe('discoverCharacteristics', () => {
1075
+ it('missing gatt', () => {
1076
+ const peripheralUuid = 'uuid';
1077
+ const handle = 'handle';
1078
+ const anotherHandle = 'another_handle';
1079
+ const serviceUuid = 'serviceUuid';
1080
+ const characteristicUuids = 'characteristics';
1081
+ const gatt = {
1082
+ discoverCharacteristics: sinon.spy()
1083
+ };
1084
+
1085
+ bindings._handles[peripheralUuid] = anotherHandle;
1086
+ bindings._gatts[handle] = gatt;
1087
+ bindings.discoverCharacteristics(peripheralUuid, serviceUuid, characteristicUuids);
1088
+
1089
+ assert.notCalled(gatt.discoverCharacteristics);
1090
+ });
1091
+
1092
+ it('existing gatt', () => {
1093
+ const peripheralUuid = 'uuid';
1094
+ const handle = 'handle';
1095
+ const serviceUuid = 'serviceUuid';
1096
+ const characteristicUuids = 'characteristics';
1097
+ const gatt = {
1098
+ discoverCharacteristics: sinon.spy()
1099
+ };
1100
+
1101
+ bindings._handles[peripheralUuid] = handle;
1102
+ bindings._gatts[handle] = gatt;
1103
+ bindings.discoverCharacteristics(peripheralUuid, serviceUuid, characteristicUuids);
1104
+
1105
+ assert.calledOnceWithExactly(gatt.discoverCharacteristics, serviceUuid, characteristicUuids);
1106
+ });
1107
+
1108
+ it('existing gatt no uuids', () => {
1109
+ const peripheralUuid = 'uuid';
1110
+ const handle = 'handle';
1111
+ const serviceUuid = 'serviceUuid';
1112
+ const gatt = {
1113
+ discoverCharacteristics: sinon.spy()
1114
+ };
1115
+
1116
+ bindings._handles[peripheralUuid] = handle;
1117
+ bindings._gatts[handle] = gatt;
1118
+ bindings.discoverCharacteristics(peripheralUuid, serviceUuid);
1119
+
1120
+ assert.calledOnceWithExactly(gatt.discoverCharacteristics, serviceUuid, []);
1121
+ });
1122
+ });
1123
+
1124
+ it('onCharacteristicsDiscovered', () => {
1125
+ const address = 'this:is:an:address';
1126
+ const serviceUuid = 'serviceUuid';
1127
+ const characteristics = 'characteristics';
1128
+ const callback = sinon.spy();
1129
+
1130
+ bindings.on('characteristicsDiscover', callback);
1131
+ bindings.onCharacteristicsDiscovered(address, serviceUuid, characteristics);
1132
+
1133
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', serviceUuid, characteristics);
1134
+ });
1135
+
1136
+ it('onCharacteristicsDiscoveredEX', () => {
1137
+ const address = 'this:is:an:address';
1138
+ const serviceUuid = 'serviceUuid';
1139
+ const characteristics = 'characteristics';
1140
+ const callback = sinon.spy();
1141
+
1142
+ bindings.on('characteristicsDiscovered', callback);
1143
+ bindings.onCharacteristicsDiscoveredEX(address, serviceUuid, characteristics);
1144
+
1145
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', serviceUuid, characteristics);
1146
+ });
1147
+
1148
+ describe('read', () => {
1149
+ it('missing gatt', () => {
1150
+ const peripheralUuid = 'uuid';
1151
+ const handle = 'handle';
1152
+ const anotherHandle = 'another_handle';
1153
+ const serviceUuid = 'serviceUuid';
1154
+ const characteristicUuid = 'characteristic';
1155
+ const gatt = {
1156
+ read: sinon.spy()
1157
+ };
1158
+
1159
+ bindings._handles[peripheralUuid] = anotherHandle;
1160
+ bindings._gatts[handle] = gatt;
1161
+ bindings.read(peripheralUuid, serviceUuid, characteristicUuid);
1162
+
1163
+ assert.notCalled(gatt.read);
1164
+ });
1165
+
1166
+ it('existing gatt', () => {
1167
+ const peripheralUuid = 'uuid';
1168
+ const handle = 'handle';
1169
+ const serviceUuid = 'serviceUuid';
1170
+ const characteristicUuid = 'characteristics';
1171
+ const gatt = {
1172
+ read: sinon.spy()
1173
+ };
1174
+
1175
+ bindings._handles[peripheralUuid] = handle;
1176
+ bindings._gatts[handle] = gatt;
1177
+ bindings.read(peripheralUuid, serviceUuid, characteristicUuid);
1178
+
1179
+ assert.calledOnceWithExactly(gatt.read, serviceUuid, characteristicUuid);
1180
+ });
1181
+
1182
+ it('existing gatt no uuids', () => {
1183
+ const peripheralUuid = 'uuid';
1184
+ const handle = 'handle';
1185
+ const gatt = {
1186
+ read: sinon.spy()
1187
+ };
1188
+
1189
+ bindings._handles[peripheralUuid] = handle;
1190
+ bindings._gatts[handle] = gatt;
1191
+ bindings.read(peripheralUuid);
1192
+
1193
+ assert.calledOnceWithExactly(gatt.read, undefined, undefined);
1194
+ });
1195
+ });
1196
+
1197
+ it('onRead', () => {
1198
+ const address = 'this:is:an:address';
1199
+ const serviceUuid = 'serviceUuid';
1200
+ const characteristicUuid = 'characteristics';
1201
+ const data = 'data';
1202
+ const callback = sinon.spy();
1203
+
1204
+ bindings.on('read', callback);
1205
+ bindings.onRead(address, serviceUuid, characteristicUuid, data);
1206
+
1207
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', serviceUuid, characteristicUuid, data, false);
1208
+ });
1209
+
1210
+ describe('write', () => {
1211
+ it('missing gatt', () => {
1212
+ const peripheralUuid = 'uuid';
1213
+ const handle = 'handle';
1214
+ const anotherHandle = 'another_handle';
1215
+ const serviceUuid = 'serviceUuid';
1216
+ const characteristicUuid = 'characteristic';
1217
+ const data = 'data';
1218
+ const withoutResponse = true;
1219
+
1220
+ const gatt = {
1221
+ write: sinon.spy()
1222
+ };
1223
+
1224
+ bindings._handles[peripheralUuid] = anotherHandle;
1225
+ bindings._gatts[handle] = gatt;
1226
+ bindings.write(peripheralUuid, serviceUuid, characteristicUuid, data, withoutResponse);
1227
+
1228
+ assert.notCalled(gatt.write);
1229
+ });
1230
+
1231
+ it('existing gatt', () => {
1232
+ const peripheralUuid = 'uuid';
1233
+ const handle = 'handle';
1234
+ const serviceUuid = 'serviceUuid';
1235
+ const characteristicUuid = 'characteristics';
1236
+ const data = 'data';
1237
+ const withoutResponse = true;
1238
+ const gatt = {
1239
+ write: sinon.spy()
1240
+ };
1241
+
1242
+ bindings._handles[peripheralUuid] = handle;
1243
+ bindings._gatts[handle] = gatt;
1244
+ bindings.write(peripheralUuid, serviceUuid, characteristicUuid, data, withoutResponse);
1245
+
1246
+ assert.calledOnceWithExactly(gatt.write, serviceUuid, characteristicUuid, data, withoutResponse);
1247
+ });
1248
+
1249
+ it('existing gatt no uuids', () => {
1250
+ const peripheralUuid = 'uuid';
1251
+ const handle = 'handle';
1252
+ const gatt = {
1253
+ write: sinon.spy()
1254
+ };
1255
+
1256
+ bindings._handles[peripheralUuid] = handle;
1257
+ bindings._gatts[handle] = gatt;
1258
+ bindings.write(peripheralUuid);
1259
+
1260
+ assert.calledOnceWithExactly(gatt.write, undefined, undefined, undefined, undefined);
1261
+ });
1262
+ });
1263
+
1264
+ it('onWrite', () => {
1265
+ const address = 'this:is:an:address';
1266
+ const serviceUuid = 'serviceUuid';
1267
+ const characteristicUuid = 'characteristics';
1268
+ const callback = sinon.spy();
1269
+
1270
+ bindings.on('write', callback);
1271
+ bindings.onWrite(address, serviceUuid, characteristicUuid);
1272
+
1273
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', serviceUuid, characteristicUuid);
1274
+ });
1275
+
1276
+ describe('broadcast', () => {
1277
+ it('missing gatt', () => {
1278
+ const peripheralUuid = 'uuid';
1279
+ const handle = 'handle';
1280
+ const anotherHandle = 'another_handle';
1281
+ const serviceUuid = 'serviceUuid';
1282
+ const characteristicUuid = 'characteristic';
1283
+ const broadcast = 'broadcast';
1284
+ const gatt = {
1285
+ broadcast: sinon.spy()
1286
+ };
1287
+
1288
+ bindings._handles[peripheralUuid] = anotherHandle;
1289
+ bindings._gatts[handle] = gatt;
1290
+ bindings.broadcast(peripheralUuid, serviceUuid, characteristicUuid, broadcast);
1291
+
1292
+ assert.notCalled(gatt.broadcast);
1293
+ });
1294
+
1295
+ it('existing gatt', () => {
1296
+ const peripheralUuid = 'uuid';
1297
+ const handle = 'handle';
1298
+ const serviceUuid = 'serviceUuid';
1299
+ const characteristicUuid = 'characteristics';
1300
+ const broadcast = 'broadcast';
1301
+ const gatt = {
1302
+ broadcast: sinon.spy()
1303
+ };
1304
+
1305
+ bindings._handles[peripheralUuid] = handle;
1306
+ bindings._gatts[handle] = gatt;
1307
+ bindings.broadcast(peripheralUuid, serviceUuid, characteristicUuid, broadcast);
1308
+
1309
+ assert.calledOnceWithExactly(gatt.broadcast, serviceUuid, characteristicUuid, broadcast);
1310
+ });
1311
+
1312
+ it('existing gatt no uuids', () => {
1313
+ const peripheralUuid = 'uuid';
1314
+ const handle = 'handle';
1315
+ const gatt = {
1316
+ broadcast: sinon.spy()
1317
+ };
1318
+
1319
+ bindings._handles[peripheralUuid] = handle;
1320
+ bindings._gatts[handle] = gatt;
1321
+ bindings.broadcast(peripheralUuid);
1322
+
1323
+ assert.calledOnceWithExactly(gatt.broadcast, undefined, undefined, undefined);
1324
+ });
1325
+ });
1326
+
1327
+ it('onBroadcast', () => {
1328
+ const address = 'this:is:an:address';
1329
+ const serviceUuid = 'serviceUuid';
1330
+ const characteristicUuid = 'characteristics';
1331
+ const state = 'data';
1332
+ const callback = sinon.spy();
1333
+
1334
+ bindings.on('broadcast', callback);
1335
+ bindings.onBroadcast(address, serviceUuid, characteristicUuid, state);
1336
+
1337
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', serviceUuid, characteristicUuid, state);
1338
+ });
1339
+
1340
+ describe('notify', () => {
1341
+ it('missing gatt', () => {
1342
+ const peripheralUuid = 'uuid';
1343
+ const handle = 'handle';
1344
+ const anotherHandle = 'another_handle';
1345
+ const serviceUuid = 'serviceUuid';
1346
+ const characteristicUuid = 'characteristic';
1347
+ const notify = 'notify';
1348
+ const gatt = {
1349
+ notify: sinon.spy()
1350
+ };
1351
+
1352
+ bindings._handles[peripheralUuid] = anotherHandle;
1353
+ bindings._gatts[handle] = gatt;
1354
+ bindings.notify(peripheralUuid, serviceUuid, characteristicUuid, notify);
1355
+
1356
+ assert.notCalled(gatt.notify);
1357
+ });
1358
+
1359
+ it('existing gatt', () => {
1360
+ const peripheralUuid = 'uuid';
1361
+ const handle = 'handle';
1362
+ const serviceUuid = 'serviceUuid';
1363
+ const characteristicUuid = 'characteristics';
1364
+ const notify = 'notify';
1365
+ const gatt = {
1366
+ notify: sinon.spy()
1367
+ };
1368
+
1369
+ bindings._handles[peripheralUuid] = handle;
1370
+ bindings._gatts[handle] = gatt;
1371
+ bindings.notify(peripheralUuid, serviceUuid, characteristicUuid, notify);
1372
+
1373
+ assert.calledOnceWithExactly(gatt.notify, serviceUuid, characteristicUuid, notify);
1374
+ });
1375
+
1376
+ it('existing gatt no uuids', () => {
1377
+ const peripheralUuid = 'uuid';
1378
+ const handle = 'handle';
1379
+ const gatt = {
1380
+ notify: sinon.spy()
1381
+ };
1382
+
1383
+ bindings._handles[peripheralUuid] = handle;
1384
+ bindings._gatts[handle] = gatt;
1385
+ bindings.notify(peripheralUuid);
1386
+
1387
+ assert.calledOnceWithExactly(gatt.notify, undefined, undefined, undefined);
1388
+ });
1389
+ });
1390
+
1391
+ it('onNotify', () => {
1392
+ const address = 'this:is:an:address';
1393
+ const serviceUuid = 'serviceUuid';
1394
+ const characteristicUuid = 'characteristics';
1395
+ const state = 'data';
1396
+ const callback = sinon.spy();
1397
+
1398
+ bindings.on('notify', callback);
1399
+ bindings.onNotify(address, serviceUuid, characteristicUuid, state);
1400
+
1401
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', serviceUuid, characteristicUuid, state);
1402
+ });
1403
+
1404
+ it('onNotification', () => {
1405
+ const address = 'this:is:an:address';
1406
+ const serviceUuid = 'serviceUuid';
1407
+ const characteristicUuid = 'characteristics';
1408
+ const data = 'data';
1409
+ const callback = sinon.spy();
1410
+
1411
+ bindings.on('read', callback);
1412
+ bindings.onNotification(address, serviceUuid, characteristicUuid, data);
1413
+
1414
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', serviceUuid, characteristicUuid, data, true);
1415
+ });
1416
+
1417
+ describe('discoverDescriptors', () => {
1418
+ it('missing gatt', () => {
1419
+ const peripheralUuid = 'uuid';
1420
+ const handle = 'handle';
1421
+ const anotherHandle = 'another_handle';
1422
+ const serviceUuid = 'serviceUuid';
1423
+ const characteristicUuid = 'characteristic';
1424
+ const gatt = {
1425
+ discoverDescriptors: sinon.spy()
1426
+ };
1427
+
1428
+ bindings._handles[peripheralUuid] = anotherHandle;
1429
+ bindings._gatts[handle] = gatt;
1430
+ bindings.discoverDescriptors(peripheralUuid, serviceUuid, characteristicUuid);
1431
+
1432
+ assert.notCalled(gatt.discoverDescriptors);
1433
+ });
1434
+
1435
+ it('existing gatt', () => {
1436
+ const peripheralUuid = 'uuid';
1437
+ const handle = 'handle';
1438
+ const serviceUuid = 'serviceUuid';
1439
+ const characteristicUuid = 'characteristics';
1440
+ const gatt = {
1441
+ discoverDescriptors: sinon.spy()
1442
+ };
1443
+
1444
+ bindings._handles[peripheralUuid] = handle;
1445
+ bindings._gatts[handle] = gatt;
1446
+ bindings.discoverDescriptors(peripheralUuid, serviceUuid, characteristicUuid);
1447
+
1448
+ assert.calledOnceWithExactly(gatt.discoverDescriptors, serviceUuid, characteristicUuid);
1449
+ });
1450
+
1451
+ it('existing gatt no uuids', () => {
1452
+ const peripheralUuid = 'uuid';
1453
+ const handle = 'handle';
1454
+ const gatt = {
1455
+ discoverDescriptors: sinon.spy()
1456
+ };
1457
+
1458
+ bindings._handles[peripheralUuid] = handle;
1459
+ bindings._gatts[handle] = gatt;
1460
+ bindings.discoverDescriptors(peripheralUuid);
1461
+
1462
+ assert.calledOnceWithExactly(gatt.discoverDescriptors, undefined, undefined);
1463
+ });
1464
+ });
1465
+
1466
+ it('onDescriptorsDiscovered', () => {
1467
+ const address = 'this:is:an:address';
1468
+ const serviceUuid = 'serviceUuid';
1469
+ const characteristicUuid = 'characteristics';
1470
+ const descriptorUuids = 'descriptorUuids';
1471
+ const callback = sinon.spy();
1472
+
1473
+ bindings.on('descriptorsDiscover', callback);
1474
+ bindings.onDescriptorsDiscovered(address, serviceUuid, characteristicUuid, descriptorUuids);
1475
+
1476
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', serviceUuid, characteristicUuid, descriptorUuids);
1477
+ });
1478
+
1479
+ describe('readValue', () => {
1480
+ it('missing gatt', () => {
1481
+ const peripheralUuid = 'uuid';
1482
+ const handle = 'handle';
1483
+ const anotherHandle = 'another_handle';
1484
+ const serviceUuid = 'serviceUuid';
1485
+ const characteristicUuid = 'characteristic';
1486
+ const descriptorUuid = 'descriptorUuid';
1487
+ const gatt = {
1488
+ readValue: sinon.spy()
1489
+ };
1490
+
1491
+ bindings._handles[peripheralUuid] = anotherHandle;
1492
+ bindings._gatts[handle] = gatt;
1493
+ bindings.readValue(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid);
1494
+
1495
+ assert.notCalled(gatt.readValue);
1496
+ });
1497
+
1498
+ it('existing gatt', () => {
1499
+ const peripheralUuid = 'uuid';
1500
+ const handle = 'handle';
1501
+ const serviceUuid = 'serviceUuid';
1502
+ const characteristicUuid = 'characteristics';
1503
+ const descriptorUuid = 'descriptorUuid';
1504
+ const gatt = {
1505
+ readValue: sinon.spy()
1506
+ };
1507
+
1508
+ bindings._handles[peripheralUuid] = handle;
1509
+ bindings._gatts[handle] = gatt;
1510
+ bindings.readValue(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid);
1511
+
1512
+ assert.calledOnceWithExactly(gatt.readValue, serviceUuid, characteristicUuid, descriptorUuid);
1513
+ });
1514
+
1515
+ it('existing gatt no uuids', () => {
1516
+ const peripheralUuid = 'uuid';
1517
+ const handle = 'handle';
1518
+ const gatt = {
1519
+ readValue: sinon.spy()
1520
+ };
1521
+
1522
+ bindings._handles[peripheralUuid] = handle;
1523
+ bindings._gatts[handle] = gatt;
1524
+ bindings.readValue(peripheralUuid);
1525
+
1526
+ assert.calledOnceWithExactly(gatt.readValue, undefined, undefined, undefined);
1527
+ });
1528
+ });
1529
+
1530
+ it('onValueRead', () => {
1531
+ const address = 'this:is:an:address';
1532
+ const serviceUuid = 'serviceUuid';
1533
+ const characteristicUuid = 'characteristics';
1534
+ const descriptorUuid = 'descriptorUuid';
1535
+ const data = 'data';
1536
+ const callback = sinon.spy();
1537
+
1538
+ bindings.on('valueRead', callback);
1539
+ bindings.onValueRead(address, serviceUuid, characteristicUuid, descriptorUuid, data);
1540
+
1541
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', serviceUuid, characteristicUuid, descriptorUuid, data);
1542
+ });
1543
+
1544
+ describe('writeValue', () => {
1545
+ it('missing gatt', () => {
1546
+ const peripheralUuid = 'uuid';
1547
+ const handle = 'handle';
1548
+ const anotherHandle = 'another_handle';
1549
+ const serviceUuid = 'serviceUuid';
1550
+ const characteristicUuid = 'characteristic';
1551
+ const descriptorUuid = 'descriptorUuid';
1552
+ const data = 'data';
1553
+ const gatt = {
1554
+ writeValue: sinon.spy()
1555
+ };
1556
+
1557
+ bindings._handles[peripheralUuid] = anotherHandle;
1558
+ bindings._gatts[handle] = gatt;
1559
+ bindings.writeValue(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, data);
1560
+
1561
+ assert.notCalled(gatt.writeValue);
1562
+ });
1563
+
1564
+ it('existing gatt', () => {
1565
+ const peripheralUuid = 'uuid';
1566
+ const handle = 'handle';
1567
+ const serviceUuid = 'serviceUuid';
1568
+ const characteristicUuid = 'characteristics';
1569
+ const descriptorUuid = 'descriptorUuid';
1570
+ const data = 'data';
1571
+ const gatt = {
1572
+ writeValue: sinon.spy()
1573
+ };
1574
+
1575
+ bindings._handles[peripheralUuid] = handle;
1576
+ bindings._gatts[handle] = gatt;
1577
+ bindings.writeValue(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, data);
1578
+
1579
+ assert.calledOnceWithExactly(gatt.writeValue, serviceUuid, characteristicUuid, descriptorUuid, data);
1580
+ });
1581
+
1582
+ it('existing gatt no uuids', () => {
1583
+ const peripheralUuid = 'uuid';
1584
+ const handle = 'handle';
1585
+ const gatt = {
1586
+ writeValue: sinon.spy()
1587
+ };
1588
+
1589
+ bindings._handles[peripheralUuid] = handle;
1590
+ bindings._gatts[handle] = gatt;
1591
+ bindings.writeValue(peripheralUuid);
1592
+
1593
+ assert.calledOnceWithExactly(gatt.writeValue, undefined, undefined, undefined, undefined);
1594
+ });
1595
+ });
1596
+
1597
+ it('onValueWrite', () => {
1598
+ const address = 'this:is:an:address';
1599
+ const serviceUuid = 'serviceUuid';
1600
+ const characteristicUuid = 'characteristics';
1601
+ const descriptorUuid = 'descriptorUuid';
1602
+ const callback = sinon.spy();
1603
+
1604
+ bindings.on('valueWrite', callback);
1605
+ bindings.onValueWrite(address, serviceUuid, characteristicUuid, descriptorUuid);
1606
+
1607
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', serviceUuid, characteristicUuid, descriptorUuid);
1608
+ });
1609
+
1610
+ describe('readHandle', () => {
1611
+ it('missing gatt', () => {
1612
+ const peripheralUuid = 'uuid';
1613
+ const handle = 'handle';
1614
+ const anotherHandle = 'another_handle';
1615
+ const attHandle = 'attHandle';
1616
+ const gatt = {
1617
+ readHandle: sinon.spy()
1618
+ };
1619
+
1620
+ bindings._handles[peripheralUuid] = anotherHandle;
1621
+ bindings._gatts[handle] = gatt;
1622
+ bindings.readHandle(peripheralUuid, attHandle);
1623
+
1624
+ assert.notCalled(gatt.readHandle);
1625
+ });
1626
+
1627
+ it('existing gatt', () => {
1628
+ const peripheralUuid = 'uuid';
1629
+ const handle = 'handle';
1630
+ const attHandle = 'attHandle';
1631
+ const gatt = {
1632
+ readHandle: sinon.spy()
1633
+ };
1634
+
1635
+ bindings._handles[peripheralUuid] = handle;
1636
+ bindings._gatts[handle] = gatt;
1637
+ bindings.readHandle(peripheralUuid, attHandle);
1638
+
1639
+ assert.calledOnceWithExactly(gatt.readHandle, attHandle);
1640
+ });
1641
+
1642
+ it('existing gatt no uuids', () => {
1643
+ const peripheralUuid = 'uuid';
1644
+ const handle = 'handle';
1645
+ const gatt = {
1646
+ readHandle: sinon.spy()
1647
+ };
1648
+
1649
+ bindings._handles[peripheralUuid] = handle;
1650
+ bindings._gatts[handle] = gatt;
1651
+ bindings.readHandle(peripheralUuid);
1652
+
1653
+ assert.calledOnceWithExactly(gatt.readHandle, undefined);
1654
+ });
1655
+ });
1656
+
1657
+ it('onHandleRead', () => {
1658
+ const address = 'this:is:an:address';
1659
+ const handle = 'handle';
1660
+ const data = 'data';
1661
+ const callback = sinon.spy();
1662
+
1663
+ bindings.on('handleRead', callback);
1664
+ bindings.onHandleRead(address, handle, data);
1665
+
1666
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', handle, data);
1667
+ });
1668
+
1669
+ describe('writeHandle', () => {
1670
+ it('missing gatt', () => {
1671
+ const peripheralUuid = 'uuid';
1672
+ const handle = 'handle';
1673
+ const anotherHandle = 'another_handle';
1674
+ const attHandle = 'attHandle';
1675
+ const data = 'data';
1676
+ const withoutResponse = true;
1677
+ const gatt = {
1678
+ writeHandle: sinon.spy()
1679
+ };
1680
+
1681
+ bindings._handles[peripheralUuid] = anotherHandle;
1682
+ bindings._gatts[handle] = gatt;
1683
+ bindings.writeHandle(peripheralUuid, attHandle, data, withoutResponse);
1684
+
1685
+ assert.notCalled(gatt.writeHandle);
1686
+ });
1687
+
1688
+ it('existing gatt', () => {
1689
+ const peripheralUuid = 'uuid';
1690
+ const handle = 'handle';
1691
+ const attHandle = 'attHandle';
1692
+ const data = 'data';
1693
+ const withoutResponse = true;
1694
+ const gatt = {
1695
+ writeHandle: sinon.spy()
1696
+ };
1697
+
1698
+ bindings._handles[peripheralUuid] = handle;
1699
+ bindings._gatts[handle] = gatt;
1700
+ bindings.writeHandle(peripheralUuid, attHandle, data, withoutResponse);
1701
+
1702
+ assert.calledOnceWithExactly(gatt.writeHandle, attHandle, data, withoutResponse);
1703
+ });
1704
+
1705
+ it('existing gatt no uuids', () => {
1706
+ const peripheralUuid = 'uuid';
1707
+ const handle = 'handle';
1708
+ const gatt = {
1709
+ writeHandle: sinon.spy()
1710
+ };
1711
+
1712
+ bindings._handles[peripheralUuid] = handle;
1713
+ bindings._gatts[handle] = gatt;
1714
+ bindings.writeHandle(peripheralUuid);
1715
+
1716
+ assert.calledOnceWithExactly(gatt.writeHandle, undefined, undefined, undefined);
1717
+ });
1718
+ });
1719
+
1720
+ it('onHandleWrite', () => {
1721
+ const address = 'this:is:an:address';
1722
+ const handle = 'handle';
1723
+ const callback = sinon.spy();
1724
+
1725
+ bindings.on('handleWrite', callback);
1726
+ bindings.onHandleWrite(address, handle);
1727
+
1728
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', handle);
1729
+ });
1730
+
1731
+ it('onHandleNotify', () => {
1732
+ const address = 'this:is:an:address';
1733
+ const handle = 'handle';
1734
+ const data = 'data';
1735
+ const callback = sinon.spy();
1736
+
1737
+ bindings.on('handleNotify', callback);
1738
+ bindings.onHandleNotify(address, handle, data);
1739
+
1740
+ assert.calledOnceWithExactly(callback, 'thisisanaddress', handle, data);
1741
+ });
1742
+
1743
+ it('onConnectionParameterUpdateRequest', () => {
1744
+ const handle = 'handle';
1745
+ const minInterval = 'minInterval';
1746
+ const maxInterval = 'maxInterval';
1747
+ const latency = 'latency';
1748
+ const supervisionTimeout = 'supervisionTimeout';
1749
+ const connUpdateLe = sinon.spy();
1750
+
1751
+ bindings._hci.connUpdateLe = connUpdateLe;
1752
+ bindings.onConnectionParameterUpdateRequest(handle, minInterval, maxInterval, latency, supervisionTimeout);
1753
+
1754
+ assert.calledOnceWithExactly(connUpdateLe, handle, minInterval, maxInterval, latency, supervisionTimeout);
1755
+ });
1756
+ });