@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,1565 @@
1
+ const should = require('should');
2
+ const sinon = require('sinon');
3
+
4
+ const { assert } = sinon;
5
+
6
+ const Noble = require('../lib/noble');
7
+ const Peripheral = require('../lib/peripheral');
8
+ const Service = require('../lib/service');
9
+ const Characteristic = require('../lib/characteristic');
10
+ const Descriptor = require('../lib/descriptor');
11
+
12
+ describe('noble', () => {
13
+ /**
14
+ * @type {Noble & import('events').EventEmitter}
15
+ */
16
+ let noble;
17
+ let mockBindings;
18
+
19
+ beforeEach(() => {
20
+ mockBindings = {
21
+ init: () => {},
22
+ on: () => {}
23
+ };
24
+
25
+ noble = new Noble(mockBindings);
26
+ });
27
+
28
+ describe('startScanning', () => {
29
+ beforeEach(() => {
30
+ mockBindings.startScanning = sinon.spy();
31
+ });
32
+
33
+ afterEach(() => {
34
+ sinon.reset();
35
+ });
36
+
37
+ it('should emit warning due to serviceUuids', () => {
38
+ const callback = sinon.spy();
39
+ const eventCallback = sinon.spy();
40
+ const expectedAllowDuplicates = true;
41
+ noble.on('warning', eventCallback);
42
+
43
+ noble.startScanning(callback, expectedAllowDuplicates);
44
+ noble.emit('stateChange', 'poweredOn');
45
+ // Check for single callback
46
+ noble.emit('stateChange', 'poweredOn');
47
+ noble.emit('scanStart');
48
+ // Check for single callback
49
+ noble.emit('scanStart');
50
+
51
+ assert.calledOnceWithExactly(
52
+ mockBindings.startScanning,
53
+ callback,
54
+ expectedAllowDuplicates
55
+ );
56
+ assert.calledOnceWithExactly(
57
+ eventCallback,
58
+ 'calling startScanning(callback) is deprecated'
59
+ );
60
+ });
61
+
62
+ it('should emit warning due to allowDuplicates', () => {
63
+ const callback = sinon.spy();
64
+ const eventCallback = sinon.spy();
65
+ const expectedServiceUuids = [1, 2, 3];
66
+ noble.on('warning', eventCallback);
67
+
68
+ noble.startScanning(expectedServiceUuids, callback);
69
+ noble.emit('stateChange', 'poweredOn');
70
+ // Check for single callback
71
+ noble.emit('stateChange', 'poweredOn');
72
+ noble.emit('scanStart');
73
+ // Check for single callback
74
+ noble.emit('scanStart');
75
+
76
+ assert.calledOnceWithExactly(
77
+ mockBindings.startScanning,
78
+ expectedServiceUuids,
79
+ callback
80
+ );
81
+ assert.calledOnceWithExactly(
82
+ eventCallback,
83
+ 'calling startScanning(serviceUuids, callback) is deprecated'
84
+ );
85
+ });
86
+
87
+ it('should delegate to binding', () => {
88
+ const expectedServiceUuids = [1, 2, 3];
89
+ const expectedAllowDuplicates = true;
90
+
91
+ noble.startScanning(expectedServiceUuids, expectedAllowDuplicates);
92
+ noble.emit('stateChange', 'poweredOn');
93
+ // Check for single callback
94
+ noble.emit('stateChange', 'poweredOn');
95
+ noble.emit('scanStart');
96
+ // Check for single callback
97
+ noble.emit('scanStart');
98
+
99
+ assert.calledOnceWithExactly(
100
+ mockBindings.startScanning,
101
+ expectedServiceUuids,
102
+ expectedAllowDuplicates
103
+ );
104
+ });
105
+
106
+ it('should delegate to callback', async () => {
107
+ const expectedServiceUuids = [1, 2, 3];
108
+ const expectedAllowDuplicates = true;
109
+ const callback = sinon.spy();
110
+
111
+ noble.startScanning(
112
+ expectedServiceUuids,
113
+ expectedAllowDuplicates,
114
+ callback
115
+ );
116
+ noble.emit('stateChange', 'poweredOn');
117
+ // Check for single callback
118
+ noble.emit('stateChange', 'poweredOn');
119
+ noble.emit('scanStart');
120
+ // Check for single callback
121
+ noble.emit('scanStart');
122
+
123
+ assert.calledOnceWithExactly(callback, null, undefined);
124
+ assert.calledOnceWithExactly(
125
+ mockBindings.startScanning,
126
+ expectedServiceUuids,
127
+ expectedAllowDuplicates
128
+ );
129
+ });
130
+
131
+ it('should delegate to callback, already initialized', async () => {
132
+ noble.initialized = true;
133
+ noble._state = 'poweredOn';
134
+
135
+ noble.startScanning();
136
+
137
+ assert.calledOnceWithExactly(
138
+ mockBindings.startScanning,
139
+ undefined,
140
+ undefined
141
+ );
142
+ });
143
+
144
+ it('should delegate to callback with filter', async () => {
145
+ const expectedServiceUuids = [1, 2, 3];
146
+ const expectedAllowDuplicates = true;
147
+ const callback = sinon.spy();
148
+
149
+ noble.startScanning(
150
+ expectedServiceUuids,
151
+ expectedAllowDuplicates,
152
+ callback
153
+ );
154
+ noble.emit('stateChange', 'poweredOn');
155
+ // Check for single callback
156
+ noble.emit('stateChange', 'poweredOn');
157
+ noble.emit('scanStart', 'filter');
158
+
159
+ assert.calledOnceWithExactly(callback, null, 'filter');
160
+ assert.calledOnceWithExactly(
161
+ mockBindings.startScanning,
162
+ expectedServiceUuids,
163
+ expectedAllowDuplicates
164
+ );
165
+ });
166
+
167
+ it('should throw an error if not powered on', async () => {
168
+ try {
169
+ noble.startScanning();
170
+ noble.emit('stateChange', 'poweredOff');
171
+ // Check for single callback
172
+ noble.emit('stateChange', 'poweredOff');
173
+ noble.emit('scanStart');
174
+ // Check for single callback
175
+ noble.emit('scanStart');
176
+
177
+ assert.fail();
178
+ } catch (e) {
179
+ should(e.message).equal(
180
+ 'Could not start scanning, state is poweredOff (not poweredOn)'
181
+ );
182
+ }
183
+ assert.notCalled(mockBindings.startScanning);
184
+ });
185
+ });
186
+
187
+ describe('startScanningAsync', () => {
188
+ beforeEach(() => {
189
+ mockBindings.startScanning = sinon.spy();
190
+ });
191
+
192
+ afterEach(() => {
193
+ sinon.reset();
194
+ });
195
+
196
+ it('should delegate to binding', async () => {
197
+ const expectedServiceUuids = [1, 2, 3];
198
+ const expectedAllowDuplicates = true;
199
+
200
+ const promise = noble.startScanningAsync(
201
+ expectedServiceUuids,
202
+ expectedAllowDuplicates
203
+ );
204
+ noble.emit('stateChange', 'poweredOn');
205
+ // Check for single callback
206
+ noble.emit('stateChange', 'poweredOn');
207
+ noble.emit('scanStart');
208
+ // Check for single callback
209
+ noble.emit('scanStart');
210
+
211
+ should(promise).resolvedWith(undefined);
212
+ assert.calledOnceWithExactly(
213
+ mockBindings.startScanning,
214
+ expectedServiceUuids,
215
+ expectedAllowDuplicates
216
+ );
217
+ });
218
+
219
+ it('should throw an error if not powered on', async () => {
220
+ const promise = noble.startScanningAsync();
221
+ noble.emit('stateChange', 'poweredOff');
222
+ // Check for single callback
223
+ noble.emit('stateChange', 'poweredOff');
224
+ noble.emit('scanStart');
225
+ // Check for single callback
226
+ noble.emit('scanStart');
227
+
228
+ should(promise).rejectedWith(
229
+ 'Could not start scanning, state is poweredOff (not poweredOn)'
230
+ );
231
+ assert.notCalled(mockBindings.startScanning);
232
+ });
233
+ });
234
+
235
+ describe('stopScanning', () => {
236
+ beforeEach(() => {
237
+ mockBindings.stopScanning = sinon.spy();
238
+ });
239
+
240
+ afterEach(() => {
241
+ sinon.reset();
242
+ });
243
+
244
+ it('should no callback', async () => {
245
+ noble.initialized = true;
246
+ noble.stopScanning();
247
+ assert.calledOnceWithExactly(mockBindings.stopScanning);
248
+ });
249
+ });
250
+
251
+ describe('stopScanningAsync', () => {
252
+ beforeEach(() => {
253
+ mockBindings.stopScanning = sinon.spy();
254
+ });
255
+
256
+ afterEach(() => {
257
+ sinon.reset();
258
+ });
259
+
260
+ it('should not delegate to binding (not initialized)', async () => {
261
+ const promise = noble.stopScanningAsync();
262
+ noble.emit('scanStop');
263
+
264
+ should(promise).resolvedWith(undefined);
265
+ assert.notCalled(mockBindings.stopScanning);
266
+ });
267
+
268
+ it('should delegate to binding (initilazed)', async () => {
269
+ noble.initialized = true;
270
+ const promise = noble.stopScanningAsync();
271
+ noble.emit('scanStop');
272
+
273
+ should(promise).resolvedWith(undefined);
274
+ assert.calledOnceWithExactly(mockBindings.stopScanning);
275
+ });
276
+ });
277
+
278
+ describe('connect', () => {
279
+ beforeEach(() => {
280
+ mockBindings.connect = sinon.spy();
281
+ });
282
+
283
+ afterEach(() => {
284
+ sinon.reset();
285
+ });
286
+ it('should delegate to binding', () => {
287
+ const peripheralUuid = 'peripheral-uuid';
288
+ const parameters = {};
289
+
290
+ noble.connect(peripheralUuid, parameters);
291
+
292
+ assert.calledOnceWithExactly(
293
+ mockBindings.connect,
294
+ peripheralUuid,
295
+ parameters
296
+ );
297
+ });
298
+ });
299
+
300
+ describe('onConnect', () => {
301
+ it('should emit connected on existing peripheral', () => {
302
+ const emit = sinon.spy();
303
+ noble._peripherals = {
304
+ uuid: { emit }
305
+ };
306
+
307
+ const warningCallback = sinon.spy();
308
+
309
+ noble.on('warning', warningCallback);
310
+ noble.onConnect('uuid', false);
311
+
312
+ assert.calledOnceWithExactly(emit, 'connect', false);
313
+ assert.notCalled(warningCallback);
314
+
315
+ should(noble._peripherals).deepEqual({
316
+ uuid: { state: 'connected', emit }
317
+ });
318
+ });
319
+
320
+ it('should emit error on existing peripheral', () => {
321
+ const emit = sinon.spy();
322
+ noble._peripherals = {
323
+ uuid: { emit }
324
+ };
325
+
326
+ const warningCallback = sinon.spy();
327
+
328
+ noble.on('warning', warningCallback);
329
+ noble.onConnect('uuid', true);
330
+
331
+ assert.calledOnceWithExactly(emit, 'connect', true);
332
+ assert.notCalled(warningCallback);
333
+
334
+ should(noble._peripherals).deepEqual({
335
+ uuid: { state: 'error', emit }
336
+ });
337
+ });
338
+
339
+ it('should emit warning on missing peripheral', () => {
340
+ const warningCallback = sinon.spy();
341
+
342
+ noble.on('warning', warningCallback);
343
+ noble.onConnect('uuid', true);
344
+
345
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral uuid connected!');
346
+
347
+ should(noble._peripherals).deepEqual({});
348
+ });
349
+ });
350
+
351
+ describe('setScanParameters', () => {
352
+ beforeEach(() => {
353
+ mockBindings.setScanParameters = sinon.spy();
354
+ });
355
+
356
+ afterEach(() => {
357
+ sinon.reset();
358
+ });
359
+
360
+ it('should delegate to binding', async () => {
361
+ const interval = 'interval';
362
+ const window = 'window';
363
+
364
+ noble.setScanParameters(interval, window);
365
+ noble.emit('scanParametersSet');
366
+
367
+ assert.calledOnceWithExactly(
368
+ mockBindings.setScanParameters,
369
+ interval,
370
+ window
371
+ );
372
+ });
373
+
374
+ it('should delegate to callback too', async () => {
375
+ const interval = 'interval';
376
+ const window = 'window';
377
+ const callback = sinon.spy();
378
+
379
+ noble.setScanParameters(interval, window, callback);
380
+ noble.emit('scanParametersSet');
381
+ // Check for single callback
382
+ noble.emit('scanParametersSet');
383
+
384
+ assert.calledOnceWithExactly(
385
+ mockBindings.setScanParameters,
386
+ interval,
387
+ window
388
+ );
389
+ assert.calledOnceWithExactly(callback);
390
+ });
391
+ });
392
+
393
+ describe('cancelConnect', () => {
394
+ beforeEach(() => {
395
+ mockBindings.cancelConnect = sinon.spy();
396
+ });
397
+
398
+ afterEach(() => {
399
+ sinon.reset();
400
+ });
401
+
402
+ it('should delegate to binding', () => {
403
+ const peripheralUuid = 'peripheral-uuid';
404
+ const parameters = {};
405
+
406
+ noble.cancelConnect(peripheralUuid, parameters);
407
+
408
+ assert.calledOnceWithExactly(
409
+ mockBindings.cancelConnect,
410
+ peripheralUuid,
411
+ parameters
412
+ );
413
+ });
414
+ });
415
+
416
+ it('should emit state', () => {
417
+ const callback = sinon.spy();
418
+ noble.on('stateChange', callback);
419
+
420
+ const state = 'newState';
421
+ noble.onStateChange(state);
422
+
423
+ should(noble._state).equal(state);
424
+ assert.calledOnceWithExactly(callback, state);
425
+ });
426
+
427
+ it('should change address', () => {
428
+ const address = 'newAddress';
429
+ noble.onAddressChange(address);
430
+
431
+ should(noble.address).equal(address);
432
+ });
433
+
434
+ it('should emit scanParametersSet event', () => {
435
+ const callback = sinon.spy();
436
+ noble.on('scanParametersSet', callback);
437
+
438
+ noble.onScanParametersSet();
439
+
440
+ assert.calledOnceWithExactly(callback);
441
+ });
442
+
443
+ it('should emit scanStart event', () => {
444
+ const callback = sinon.spy();
445
+ noble.on('scanStart', callback);
446
+
447
+ noble.onScanStart('filterDuplicates');
448
+
449
+ assert.calledOnceWithExactly(callback, 'filterDuplicates');
450
+ });
451
+
452
+ it('should emit scanStop event', () => {
453
+ const callback = sinon.spy();
454
+ noble.on('scanStop', callback);
455
+
456
+ noble.onScanStop();
457
+
458
+ assert.calledOnceWithExactly(callback);
459
+ });
460
+
461
+ describe('reset', () => {
462
+ beforeEach(() => {
463
+ mockBindings.reset = sinon.spy();
464
+ });
465
+
466
+ afterEach(() => {
467
+ sinon.reset();
468
+ });
469
+
470
+ it('should reset', () => {
471
+ noble.reset();
472
+ assert.calledOnceWithExactly(mockBindings.reset);
473
+ });
474
+ });
475
+
476
+ describe('disconnect', () => {
477
+ beforeEach(() => {
478
+ mockBindings.disconnect = sinon.spy();
479
+ });
480
+
481
+ afterEach(() => {
482
+ sinon.reset();
483
+ });
484
+
485
+ it('should disconnect', () => {
486
+ noble.disconnect('peripheralUuid');
487
+ assert.calledOnceWithExactly(mockBindings.disconnect, 'peripheralUuid');
488
+ });
489
+ });
490
+
491
+ describe('onDisconnect', () => {
492
+ it('should emit disconnect on existing peripheral', () => {
493
+ const emit = sinon.spy();
494
+ noble._peripherals = {
495
+ uuid: { emit }
496
+ };
497
+
498
+ const warningCallback = sinon.spy();
499
+
500
+ noble.on('warning', warningCallback);
501
+ noble.onDisconnect('uuid', false);
502
+
503
+ assert.calledOnceWithExactly(emit, 'disconnect', false);
504
+ assert.notCalled(warningCallback);
505
+
506
+ should(noble._peripherals).deepEqual({
507
+ uuid: { state: 'disconnected', emit }
508
+ });
509
+ });
510
+
511
+ it('should emit warning on missing peripheral', () => {
512
+ const warningCallback = sinon.spy();
513
+
514
+ noble.on('warning', warningCallback);
515
+ noble.onDisconnect('uuid', true);
516
+
517
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral uuid disconnected!');
518
+
519
+ should(noble._peripherals).deepEqual({});
520
+ });
521
+ });
522
+
523
+ describe('onDiscover', () => {
524
+ beforeEach(() => {
525
+ mockBindings.disconnect = sinon.spy();
526
+ });
527
+
528
+ afterEach(() => {
529
+ sinon.reset();
530
+ });
531
+
532
+ it('should add new peripheral', () => {
533
+ const uuid = 'uuid';
534
+ const address = 'address';
535
+ const addressType = 'addressType';
536
+ const connectable = 'connectable';
537
+ const advertisement = [];
538
+ const rssi = 'rssi';
539
+
540
+ const eventCallback = sinon.spy();
541
+ noble.on('discover', eventCallback);
542
+
543
+ noble.onDiscover(
544
+ uuid,
545
+ address,
546
+ addressType,
547
+ connectable,
548
+ advertisement,
549
+ rssi
550
+ );
551
+
552
+ // Check new peripheral
553
+ should(noble._peripherals).have.keys(uuid);
554
+ const peripheral = noble._peripherals[uuid];
555
+ should(peripheral._noble).equal(noble);
556
+ should(peripheral.id).equal(uuid);
557
+ should(peripheral.address).equal(address);
558
+ should(peripheral.addressType).equal(addressType);
559
+ should(peripheral.connectable).equal(connectable);
560
+ should(peripheral.advertisement).equal(advertisement);
561
+ should(peripheral.rssi).equal(rssi);
562
+
563
+ should(noble._services).have.keys(uuid);
564
+ should(noble._characteristics).have.keys(uuid);
565
+ should(noble._descriptors).have.keys(uuid);
566
+ should(noble._discoveredPeripheralUUids).deepEqual([uuid]);
567
+
568
+ assert.calledOnceWithExactly(eventCallback, peripheral);
569
+ });
570
+
571
+ it('should update existing peripheral', () => {
572
+ const uuid = 'uuid';
573
+ const address = 'address';
574
+ const addressType = 'addressType';
575
+ const connectable = 'connectable';
576
+ const advertisement = [undefined, 'adv2', 'adv3'];
577
+ const rssi = 'rssi';
578
+
579
+ // init peripheral
580
+ noble._peripherals[uuid] = new Peripheral(
581
+ noble,
582
+ uuid,
583
+ 'originalAddress',
584
+ 'originalAddressType',
585
+ 'originalConnectable',
586
+ ['adv1'],
587
+ 'originalRssi'
588
+ );
589
+
590
+ const eventCallback = sinon.spy();
591
+ noble.on('discover', eventCallback);
592
+
593
+ noble.onDiscover(
594
+ uuid,
595
+ address,
596
+ addressType,
597
+ connectable,
598
+ advertisement,
599
+ rssi
600
+ );
601
+
602
+ // Check new peripheral
603
+ should(noble._peripherals).have.keys(uuid);
604
+ const peripheral = noble._peripherals[uuid];
605
+ should(peripheral._noble).equal(noble);
606
+ should(peripheral.id).equal(uuid);
607
+ should(peripheral.address).equal('originalAddress');
608
+ should(peripheral.addressType).equal('originalAddressType');
609
+ should(peripheral.connectable).equal(connectable);
610
+ should(peripheral.advertisement).deepEqual(['adv1', 'adv2', 'adv3']);
611
+ should(peripheral.rssi).equal(rssi);
612
+
613
+ should(noble._services).be.empty();
614
+ should(noble._characteristics).be.empty();
615
+ should(noble._descriptors).be.empty();
616
+ should(noble._discoveredPeripheralUUids).deepEqual([uuid]);
617
+
618
+ assert.calledOnceWithExactly(eventCallback, peripheral);
619
+ });
620
+
621
+ it('should emit on duplicate', () => {
622
+ const uuid = 'uuid';
623
+ const address = 'address';
624
+ const addressType = 'addressType';
625
+ const connectable = 'connectable';
626
+ const advertisement = ['adv1', 'adv2', 'adv3'];
627
+ const rssi = 'rssi';
628
+
629
+ // register peripheral
630
+ noble._discoveredPeripheralUUids = [uuid];
631
+ noble._allowDuplicates = true;
632
+
633
+ const eventCallback = sinon.spy();
634
+ noble.on('discover', eventCallback);
635
+
636
+ noble.onDiscover(
637
+ uuid,
638
+ address,
639
+ addressType,
640
+ connectable,
641
+ advertisement,
642
+ rssi
643
+ );
644
+
645
+ assert.calledOnceWithExactly(eventCallback, noble._peripherals[uuid]);
646
+ });
647
+
648
+ it('should not emit on duplicate', () => {
649
+ const uuid = 'uuid';
650
+ const address = 'address';
651
+ const addressType = 'addressType';
652
+ const connectable = 'connectable';
653
+ const advertisement = ['adv1', 'adv2', 'adv3'];
654
+ const rssi = 'rssi';
655
+
656
+ // register peripheral
657
+ noble._discoveredPeripheralUUids = [uuid];
658
+
659
+ const eventCallback = sinon.spy();
660
+ noble.on('discover', eventCallback);
661
+
662
+ noble.onDiscover(
663
+ uuid,
664
+ address,
665
+ addressType,
666
+ connectable,
667
+ advertisement,
668
+ rssi
669
+ );
670
+
671
+ assert.notCalled(eventCallback);
672
+ });
673
+
674
+ it('should emit on new peripheral (even if duplicates are disallowed)', () => {
675
+ const uuid = 'uuid';
676
+ const address = 'address';
677
+ const addressType = 'addressType';
678
+ const connectable = 'connectable';
679
+ const advertisement = ['adv1', 'adv2', 'adv3'];
680
+ const rssi = 'rssi';
681
+
682
+ const eventCallback = sinon.spy();
683
+ noble.on('discover', eventCallback);
684
+
685
+ noble.onDiscover(
686
+ uuid,
687
+ address,
688
+ addressType,
689
+ connectable,
690
+ advertisement,
691
+ rssi
692
+ );
693
+
694
+ assert.calledOnceWithExactly(eventCallback, noble._peripherals[uuid]);
695
+ });
696
+ });
697
+
698
+ describe('updateRssi', () => {
699
+ beforeEach(() => {
700
+ mockBindings.updateRssi = sinon.spy();
701
+ });
702
+
703
+ afterEach(() => {
704
+ sinon.reset();
705
+ });
706
+
707
+ it('should updateRssi', () => {
708
+ noble.updateRssi('peripheralUuid');
709
+ assert.calledOnceWithExactly(mockBindings.updateRssi, 'peripheralUuid');
710
+ });
711
+ });
712
+
713
+ describe('onRssiUpdate', () => {
714
+ it('should emit rssiUpdate on existing peripheral', () => {
715
+ const emit = sinon.spy();
716
+ noble._peripherals = {
717
+ uuid: { emit }
718
+ };
719
+
720
+ const warningCallback = sinon.spy();
721
+
722
+ noble.on('warning', warningCallback);
723
+ noble.onRssiUpdate('uuid', 3);
724
+
725
+ assert.calledOnceWithExactly(emit, 'rssiUpdate', 3);
726
+ assert.notCalled(warningCallback);
727
+
728
+ should(noble._peripherals).deepEqual({
729
+ uuid: { rssi: 3, emit }
730
+ });
731
+ });
732
+
733
+ it('should emit warning on missing peripheral', () => {
734
+ const warningCallback = sinon.spy();
735
+
736
+ noble.on('warning', warningCallback);
737
+ noble.onRssiUpdate('uuid', 4);
738
+
739
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral uuid RSSI update!');
740
+
741
+ should(noble._peripherals).deepEqual({});
742
+ });
743
+ });
744
+
745
+ it('should add multiple services', () => {
746
+ noble.addService = sinon.stub().returnsArg(1);
747
+
748
+ const peripheralUuid = 'peripheralUuid';
749
+ const services = ['service1', 'service2'];
750
+ const result = noble.addServices(peripheralUuid, services);
751
+
752
+ assert.callCount(noble.addService, 2);
753
+ assert.calledWithExactly(noble.addService, peripheralUuid, 'service1');
754
+ assert.calledWithExactly(noble.addService, peripheralUuid, 'service2');
755
+
756
+ should(result).deepEqual(services);
757
+ });
758
+
759
+ describe('addService', () => {
760
+ const peripheralUuid = 'peripheralUuid';
761
+ const service = {
762
+ uuid: 'serviceUuid'
763
+ };
764
+ const peripheral = {};
765
+
766
+ beforeEach(() => {
767
+ noble._peripherals = { [peripheralUuid]: peripheral };
768
+ noble._services = { [peripheralUuid]: {} };
769
+ noble._characteristics = { [peripheralUuid]: {} };
770
+ noble._descriptors = { [peripheralUuid]: {} };
771
+ });
772
+
773
+ it('should add service to lower layer', () => {
774
+ noble._bindings.addService = sinon.spy();
775
+
776
+ const result = noble.addService(peripheralUuid, service);
777
+
778
+ assert.calledOnceWithExactly(noble._bindings.addService, peripheralUuid, service);
779
+
780
+ const expectedService = new Service(noble, peripheralUuid, service.uuid);
781
+ should(result).deepEqual(expectedService);
782
+ should(peripheral.services).deepEqual([expectedService]);
783
+ should(noble._services).deepEqual({
784
+ [peripheralUuid]: {
785
+ [service.uuid]: expectedService
786
+ }
787
+ });
788
+ should(noble._characteristics).deepEqual({
789
+ [peripheralUuid]: {
790
+ [service.uuid]: {}
791
+ }
792
+ });
793
+ should(noble._descriptors).deepEqual({
794
+ [peripheralUuid]: {
795
+ [service.uuid]: {}
796
+ }
797
+ });
798
+ });
799
+
800
+ it('should add service only to noble', () => {
801
+ peripheral.services = [];
802
+
803
+ const result = noble.addService(peripheralUuid, service);
804
+
805
+ const expectedService = new Service(noble, peripheralUuid, service.uuid);
806
+ should(result).deepEqual(expectedService);
807
+ should(peripheral.services).deepEqual([expectedService]);
808
+ should(noble._services).deepEqual({
809
+ [peripheralUuid]: {
810
+ [service.uuid]: expectedService
811
+ }
812
+ });
813
+ should(noble._characteristics).deepEqual({
814
+ [peripheralUuid]: {
815
+ [service.uuid]: {}
816
+ }
817
+ });
818
+ should(noble._descriptors).deepEqual({
819
+ [peripheralUuid]: {
820
+ [service.uuid]: {}
821
+ }
822
+ });
823
+ });
824
+ });
825
+
826
+ describe('onServicesDiscovered', () => {
827
+ const peripheralUuid = 'peripheralUuid';
828
+ const services = ['service1', 'service2'];
829
+
830
+ it('should not emit servicesDiscovered', () => {
831
+ const callback = sinon.spy();
832
+ noble.on('servicesDiscovered', callback);
833
+
834
+ noble.onServicesDiscovered(peripheralUuid, services);
835
+
836
+ assert.notCalled(callback);
837
+ });
838
+
839
+ it('should emit servicesDiscovered', () => {
840
+ const emit = sinon.spy();
841
+ noble._peripherals = { [peripheralUuid]: { uuid: 'peripheral', emit } };
842
+
843
+ noble.onServicesDiscovered(peripheralUuid, services);
844
+
845
+ assert.calledOnceWithExactly(emit, 'servicesDiscovered', { uuid: 'peripheral', emit }, services);
846
+ });
847
+ });
848
+
849
+ it('discoverServices - should delegate to bindings', () => {
850
+ noble._bindings.discoverServices = sinon.spy();
851
+ noble.discoverServices('peripheral', 'uuids');
852
+ assert.calledOnceWithExactly(noble._bindings.discoverServices, 'peripheral', 'uuids');
853
+ });
854
+
855
+ describe('onServicesDiscover', () => {
856
+ it('should emit warning', () => {
857
+ const warningCallback = sinon.spy();
858
+
859
+ noble.on('warning', warningCallback);
860
+
861
+ noble.onServicesDiscover('pUuid', ['service1', 'service2']);
862
+
863
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral pUuid services discover!');
864
+ });
865
+
866
+ it('should emit servicesDiscover and store services', () => {
867
+ const warningCallback = sinon.spy();
868
+ const discoverCallback = sinon.spy();
869
+
870
+ const peripheralUuid = 'peripheralUuid';
871
+
872
+ noble._peripherals = { [peripheralUuid]: { emit: discoverCallback } };
873
+ noble._services = { [peripheralUuid]: {} };
874
+ noble._characteristics = { [peripheralUuid]: {} };
875
+ noble._descriptors = { [peripheralUuid]: {} };
876
+
877
+ noble.on('warning', warningCallback);
878
+
879
+ noble.onServicesDiscover(peripheralUuid, ['service1', 'service2']);
880
+
881
+ const services = [new Service(noble, peripheralUuid, 'service1'), new Service(noble, peripheralUuid, 'service2')];
882
+
883
+ assert.calledOnceWithExactly(discoverCallback, 'servicesDiscover', services);
884
+ assert.notCalled(warningCallback);
885
+
886
+ should(noble._peripherals).deepEqual({
887
+ [peripheralUuid]: { services, emit: discoverCallback }
888
+ });
889
+ should(noble._services).deepEqual({
890
+ [peripheralUuid]: { service1: services[0], service2: services[1] }
891
+ });
892
+ should(noble._characteristics).deepEqual({
893
+ [peripheralUuid]: { service1: {}, service2: {} }
894
+ });
895
+ should(noble._descriptors).deepEqual({
896
+ [peripheralUuid]: { service1: {}, service2: {} }
897
+ });
898
+ });
899
+ });
900
+
901
+ describe('discoverIncludedServices', () => {
902
+ beforeEach(() => {
903
+ mockBindings.discoverIncludedServices = sinon.spy();
904
+ });
905
+
906
+ afterEach(() => {
907
+ sinon.reset();
908
+ });
909
+
910
+ it('should disconnect', () => {
911
+ noble.discoverIncludedServices('peripheralUuid', 'serviceUuid', 'serviceUuids');
912
+ assert.calledOnceWithExactly(mockBindings.discoverIncludedServices, 'peripheralUuid', 'serviceUuid', 'serviceUuids');
913
+ });
914
+ });
915
+
916
+ describe('addCharacteristics', () => {
917
+ const peripheralUuid = 'peripheralUuid';
918
+ const serviceUuid = 'serviceUuid';
919
+ const characteristic1 = {
920
+ uuid: 'characteristic1',
921
+ properties: 'properties1'
922
+ };
923
+ const characteristic2 = {
924
+ uuid: 'characteristic2',
925
+ properties: 'properties2'
926
+ };
927
+ const characteristics = [characteristic1, characteristic2];
928
+
929
+ beforeEach(() => {
930
+ noble._services = { [peripheralUuid]: { [serviceUuid]: {} } };
931
+ noble._characteristics = { [peripheralUuid]: { [serviceUuid]: {} } };
932
+ noble._descriptors = { [peripheralUuid]: { [serviceUuid]: {} } };
933
+ });
934
+
935
+ it('should delegate to bindings', () => {
936
+ const warningCallback = sinon.spy();
937
+
938
+ noble._bindings.addCharacteristics = sinon.spy();
939
+ noble.on('warning', warningCallback);
940
+
941
+ const result = noble.addCharacteristics(peripheralUuid, serviceUuid, characteristics);
942
+
943
+ assert.notCalled(warningCallback);
944
+ assert.calledOnceWithExactly(noble._bindings.addCharacteristics, peripheralUuid, serviceUuid, characteristics);
945
+
946
+ const expectedCharacteristics = [
947
+ new Characteristic(noble, peripheralUuid, serviceUuid, 'characteristic1', 'properties1'),
948
+ new Characteristic(noble, peripheralUuid, serviceUuid, 'characteristic2', 'properties2')
949
+ ];
950
+ should(result).deepEqual(expectedCharacteristics);
951
+ should(noble._services).deepEqual({ [peripheralUuid]: { [serviceUuid]: { characteristics: expectedCharacteristics } } });
952
+ should(noble._characteristics).deepEqual({ [peripheralUuid]: { [serviceUuid]: { characteristic1: expectedCharacteristics[0], characteristic2: expectedCharacteristics[1] } } });
953
+ should(noble._descriptors).deepEqual({ [peripheralUuid]: { [serviceUuid]: { characteristic1: {}, characteristic2: {} } } });
954
+ });
955
+
956
+ it('should not delegate to bindings', () => {
957
+ const warningCallback = sinon.spy();
958
+
959
+ noble.on('warning', warningCallback);
960
+
961
+ const result = noble.addCharacteristics(peripheralUuid, serviceUuid, characteristics);
962
+
963
+ assert.notCalled(warningCallback);
964
+
965
+ const expectedCharacteristics = [
966
+ new Characteristic(noble, peripheralUuid, serviceUuid, 'characteristic1', 'properties1'),
967
+ new Characteristic(noble, peripheralUuid, serviceUuid, 'characteristic2', 'properties2')
968
+ ];
969
+ should(result).deepEqual(expectedCharacteristics);
970
+ should(noble._services).deepEqual({ [peripheralUuid]: { [serviceUuid]: { characteristics: expectedCharacteristics } } });
971
+ should(noble._characteristics).deepEqual({ [peripheralUuid]: { [serviceUuid]: { characteristic1: expectedCharacteristics[0], characteristic2: expectedCharacteristics[1] } } });
972
+ should(noble._descriptors).deepEqual({ [peripheralUuid]: { [serviceUuid]: { characteristic1: {}, characteristic2: {} } } });
973
+ });
974
+
975
+ it('should emit warning', () => {
976
+ const warningCallback = sinon.spy();
977
+
978
+ noble.on('warning', warningCallback);
979
+
980
+ noble._services = { peripheralUuid: {} };
981
+ const result = noble.addCharacteristics(peripheralUuid, serviceUuid, characteristics);
982
+
983
+ assert.calledOnceWithExactly(warningCallback, 'unknown service peripheralUuid, serviceUuid characteristics discover!');
984
+
985
+ should(result).equal(undefined);
986
+ should(noble._services).deepEqual({ [peripheralUuid]: { } });
987
+ should(noble._characteristics).deepEqual({ [peripheralUuid]: { [serviceUuid]: { } } });
988
+ should(noble._descriptors).deepEqual({ [peripheralUuid]: { [serviceUuid]: { } } });
989
+ });
990
+ });
991
+
992
+ it('onCharacteristicsDiscovered - should emit event', () => {
993
+ const emit = sinon.spy();
994
+
995
+ noble._services = {
996
+ peripheralUuid: {
997
+ serviceUuid: {
998
+ emit
999
+ }
1000
+ }
1001
+ };
1002
+
1003
+ noble.onCharacteristicsDiscovered('peripheralUuid', 'serviceUuid', 'characteristics');
1004
+
1005
+ assert.calledOnceWithExactly(emit, 'characteristicsDiscovered', 'characteristics');
1006
+ });
1007
+
1008
+ it('discoverCharacteristics - should delegate', () => {
1009
+ noble._bindings.discoverCharacteristics = sinon.spy();
1010
+
1011
+ noble.discoverCharacteristics('peripheralUuid', 'serviceUuid', 'characteristicUuids');
1012
+
1013
+ assert.calledOnceWithExactly(noble._bindings.discoverCharacteristics, 'peripheralUuid', 'serviceUuid', 'characteristicUuids');
1014
+ });
1015
+
1016
+ describe('onCharacteristicsDiscover', () => {
1017
+ it('should emit warning', () => {
1018
+ const warningCallback = sinon.spy();
1019
+
1020
+ const peripheralUuid = 'peripheralUuid';
1021
+ const serviceUuid = 'serviceUuid';
1022
+ const characteristics = ['characteristic1', 'characteristic2'];
1023
+
1024
+ noble.on('warning', warningCallback);
1025
+
1026
+ noble._services[peripheralUuid] = {};
1027
+ noble.onCharacteristicsDiscover(peripheralUuid, serviceUuid, characteristics);
1028
+
1029
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral peripheralUuid, serviceUuid characteristics discover!');
1030
+ });
1031
+
1032
+ it('should emit characteristicsDiscover and store characteristics', () => {
1033
+ const warningCallback = sinon.spy();
1034
+ const emit = sinon.spy();
1035
+
1036
+ const peripheralUuid = 'peripheralUuid';
1037
+ const serviceUuid = 'serviceUuid';
1038
+ const characteristics = [
1039
+ { uuid: 'characteristic1', properties: 'properties1' },
1040
+ { uuid: 'characteristic2', properties: 'properties2' }
1041
+ ];
1042
+
1043
+ noble._services = { [peripheralUuid]: { [serviceUuid]: { emit } } };
1044
+ noble._characteristics = { [peripheralUuid]: { [serviceUuid]: {} } };
1045
+ noble._descriptors = { [peripheralUuid]: { [serviceUuid]: {} } };
1046
+
1047
+ noble.on('warning', warningCallback);
1048
+
1049
+ noble.onCharacteristicsDiscover(peripheralUuid, serviceUuid, characteristics);
1050
+
1051
+ const expectedCharacteristics = [
1052
+ new Characteristic(noble, peripheralUuid, serviceUuid, characteristics[0].uuid, characteristics[0].properties),
1053
+ new Characteristic(noble, peripheralUuid, serviceUuid, characteristics[1].uuid, characteristics[1].properties)
1054
+ ];
1055
+
1056
+ assert.calledOnceWithExactly(emit, 'characteristicsDiscover', expectedCharacteristics);
1057
+ assert.notCalled(warningCallback);
1058
+
1059
+ should(noble._services).deepEqual({
1060
+ [peripheralUuid]: {
1061
+ [serviceUuid]: {
1062
+ emit, characteristics: expectedCharacteristics
1063
+ }
1064
+ }
1065
+ });
1066
+ should(noble._characteristics).deepEqual({
1067
+ [peripheralUuid]: {
1068
+ [serviceUuid]: { characteristic1: expectedCharacteristics[0], characteristic2: expectedCharacteristics[1] }
1069
+ }
1070
+ });
1071
+ should(noble._descriptors).deepEqual({
1072
+ [peripheralUuid]: { [serviceUuid]: { characteristic1: {}, characteristic2: {} } }
1073
+ });
1074
+ });
1075
+ });
1076
+
1077
+ it('read - should delegate to bindings', () => {
1078
+ noble._bindings.read = sinon.spy();
1079
+ noble.read('peripheralUuid', 'serviceUuid', 'characteristicUuid');
1080
+ assert.calledOnceWithExactly(noble._bindings.read, 'peripheralUuid', 'serviceUuid', 'characteristicUuid');
1081
+ });
1082
+
1083
+ describe('onRead', () => {
1084
+ it('should emit warning', () => {
1085
+ const warningCallback = sinon.spy();
1086
+ noble.on('warning', warningCallback);
1087
+
1088
+ noble._characteristics = {
1089
+ peripheralUuid: {
1090
+ serviceUuid: {
1091
+ }
1092
+ }
1093
+ };
1094
+ noble.onRead('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'data', 'isNotification');
1095
+
1096
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral peripheralUuid, serviceUuid, characteristicUuid read!');
1097
+ });
1098
+
1099
+ it('should emit data and read', () => {
1100
+ const warningCallback = sinon.spy();
1101
+ const emit = sinon.spy();
1102
+
1103
+ noble.on('warning', warningCallback);
1104
+
1105
+ noble._characteristics = {
1106
+ peripheralUuid: {
1107
+ serviceUuid: {
1108
+ characteristicUuid: {
1109
+ emit
1110
+ }
1111
+ }
1112
+ }
1113
+ };
1114
+ noble.onRead('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'dataArg', 'isNotification');
1115
+
1116
+ assert.notCalled(warningCallback);
1117
+ assert.callCount(emit, 2);
1118
+ assert.calledWithExactly(emit, 'data', 'dataArg', 'isNotification');
1119
+ assert.calledWithExactly(emit, 'read', 'dataArg', 'isNotification');
1120
+ });
1121
+ });
1122
+
1123
+ it('write - should delegate to bindings', () => {
1124
+ noble._bindings.write = sinon.spy();
1125
+ noble.write('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'dataArg', 'isNotification');
1126
+ assert.calledOnceWithExactly(noble._bindings.write, 'peripheralUuid', 'serviceUuid', 'characteristicUuid', 'dataArg', 'isNotification');
1127
+ });
1128
+
1129
+ describe('onWrite', () => {
1130
+ it('should emit warning', () => {
1131
+ const warningCallback = sinon.spy();
1132
+ noble.on('warning', warningCallback);
1133
+
1134
+ noble._characteristics = {
1135
+ peripheralUuid: {
1136
+ serviceUuid: {
1137
+ }
1138
+ }
1139
+ };
1140
+ noble.onWrite('peripheralUuid', 'serviceUuid', 'characteristicUuid');
1141
+
1142
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral peripheralUuid, serviceUuid, characteristicUuid write!');
1143
+ });
1144
+
1145
+ it('should emit write', () => {
1146
+ const warningCallback = sinon.spy();
1147
+ const emit = sinon.spy();
1148
+
1149
+ noble.on('warning', warningCallback);
1150
+
1151
+ noble._characteristics = {
1152
+ peripheralUuid: {
1153
+ serviceUuid: {
1154
+ characteristicUuid: {
1155
+ emit
1156
+ }
1157
+ }
1158
+ }
1159
+ };
1160
+ noble.onWrite('peripheralUuid', 'serviceUuid', 'characteristicUuid');
1161
+
1162
+ assert.notCalled(warningCallback);
1163
+ assert.calledOnceWithExactly(emit, 'write');
1164
+ });
1165
+ });
1166
+
1167
+ it('broadcast - should delegate to bindings', () => {
1168
+ noble._bindings.broadcast = sinon.spy();
1169
+ noble.broadcast('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'broadcast');
1170
+ assert.calledOnceWithExactly(noble._bindings.broadcast, 'peripheralUuid', 'serviceUuid', 'characteristicUuid', 'broadcast');
1171
+ });
1172
+
1173
+ describe('onBroadcast', () => {
1174
+ it('should emit warning', () => {
1175
+ const warningCallback = sinon.spy();
1176
+ noble.on('warning', warningCallback);
1177
+
1178
+ noble._characteristics = {
1179
+ peripheralUuid: {
1180
+ serviceUuid: {
1181
+ }
1182
+ }
1183
+ };
1184
+ noble.onBroadcast('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'state');
1185
+
1186
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral peripheralUuid, serviceUuid, characteristicUuid broadcast!');
1187
+ });
1188
+
1189
+ it('should emit broadcast', () => {
1190
+ const warningCallback = sinon.spy();
1191
+ const emit = sinon.spy();
1192
+
1193
+ noble.on('warning', warningCallback);
1194
+
1195
+ noble._characteristics = {
1196
+ peripheralUuid: {
1197
+ serviceUuid: {
1198
+ characteristicUuid: {
1199
+ emit
1200
+ }
1201
+ }
1202
+ }
1203
+ };
1204
+ noble.onBroadcast('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'state');
1205
+
1206
+ assert.notCalled(warningCallback);
1207
+ assert.calledOnceWithExactly(emit, 'broadcast', 'state');
1208
+ });
1209
+ });
1210
+
1211
+ it('notify - should delegate to bindings', () => {
1212
+ noble._bindings.notify = sinon.spy();
1213
+ noble.notify('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'notify');
1214
+ assert.calledOnceWithExactly(noble._bindings.notify, 'peripheralUuid', 'serviceUuid', 'characteristicUuid', 'notify');
1215
+ });
1216
+
1217
+ describe('onNotify', () => {
1218
+ it('should emit warning', () => {
1219
+ const warningCallback = sinon.spy();
1220
+ noble.on('warning', warningCallback);
1221
+
1222
+ noble._characteristics = {
1223
+ peripheralUuid: {
1224
+ serviceUuid: {
1225
+ }
1226
+ }
1227
+ };
1228
+ noble.onNotify('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'state');
1229
+
1230
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral peripheralUuid, serviceUuid, characteristicUuid notify!');
1231
+ });
1232
+
1233
+ it('should emit notify', () => {
1234
+ const warningCallback = sinon.spy();
1235
+ const emit = sinon.spy();
1236
+
1237
+ noble.on('warning', warningCallback);
1238
+
1239
+ noble._characteristics = {
1240
+ peripheralUuid: {
1241
+ serviceUuid: {
1242
+ characteristicUuid: {
1243
+ emit
1244
+ }
1245
+ }
1246
+ }
1247
+ };
1248
+ noble.onNotify('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'state');
1249
+
1250
+ assert.notCalled(warningCallback);
1251
+ assert.calledOnceWithExactly(emit, 'notify', 'state');
1252
+ });
1253
+ });
1254
+
1255
+ it('discoverDescriptors - should delegate', () => {
1256
+ noble._bindings.discoverDescriptors = sinon.spy();
1257
+
1258
+ noble.discoverDescriptors('peripheralUuid', 'serviceUuid', 'characteristicUuid');
1259
+
1260
+ assert.calledOnceWithExactly(noble._bindings.discoverDescriptors, 'peripheralUuid', 'serviceUuid', 'characteristicUuid');
1261
+ });
1262
+
1263
+ describe('onDescriptorsDiscover', () => {
1264
+ it('should emit warning', () => {
1265
+ const warningCallback = sinon.spy();
1266
+
1267
+ const peripheralUuid = 'peripheralUuid';
1268
+ const serviceUuid = 'serviceUuid';
1269
+ const characteristicUuid = 'characteristicUuid';
1270
+ const descriptors = ['descriptor1', 'descriptor2'];
1271
+
1272
+ noble.on('warning', warningCallback);
1273
+
1274
+ noble._characteristics[peripheralUuid] = {
1275
+ [serviceUuid]: {}
1276
+ };
1277
+ noble.onDescriptorsDiscover(peripheralUuid, serviceUuid, characteristicUuid, descriptors);
1278
+
1279
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral peripheralUuid, serviceUuid, characteristicUuid descriptors discover!');
1280
+ });
1281
+
1282
+ it('should emit characteristicsDiscover and store characteristics', () => {
1283
+ const warningCallback = sinon.spy();
1284
+ const emit = sinon.spy();
1285
+
1286
+ const peripheralUuid = 'peripheralUuid';
1287
+ const serviceUuid = 'serviceUuid';
1288
+ const characteristicUuid = 'characteristicUuid';
1289
+ const descriptors = ['descriptor1', 'descriptor2'];
1290
+
1291
+ noble._characteristics = { [peripheralUuid]: { [serviceUuid]: { [characteristicUuid]: { emit } } } };
1292
+ noble._descriptors = { [peripheralUuid]: { [serviceUuid]: { [characteristicUuid]: {} } } };
1293
+
1294
+ noble.on('warning', warningCallback);
1295
+
1296
+ noble.onDescriptorsDiscover(peripheralUuid, serviceUuid, characteristicUuid, descriptors);
1297
+
1298
+ const expectedDescriptors = [
1299
+ new Descriptor(noble, peripheralUuid, serviceUuid, characteristicUuid, descriptors[0]),
1300
+ new Descriptor(noble, peripheralUuid, serviceUuid, characteristicUuid, descriptors[1])
1301
+ ];
1302
+
1303
+ assert.calledOnceWithExactly(emit, 'descriptorsDiscover', expectedDescriptors);
1304
+ assert.notCalled(warningCallback);
1305
+
1306
+ should(noble._characteristics).deepEqual({
1307
+ [peripheralUuid]: { [serviceUuid]: { [characteristicUuid]: { emit, descriptors: expectedDescriptors } } }
1308
+ });
1309
+ should(noble._descriptors).deepEqual({
1310
+ [peripheralUuid]: { [serviceUuid]: { [characteristicUuid]: { descriptor1: expectedDescriptors[0], descriptor2: expectedDescriptors[1] } } }
1311
+ });
1312
+ });
1313
+ });
1314
+
1315
+ it('readValue - should delegate to bindings', () => {
1316
+ noble._bindings.readValue = sinon.spy();
1317
+ noble.readValue('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'descriptorUuid');
1318
+ assert.calledOnceWithExactly(noble._bindings.readValue, 'peripheralUuid', 'serviceUuid', 'characteristicUuid', 'descriptorUuid');
1319
+ });
1320
+
1321
+ describe('onValueRead', () => {
1322
+ it('should emit warning', () => {
1323
+ const warningCallback = sinon.spy();
1324
+ noble.on('warning', warningCallback);
1325
+
1326
+ noble._descriptors = {
1327
+ peripheralUuid: {
1328
+ serviceUuid: {
1329
+ characteristicUuid: {}
1330
+ }
1331
+ }
1332
+ };
1333
+ noble.onValueRead('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'descriptorUuid', 'data');
1334
+
1335
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid value read!');
1336
+ });
1337
+
1338
+ it('should emit valueRead', () => {
1339
+ const warningCallback = sinon.spy();
1340
+ const emit = sinon.spy();
1341
+
1342
+ noble.on('warning', warningCallback);
1343
+
1344
+ noble._descriptors = {
1345
+ peripheralUuid: {
1346
+ serviceUuid: {
1347
+ characteristicUuid: {
1348
+ descriptorUuid: {
1349
+ emit
1350
+ }
1351
+ }
1352
+ }
1353
+ }
1354
+ };
1355
+ noble.onValueRead('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'descriptorUuid', 'data');
1356
+
1357
+ assert.notCalled(warningCallback);
1358
+ assert.calledOnceWithExactly(emit, 'valueRead', 'data');
1359
+ });
1360
+ });
1361
+
1362
+ it('writeValue - should delegate to bindings', () => {
1363
+ noble._bindings.writeValue = sinon.spy();
1364
+ noble.writeValue('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'descriptorUuid', 'data');
1365
+ assert.calledOnceWithExactly(noble._bindings.writeValue, 'peripheralUuid', 'serviceUuid', 'characteristicUuid', 'descriptorUuid', 'data');
1366
+ });
1367
+
1368
+ describe('onValueWrite', () => {
1369
+ it('should emit warning', () => {
1370
+ const warningCallback = sinon.spy();
1371
+ noble.on('warning', warningCallback);
1372
+
1373
+ noble._descriptors = {
1374
+ peripheralUuid: {
1375
+ serviceUuid: {
1376
+ characteristicUuid: {}
1377
+ }
1378
+ }
1379
+ };
1380
+ noble.onValueWrite('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'descriptorUuid');
1381
+
1382
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid value write!');
1383
+ });
1384
+
1385
+ it('should emit valueWrite', () => {
1386
+ const warningCallback = sinon.spy();
1387
+ const emit = sinon.spy();
1388
+
1389
+ noble.on('warning', warningCallback);
1390
+
1391
+ noble._descriptors = {
1392
+ peripheralUuid: {
1393
+ serviceUuid: {
1394
+ characteristicUuid: {
1395
+ descriptorUuid: {
1396
+ emit
1397
+ }
1398
+ }
1399
+ }
1400
+ }
1401
+ };
1402
+ noble.onValueWrite('peripheralUuid', 'serviceUuid', 'characteristicUuid', 'descriptorUuid');
1403
+
1404
+ assert.notCalled(warningCallback);
1405
+ assert.calledOnceWithExactly(emit, 'valueWrite');
1406
+ });
1407
+ });
1408
+
1409
+ it('readHandle - should delegate to bindings', () => {
1410
+ noble._bindings.readHandle = sinon.spy();
1411
+ noble.readHandle('peripheralUuid', 'handle');
1412
+ assert.calledOnceWithExactly(noble._bindings.readHandle, 'peripheralUuid', 'handle');
1413
+ });
1414
+
1415
+ describe('onHandleRead', () => {
1416
+ it('should emit warning', () => {
1417
+ const warningCallback = sinon.spy();
1418
+ noble.on('warning', warningCallback);
1419
+
1420
+ noble._peripherals = {
1421
+ };
1422
+ noble.onHandleRead('peripheralUuid', 'nameOfHandle', 'data');
1423
+
1424
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral peripheralUuid handle read!');
1425
+ });
1426
+
1427
+ it('should emit handleWrite', () => {
1428
+ const warningCallback = sinon.spy();
1429
+ const emit = sinon.spy();
1430
+
1431
+ noble.on('warning', warningCallback);
1432
+
1433
+ noble._peripherals = {
1434
+ peripheralUuid: {
1435
+ emit
1436
+ }
1437
+ };
1438
+ noble.onHandleRead('peripheralUuid', 'nameOfHandle', 'data');
1439
+
1440
+ assert.notCalled(warningCallback);
1441
+ assert.calledOnceWithExactly(emit, 'handleReadnameOfHandle', 'data');
1442
+ });
1443
+ });
1444
+
1445
+ it('writeHandle - should delegate to bindings', () => {
1446
+ noble._bindings.writeHandle = sinon.spy();
1447
+ noble.writeHandle('peripheralUuid', 'handle', 'data', 'withoutResponse');
1448
+ assert.calledOnceWithExactly(noble._bindings.writeHandle, 'peripheralUuid', 'handle', 'data', 'withoutResponse');
1449
+ });
1450
+
1451
+ describe('onHandleWrite', () => {
1452
+ it('should emit warning', () => {
1453
+ const warningCallback = sinon.spy();
1454
+ noble.on('warning', warningCallback);
1455
+
1456
+ noble._peripherals = {
1457
+ };
1458
+ noble.onHandleWrite('peripheralUuid', 'nameOfHandle');
1459
+
1460
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral peripheralUuid handle write!');
1461
+ });
1462
+
1463
+ it('should emit handleRead', () => {
1464
+ const warningCallback = sinon.spy();
1465
+ const emit = sinon.spy();
1466
+
1467
+ noble.on('warning', warningCallback);
1468
+
1469
+ noble._peripherals = {
1470
+ peripheralUuid: {
1471
+ emit
1472
+ }
1473
+ };
1474
+ noble.onHandleWrite('peripheralUuid', 'nameOfHandle');
1475
+
1476
+ assert.notCalled(warningCallback);
1477
+ assert.calledOnceWithExactly(emit, 'handleWritenameOfHandle');
1478
+ });
1479
+ });
1480
+
1481
+ describe('onHandleNotify', () => {
1482
+ it('should emit warning', () => {
1483
+ const warningCallback = sinon.spy();
1484
+ noble.on('warning', warningCallback);
1485
+
1486
+ noble._peripherals = {
1487
+ };
1488
+ noble.onHandleNotify('peripheralUuid', 'nameOfHandle', 'data');
1489
+
1490
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral peripheralUuid handle notify!');
1491
+ });
1492
+
1493
+ it('should emit handleNotify', () => {
1494
+ const warningCallback = sinon.spy();
1495
+ const emit = sinon.spy();
1496
+
1497
+ noble.on('warning', warningCallback);
1498
+
1499
+ noble._peripherals = {
1500
+ peripheralUuid: {
1501
+ emit
1502
+ }
1503
+ };
1504
+ noble.onHandleNotify('peripheralUuid', 'nameOfHandle', 'data');
1505
+
1506
+ assert.notCalled(warningCallback);
1507
+ assert.calledOnceWithExactly(emit, 'handleNotify', 'nameOfHandle', 'data');
1508
+ });
1509
+ });
1510
+
1511
+ it('onMtu - should update peripheral mtu', () => {
1512
+ const peripheral = {
1513
+ mtu: 'nan'
1514
+ };
1515
+
1516
+ noble._peripherals = { uuid: peripheral };
1517
+ noble.onMtu('uuid', 'mtu');
1518
+
1519
+ should(peripheral).deepEqual({ mtu: 'mtu' });
1520
+ });
1521
+
1522
+ it('onMtu - should not update peripheral mtu', () => {
1523
+ const peripheral = {
1524
+ };
1525
+
1526
+ noble._peripherals = { uuid: peripheral };
1527
+ noble.onMtu('uuid', 'mtu');
1528
+
1529
+ should(peripheral).deepEqual({ });
1530
+ });
1531
+
1532
+ describe('onIncludedServicesDiscover', () => {
1533
+ it('should emit connected on existing peripheral', () => {
1534
+ const emit = sinon.spy();
1535
+ noble._services = {
1536
+ uuid: { serviceUuid: { emit } }
1537
+ };
1538
+
1539
+ const warningCallback = sinon.spy();
1540
+
1541
+ noble.on('warning', warningCallback);
1542
+ noble.onIncludedServicesDiscover('uuid', 'serviceUuid', 'serviceUuids');
1543
+
1544
+ assert.calledOnceWithExactly(emit, 'includedServicesDiscover', 'serviceUuids');
1545
+ assert.notCalled(warningCallback);
1546
+
1547
+ should(noble._services).deepEqual({
1548
+ uuid: { serviceUuid: { includedServiceUuids: 'serviceUuids', emit } }
1549
+ });
1550
+ });
1551
+
1552
+ it('should emit warning on missing peripheral', () => {
1553
+ noble._services = { uuid: {} };
1554
+
1555
+ const warningCallback = sinon.spy();
1556
+
1557
+ noble.on('warning', warningCallback);
1558
+ noble.onIncludedServicesDiscover('uuid', 'serviceUuid', 'serviceUuids');
1559
+
1560
+ assert.calledOnceWithExactly(warningCallback, 'unknown peripheral uuid, serviceUuid included services discover!');
1561
+
1562
+ should(noble._services).deepEqual({ uuid: {} });
1563
+ });
1564
+ });
1565
+ });