@stoprocent/noble 1.19.0 → 2.0.0

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 (97) hide show
  1. package/README.md +393 -650
  2. package/examples/advertisement-discovery.js +57 -48
  3. package/examples/connect-address.js +59 -34
  4. package/examples/echo.js +59 -69
  5. package/examples/enter-exit.js +55 -49
  6. package/examples/multiple-bindings.js +53 -0
  7. package/examples/peripheral-explorer-async.js +39 -21
  8. package/examples/peripheral-explorer.ts +52 -0
  9. package/index.d.ts +249 -209
  10. package/index.js +4 -1
  11. package/jest.config.js +4 -0
  12. package/lib/characteristic.js +153 -127
  13. package/lib/{win/src/callbacks.h → common/include/Emit.h} +17 -14
  14. package/lib/common/include/Peripheral.h +31 -0
  15. package/lib/common/include/ThreadSafeCallback.h +95 -0
  16. package/lib/{win/src/callbacks.cc → common/src/Emit.cc} +111 -68
  17. package/lib/descriptor.js +57 -54
  18. package/lib/hci-socket/acl-stream.js +2 -4
  19. package/lib/hci-socket/bindings.js +96 -73
  20. package/lib/hci-socket/gap.js +2 -3
  21. package/lib/hci-socket/gatt.js +2 -5
  22. package/lib/hci-socket/hci.js +19 -7
  23. package/lib/hci-socket/signaling.js +2 -3
  24. package/lib/hci-socket/smp.js +2 -3
  25. package/lib/hci-socket/vs.js +1 -0
  26. package/lib/mac/binding.gyp +5 -7
  27. package/lib/mac/bindings.js +1 -3
  28. package/lib/mac/src/ble_manager.h +1 -8
  29. package/lib/mac/src/ble_manager.mm +87 -44
  30. package/lib/mac/src/napi_objc.h +1 -0
  31. package/lib/mac/src/napi_objc.mm +0 -6
  32. package/lib/mac/src/noble_mac.h +5 -3
  33. package/lib/mac/src/noble_mac.mm +99 -57
  34. package/lib/mac/src/objc_cpp.h +3 -2
  35. package/lib/mac/src/objc_cpp.mm +0 -6
  36. package/lib/noble.js +579 -488
  37. package/lib/peripheral.js +171 -174
  38. package/lib/resolve-bindings.js +37 -30
  39. package/lib/service.js +58 -55
  40. package/lib/win/binding.gyp +4 -11
  41. package/lib/win/bindings.js +1 -3
  42. package/lib/win/src/ble_manager.cc +291 -166
  43. package/lib/win/src/ble_manager.h +11 -13
  44. package/lib/win/src/napi_winrt.cc +1 -7
  45. package/lib/win/src/napi_winrt.h +1 -1
  46. package/lib/win/src/noble_winrt.cc +88 -61
  47. package/lib/win/src/noble_winrt.h +5 -3
  48. package/lib/win/src/notify_map.cc +0 -7
  49. package/lib/win/src/notify_map.h +1 -8
  50. package/lib/win/src/peripheral_winrt.cc +29 -11
  51. package/lib/win/src/peripheral_winrt.h +1 -1
  52. package/lib/win/src/radio_watcher.cc +79 -69
  53. package/lib/win/src/radio_watcher.h +30 -11
  54. package/lib/win/src/winrt_cpp.cc +1 -1
  55. package/lib/win/src/winrt_cpp.h +3 -0
  56. package/package.json +14 -17
  57. package/prebuilds/darwin-x64+arm64/@stoprocent+noble.node +0 -0
  58. package/prebuilds/win32-ia32/@stoprocent+noble.node +0 -0
  59. package/prebuilds/win32-x64/@stoprocent+noble.node +0 -0
  60. package/test/lib/characteristic.test.js +202 -322
  61. package/test/lib/descriptor.test.js +62 -95
  62. package/test/lib/hci-socket/acl-stream.test.js +112 -108
  63. package/test/lib/hci-socket/bindings.test.js +576 -365
  64. package/test/lib/hci-socket/hci.test.js +442 -473
  65. package/test/lib/hci-socket/signaling.test.js +45 -48
  66. package/test/lib/hci-socket/smp.test.js +144 -142
  67. package/test/lib/hci-socket/vs.test.js +193 -18
  68. package/test/lib/peripheral.test.js +492 -322
  69. package/test/lib/resolve-bindings.test.js +207 -82
  70. package/test/lib/service.test.js +79 -88
  71. package/test/noble.test.js +381 -1085
  72. package/.editorconfig +0 -11
  73. package/.nycrc.json +0 -4
  74. package/codecov.yml +0 -5
  75. package/examples/cache-gatt-discovery.js +0 -198
  76. package/examples/cache-gatt-reconnect.js +0 -164
  77. package/examples/ext-advertisement-discovery.js +0 -65
  78. package/examples/peripheral-explorer.js +0 -225
  79. package/examples/pizza/central.js +0 -194
  80. package/examples/pizza/pizza.js +0 -60
  81. package/examples/test/test.custom.js +0 -131
  82. package/examples/uart-bind-params.js +0 -28
  83. package/lib/distributed/bindings.js +0 -326
  84. package/lib/mac/src/callbacks.cc +0 -222
  85. package/lib/mac/src/callbacks.h +0 -84
  86. package/lib/mac/src/peripheral.h +0 -23
  87. package/lib/resolve-bindings-web.js +0 -9
  88. package/lib/webbluetooth/bindings.js +0 -368
  89. package/lib/websocket/bindings.js +0 -321
  90. package/lib/win/src/peripheral.h +0 -23
  91. package/test/lib/distributed/bindings.test.js +0 -918
  92. package/test/lib/webbluetooth/bindings.test.js +0 -190
  93. package/test/lib/websocket/bindings.test.js +0 -456
  94. package/test/mocha.setup.js +0 -0
  95. package/with-bindings.js +0 -5
  96. package/with-custom-binding.js +0 -6
  97. package/ws-slave.js +0 -404
@@ -6,25 +6,33 @@ const { assert } = sinon;
6
6
 
7
7
  describe('hci-socket hci', () => {
8
8
  const deviceId = 'deviceId';
9
- const Socket = sinon.stub();
9
+ const mockSocket = sinon.stub();
10
10
 
11
- const Hci = proxyquire('../../../lib/hci-socket/hci', {
12
- '@stoprocent/bluetooth-hci-socket': Socket
13
- });
11
+ // Mock the crypto module
12
+ jest.mock('os', () => ({
13
+ platform: () => 'linux',
14
+ release: () => '5.10.0-11-amd64'
15
+ }));
16
+
17
+ jest.mock('@stoprocent/bluetooth-hci-socket', () => ({
18
+ loadDriver: () => mockSocket
19
+ }));
20
+
21
+ const Hci = require('../../../lib/hci-socket/hci');
14
22
 
15
23
  let hci;
16
24
 
17
25
  beforeEach(() => {
18
- Socket.prototype.on = sinon.stub();
19
- Socket.prototype.bindUser = sinon.stub();
20
- Socket.prototype.bindRaw = sinon.stub();
21
- Socket.prototype.start = sinon.stub();
22
- Socket.prototype.isDevUp = sinon.stub();
23
- Socket.prototype.removeAllListeners = sinon.stub();
24
- Socket.prototype.setFilter = sinon.stub();
25
- Socket.prototype.setAddress = sinon.stub();
26
- Socket.prototype.write = sinon.stub();
27
-
26
+ mockSocket.prototype.on = sinon.stub();
27
+ mockSocket.prototype.bindUser = sinon.stub();
28
+ mockSocket.prototype.bindRaw = sinon.stub();
29
+ mockSocket.prototype.start = sinon.stub();
30
+ mockSocket.prototype.isDevUp = sinon.stub();
31
+ mockSocket.prototype.removeAllListeners = sinon.stub();
32
+ mockSocket.prototype.setFilter = sinon.stub();
33
+ mockSocket.prototype.setAddress = sinon.stub();
34
+ mockSocket.prototype.write = sinon.stub();
35
+
28
36
  hci = new Hci({});
29
37
  hci._deviceId = deviceId;
30
38
  });
@@ -567,6 +575,7 @@ describe('hci-socket hci', () => {
567
575
  });
568
576
 
569
577
  describe('onSocketData', () => {
578
+ // Define the standard ACL queue used in tests
570
579
  const aclQueue = [
571
580
  {
572
581
  handle: 4660,
@@ -581,573 +590,526 @@ describe('hci-socket hci', () => {
581
590
  packet: Buffer.from([0x02])
582
591
  }
583
592
  ];
584
-
593
+
594
+ // Event callback mocks
585
595
  let disconnCompleteCallback;
586
596
  let encryptChangeCallback;
587
597
  let aclDataPktCallback;
588
598
  let leScanEnableSetCmdCallback;
589
-
599
+
590
600
  beforeEach(() => {
591
- hci.flushAcl = sinon.spy();
592
- hci.processCmdCompleteEvent = sinon.spy();
593
- hci.processCmdStatusEvent = sinon.spy();
594
- hci.processLeMetaEvent = sinon.spy();
595
-
601
+ // Setup spies on HCI methods - preserve actual implementation
602
+ jest.spyOn(hci, 'flushAcl');
603
+ jest.spyOn(hci, 'processCmdCompleteEvent');
604
+ jest.spyOn(hci, 'processCmdStatusEvent');
605
+
606
+ hci.processLeMetaEvent = jest.fn();
607
+
608
+ // Suppress console.warn
609
+ jest.spyOn(console, 'warn').mockImplementation(() => {});
610
+
611
+ // Setup HCI's internal state for testing
596
612
  hci._aclQueue = [...aclQueue];
613
+ hci._aclConnections = new Map();
597
614
  hci._aclConnections.set(4660, { pending: 3 });
598
615
  hci._aclConnections.set(4661, { pending: 2 });
599
-
600
- disconnCompleteCallback = sinon.spy();
601
- encryptChangeCallback = sinon.spy();
602
- aclDataPktCallback = sinon.spy();
603
- leScanEnableSetCmdCallback = sinon.spy();
616
+ hci._handleBuffers = {};
617
+
618
+ // Setup event listener callbacks as mocks
619
+ disconnCompleteCallback = jest.fn();
620
+ encryptChangeCallback = jest.fn();
621
+ aclDataPktCallback = jest.fn();
622
+ leScanEnableSetCmdCallback = jest.fn();
623
+
624
+ // Register event handlers
604
625
  hci.on('disconnComplete', disconnCompleteCallback);
605
626
  hci.on('encryptChange', encryptChangeCallback);
606
627
  hci.on('aclDataPkt', aclDataPktCallback);
607
628
  hci.on('leScanEnableSetCmd', leScanEnableSetCmdCallback);
608
629
  });
609
-
630
+
610
631
  afterEach(() => {
611
- sinon.reset();
632
+ // Clear all mocks between tests
633
+ jest.restoreAllMocks();
612
634
  });
613
-
614
- it('should flushAcl - HCI_EVENT_PKT / EVT_DISCONN_COMPLETE', () => {
635
+
636
+ test('should flushAcl - HCI_EVENT_PKT / EVT_DISCONN_COMPLETE', () => {
615
637
  const eventType = 4;
616
638
  const subEventType = 5;
617
639
  const data = Buffer.from([eventType, subEventType, 0, 0, 0x34, 0x12, 3]);
618
-
640
+
619
641
  hci.onSocketData(data);
620
-
621
- // called
622
- assert.calledOnceWithExactly(hci.flushAcl);
623
- assert.calledOnceWithExactly(disconnCompleteCallback, 4660, 3);
624
-
625
- // not called
626
- assert.notCalled(hci.processCmdCompleteEvent);
627
- assert.notCalled(hci.processLeMetaEvent);
628
- assert.notCalled(encryptChangeCallback);
629
- assert.notCalled(aclDataPktCallback);
630
- assert.notCalled(leScanEnableSetCmdCallback);
631
-
632
- // hci checks
633
- should(hci._aclQueue).deepEqual([
642
+
643
+ // Called
644
+ expect(hci.flushAcl).toHaveBeenCalledTimes(1);
645
+ expect(disconnCompleteCallback).toHaveBeenCalledWith(4660, 3);
646
+
647
+ // Not called
648
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
649
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
650
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
651
+ expect(aclDataPktCallback).not.toHaveBeenCalled();
652
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
653
+
654
+ // HCI state checks
655
+ expect(hci._aclQueue).toEqual([
634
656
  {
635
657
  handle: 4661,
636
658
  packet: Buffer.from([0x02])
637
659
  }
638
660
  ]);
639
- should(hci._aclConnections).have.keys(4661);
640
- should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
661
+ expect(Array.from(hci._aclConnections.keys())).toEqual([4661]);
662
+ expect(hci._aclConnections.get(4661)).toEqual({ pending: 2 });
641
663
  });
642
-
643
- it('should only emit encryptChange - HCI_EVENT_PKT / EVT_ENCRYPT_CHANGE', () => {
664
+
665
+ test('should only emit encryptChange - HCI_EVENT_PKT / EVT_ENCRYPT_CHANGE', () => {
644
666
  const eventType = 4;
645
667
  const subEventType = 8;
646
668
  const data = Buffer.from([eventType, subEventType, 0, 0, 0x34, 0x12, 3]);
647
669
  hci.onSocketData(data);
648
-
649
- // called
650
- assert.calledOnceWithExactly(encryptChangeCallback, 4660, 3);
651
-
652
- // not called
653
- assert.notCalled(hci.flushAcl);
654
- assert.notCalled(hci.processCmdCompleteEvent);
655
- assert.notCalled(hci.processLeMetaEvent);
656
- assert.notCalled(disconnCompleteCallback);
657
- assert.notCalled(aclDataPktCallback);
658
- assert.notCalled(leScanEnableSetCmdCallback);
659
-
660
- // hci checks
661
- should(hci._aclQueue).deepEqual(aclQueue);
662
- should(hci._aclConnections).have.keys(4660, 4661);
663
- should(hci._aclConnections.get(4660)).deepEqual({ pending: 3 });
664
- should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
665
- });
666
-
667
- it('should only processCmdCompleteEvent - HCI_EVENT_PKT / EVT_CMD_COMPLETE', () => {
670
+
671
+ // Called
672
+ expect(encryptChangeCallback).toHaveBeenCalledWith(4660, 3);
673
+
674
+ // Not called
675
+ expect(hci.flushAcl).not.toHaveBeenCalled();
676
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
677
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
678
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
679
+ expect(aclDataPktCallback).not.toHaveBeenCalled();
680
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
681
+
682
+ // HCI state checks
683
+ expect(hci._aclQueue).toEqual(aclQueue);
684
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
685
+ expect(hci._aclConnections.get(4660)).toEqual({ pending: 3 });
686
+ expect(hci._aclConnections.get(4661)).toEqual({ pending: 2 });
687
+ });
688
+
689
+ test('should only processCmdCompleteEvent - HCI_EVENT_PKT / EVT_CMD_COMPLETE', () => {
668
690
  const eventType = 4;
669
691
  const subEventType = 14;
670
692
  const data = Buffer.from([eventType, subEventType, 0, 0, 0x34, 0x12, 3, 9, 9]);
671
- hci.onSocketData(data);
672
-
673
- // called
674
- assert.calledOnceWithExactly(hci.processCmdCompleteEvent, 4660, 3, Buffer.from([9, 9]));
675
-
676
- // not called
677
- assert.notCalled(hci.flushAcl);
678
- assert.notCalled(encryptChangeCallback);
679
- assert.notCalled(hci.processLeMetaEvent);
680
- assert.notCalled(disconnCompleteCallback);
681
- assert.notCalled(aclDataPktCallback);
682
- assert.notCalled(leScanEnableSetCmdCallback);
683
-
684
- // hci checks
685
- should(hci._aclQueue).deepEqual(aclQueue);
686
- should(hci._aclConnections).have.keys(4660, 4661);
687
- should(hci._aclConnections.get(4660)).deepEqual({ pending: 3 });
688
- should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
689
-
690
- describe('LE_READ_LOCAL_SUPPORTED_FEATURES', () => {
691
- beforeEach(() => {
692
- hci.setCodedPhySupport = sinon.spy();
693
- hci.setEventMask = sinon.spy();
694
- hci.setLeEventMask = sinon.spy();
695
- hci.readLocalVersion = sinon.spy();
696
- hci.writeLeHostSupported = sinon.spy();
697
- hci.readLeHostSupported = sinon.spy();
698
- hci.readLeBufferSize = sinon.spy();
699
- hci.readBdAddr = sinon.spy();
700
- });
701
-
702
- it('should not process on error status', () => {
703
- const cmd = 8195;
704
- const status = 1;
705
- const result = Buffer.from([0x00, 0x00, 0x00, 0x00]);
706
-
707
- hci.processCmdCompleteEvent(cmd, status, result);
708
-
709
- // Verify no methods were called
710
- assert.notCalled(hci.setCodedPhySupport);
711
- assert.notCalled(hci.setEventMask);
712
- assert.notCalled(hci.setLeEventMask);
713
- assert.notCalled(hci.readLocalVersion);
714
- assert.notCalled(hci.writeLeHostSupported);
715
- assert.notCalled(hci.readLeHostSupported);
716
- assert.notCalled(hci.readLeBufferSize);
717
- assert.notCalled(hci.readBdAddr);
718
693
 
719
- should(hci._isExtended).equal(false);
720
- });
721
-
722
- it('should process without extended features', () => {
723
- const cmd = 8195;
724
- const status = 0;
725
- const result = Buffer.from([0x00, 0x00, 0x00, 0x00]); // No bits set
726
-
727
- hci.processCmdCompleteEvent(cmd, status, result);
728
-
729
- // Verify extended-specific method not called
730
- assert.notCalled(hci.setCodedPhySupport);
731
-
732
- // Verify other methods were called
733
- assert.calledOnce(hci.setEventMask);
734
- assert.calledOnce(hci.setLeEventMask);
735
- assert.calledOnce(hci.readLocalVersion);
736
- assert.calledOnce(hci.writeLeHostSupported);
737
- assert.calledOnce(hci.readLeHostSupported);
738
- assert.calledOnce(hci.readLeBufferSize);
739
- assert.calledOnce(hci.readBdAddr);
740
-
741
- should(hci._isExtended).equal(false);
742
- });
743
-
744
- it('should process with extended features', () => {
745
- const cmd = 8195;
746
- const status = 0;
747
- const result = Buffer.from("bd5f660000000000", "hex");
748
-
749
- hci.processCmdCompleteEvent(cmd, status, result);
750
-
751
- // Verify all methods were called including extended-specific
752
- assert.calledOnce(hci.setCodedPhySupport);
753
- assert.calledOnce(hci.setEventMask);
754
- assert.calledOnce(hci.setLeEventMask);
755
- assert.calledOnce(hci.readLocalVersion);
756
- assert.calledOnce(hci.writeLeHostSupported);
757
- assert.calledOnce(hci.readLeHostSupported);
758
- assert.calledOnce(hci.readLeBufferSize);
759
- assert.calledOnce(hci.readBdAddr);
760
-
761
- should(hci._isExtended).equal(true);
762
- });
763
- });
764
- });
765
-
766
- it('should only processCmdStatusEvent - HCI_EVENT_PKT / EVT_CMD_STATUS', () => {
694
+ hci.onSocketData(data);
695
+
696
+ // Called
697
+ expect(hci.processCmdCompleteEvent).toHaveBeenCalledWith(4660, 3, Buffer.from([9, 9]));
698
+
699
+ // Not called
700
+ expect(hci.flushAcl).not.toHaveBeenCalled();
701
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
702
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
703
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
704
+ expect(aclDataPktCallback).not.toHaveBeenCalled();
705
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
706
+
707
+ // HCI state checks
708
+ expect(hci._aclQueue).toEqual(aclQueue);
709
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
710
+ expect(hci._aclConnections.get(4660)).toEqual({ pending: 3 });
711
+ expect(hci._aclConnections.get(4661)).toEqual({ pending: 2 });
712
+ });
713
+
714
+ test('should only processCmdStatusEvent - HCI_EVENT_PKT / EVT_CMD_STATUS', () => {
767
715
  const eventType = 4;
768
716
  const subEventType = 15;
769
717
  const data = Buffer.from([eventType, subEventType, 4, 2, 0x34, 0x12, 3, 9, 9]);
770
718
  hci.onSocketData(data);
771
-
772
- // called
773
- assert.calledOnceWithExactly(hci.processCmdStatusEvent, 786, 2);
774
-
775
- // not called
776
- assert.notCalled(hci.flushAcl);
777
- assert.notCalled(encryptChangeCallback);
778
- assert.notCalled(hci.processCmdCompleteEvent);
779
- assert.notCalled(hci.processLeMetaEvent);
780
- assert.notCalled(disconnCompleteCallback);
781
- assert.notCalled(aclDataPktCallback);
782
- assert.notCalled(leScanEnableSetCmdCallback);
783
-
784
- // hci checks
785
- should(hci._aclQueue).deepEqual(aclQueue);
786
- should(hci._aclConnections).have.keys(4660, 4661);
787
- should(hci._aclConnections.get(4660)).deepEqual({ pending: 3 });
788
- should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
789
- });
790
-
791
- it('should only processLeMetaEvent - HCI_EVENT_PKT / EVT_LE_META_EVENT', () => {
719
+
720
+ // Called
721
+ expect(hci.processCmdStatusEvent).toHaveBeenCalledWith(786, 2);
722
+
723
+ // Not called
724
+ expect(hci.flushAcl).not.toHaveBeenCalled();
725
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
726
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
727
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
728
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
729
+ expect(aclDataPktCallback).not.toHaveBeenCalled();
730
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
731
+
732
+ // HCI state checks
733
+ expect(hci._aclQueue).toEqual(aclQueue);
734
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
735
+ expect(hci._aclConnections.get(4660)).toEqual({ pending: 3 });
736
+ expect(hci._aclConnections.get(4661)).toEqual({ pending: 2 });
737
+ });
738
+
739
+ test('should only processLeMetaEvent - HCI_EVENT_PKT / EVT_LE_META_EVENT', () => {
792
740
  const eventType = 4;
793
741
  const subEventType = 62;
794
742
  const data = Buffer.from([eventType, subEventType, 0, 1, 0x34, 0x12, 3, 9, 9]);
795
- hci.onSocketData(data);
796
-
797
- // called
798
- assert.calledOnceWithExactly(hci.processLeMetaEvent, 1, 52, Buffer.from([0x12, 3, 9, 9]));
799
743
 
800
- // not called
801
- assert.notCalled(hci.flushAcl);
802
- assert.notCalled(encryptChangeCallback);
803
- assert.notCalled(hci.processCmdCompleteEvent);
804
- assert.notCalled(disconnCompleteCallback);
805
- assert.notCalled(aclDataPktCallback);
806
- assert.notCalled(leScanEnableSetCmdCallback);
807
-
808
- // hci checks
809
- should(hci._aclQueue).deepEqual(aclQueue);
810
- should(hci._aclConnections).have.keys(4660, 4661);
811
- should(hci._aclConnections.get(4660)).deepEqual({ pending: 3 });
812
- should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
813
- });
814
-
815
- it('should only flushAcl - HCI_EVENT_PKT / EVT_NUMBER_OF_COMPLETED_PACKETS', () => {
744
+ hci.onSocketData(data);
745
+
746
+ // Called
747
+ expect(hci.processLeMetaEvent).toHaveBeenCalledWith(1, 52, Buffer.from([0x12, 3, 9, 9]));
748
+
749
+ // Not called
750
+ expect(hci.flushAcl).not.toHaveBeenCalled();
751
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
752
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
753
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
754
+ expect(aclDataPktCallback).not.toHaveBeenCalled();
755
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
756
+
757
+ // HCI state checks
758
+ expect(hci._aclQueue).toEqual(aclQueue);
759
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
760
+ expect(hci._aclConnections.get(4660)).toEqual({ pending: 3 });
761
+ expect(hci._aclConnections.get(4661)).toEqual({ pending: 2 });
762
+ });
763
+
764
+ test('should only flushAcl - HCI_EVENT_PKT / EVT_NUMBER_OF_COMPLETED_PACKETS', () => {
816
765
  const eventType = 4;
817
766
  const subEventType = 19;
818
767
  const data = Buffer.from([eventType, subEventType, 0, 1, 0x34, 0x12, 3, 9, 9]);
819
768
  hci.onSocketData(data);
820
-
821
- // called
822
- assert.calledOnceWithExactly(hci.flushAcl);
823
-
824
- // not called
825
- assert.notCalled(hci.processLeMetaEvent);
826
- assert.notCalled(encryptChangeCallback);
827
- assert.notCalled(hci.processCmdCompleteEvent);
828
- assert.notCalled(disconnCompleteCallback);
829
- assert.notCalled(aclDataPktCallback);
830
- assert.notCalled(leScanEnableSetCmdCallback);
831
-
832
- // hci checks
833
- should(hci._aclQueue).deepEqual(aclQueue);
834
- should(hci._aclConnections).have.keys(4660, 4661);
835
- should(hci._aclConnections.get(4660)).deepEqual({ pending: 0 });
836
- should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
837
- });
838
-
839
- it('should do nothing - HCI_EVENT_PKT / ??', () => {
769
+
770
+ // Called
771
+ expect(hci.flushAcl).toHaveBeenCalled();
772
+
773
+ // Not called
774
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
775
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
776
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
777
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
778
+ expect(aclDataPktCallback).not.toHaveBeenCalled();
779
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
780
+
781
+ // HCI state checks
782
+ expect(hci._aclQueue).toEqual(aclQueue);
783
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
784
+ expect(hci._aclConnections.get(4660)).toEqual({ pending: 0 });
785
+ expect(hci._aclConnections.get(4661)).toEqual({ pending: 2 });
786
+ });
787
+
788
+ test('should do nothing - HCI_EVENT_PKT / unknown subEventType', () => {
840
789
  const eventType = 4;
841
790
  const subEventType = 122;
842
791
  const data = Buffer.from([eventType, subEventType, 0, 1, 0x34, 0x12, 3, 9, 9]);
843
792
  hci.onSocketData(data);
844
-
845
- // called
846
-
847
- // not called
848
- assert.notCalled(hci.flushAcl);
849
- assert.notCalled(hci.processLeMetaEvent);
850
- assert.notCalled(encryptChangeCallback);
851
- assert.notCalled(hci.processCmdCompleteEvent);
852
- assert.notCalled(disconnCompleteCallback);
853
- assert.notCalled(aclDataPktCallback);
854
- assert.notCalled(leScanEnableSetCmdCallback);
855
-
856
- // hci checks
857
- should(hci._aclQueue).deepEqual(aclQueue);
858
- should(hci._aclConnections).have.keys(4660, 4661);
859
- should(hci._aclConnections.get(4660)).deepEqual({ pending: 3 });
860
- should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
861
- });
862
-
863
- it('should only emit aclDataPkt - HCI_ACLDATA_PKT / ACL_START', () => {
793
+
794
+ // Not called - nothing should happen
795
+ expect(hci.flushAcl).not.toHaveBeenCalled();
796
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
797
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
798
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
799
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
800
+ expect(aclDataPktCallback).not.toHaveBeenCalled();
801
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
802
+
803
+ // HCI state checks
804
+ expect(hci._aclQueue).toEqual(aclQueue);
805
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
806
+ expect(hci._aclConnections.get(4660)).toEqual({ pending: 3 });
807
+ expect(hci._aclConnections.get(4661)).toEqual({ pending: 2 });
808
+ });
809
+
810
+ test('should only emit aclDataPkt - HCI_ACLDATA_PKT / ACL_START', () => {
864
811
  const eventType = 2;
865
812
  const subEventTypeP1 = 0xf2;
866
813
  const subEventTypeP2 = 0x24;
867
814
  const data = Buffer.from([eventType, subEventTypeP1, subEventTypeP2, 0x34, 0x12, 0x03, 0x00, 3, 9, 9, 8, 7]);
868
815
  hci.onSocketData(data);
869
-
870
- // called
871
- assert.calledOnceWithExactly(aclDataPktCallback, 1266, 2307, Buffer.from([9, 8, 7]));
872
-
873
- // not called
874
- assert.notCalled(hci.flushAcl);
875
- assert.notCalled(hci.processLeMetaEvent);
876
- assert.notCalled(encryptChangeCallback);
877
- assert.notCalled(hci.processCmdCompleteEvent);
878
- assert.notCalled(disconnCompleteCallback);
879
- assert.notCalled(leScanEnableSetCmdCallback);
880
-
881
- // hci checks
882
- should(hci._aclQueue).deepEqual(aclQueue);
883
- should(hci._aclConnections).have.keys(4660, 4661);
884
- should(hci._aclConnections.get(4660)).deepEqual({ pending: 3 });
885
- should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
886
-
887
- should(hci._handleBuffers).be.empty();
888
- });
889
-
890
- it('should register handle buffer - HCI_ACLDATA_PKT / ACL_START', () => {
816
+
817
+ // Called
818
+ expect(aclDataPktCallback).toHaveBeenCalledWith(1266, 2307, Buffer.from([9, 8, 7]));
819
+
820
+ // Not called
821
+ expect(hci.flushAcl).not.toHaveBeenCalled();
822
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
823
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
824
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
825
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
826
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
827
+
828
+ // HCI state checks
829
+ expect(hci._aclQueue).toEqual(aclQueue);
830
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
831
+ expect(hci._aclConnections.get(4660)).toEqual({ pending: 3 });
832
+ expect(hci._aclConnections.get(4661)).toEqual({ pending: 2 });
833
+ expect(hci._handleBuffers).toEqual({});
834
+ });
835
+
836
+ test('should register handle buffer - HCI_ACLDATA_PKT / ACL_START with incomplete data', () => {
891
837
  const eventType = 2;
892
838
  const subEventTypeP1 = 0xf2;
893
839
  const subEventTypeP2 = 0x24;
894
840
  const data = Buffer.from([eventType, subEventTypeP1, subEventTypeP2, 0x34, 0x12, 0x03, 0x00, 3, 9, 9, 8]);
895
841
  hci.onSocketData(data);
896
-
897
- // called
898
-
899
- // not called
900
- assert.notCalled(aclDataPktCallback);
901
- assert.notCalled(hci.flushAcl);
902
- assert.notCalled(hci.processLeMetaEvent);
903
- assert.notCalled(encryptChangeCallback);
904
- assert.notCalled(hci.processCmdCompleteEvent);
905
- assert.notCalled(disconnCompleteCallback);
906
- assert.notCalled(leScanEnableSetCmdCallback);
907
-
908
- // hci checks
909
- should(hci._aclQueue).deepEqual(aclQueue);
910
- should(hci._aclConnections).have.keys(4660, 4661);
911
- should(hci._aclConnections.get(4660)).deepEqual({ pending: 3 });
912
- should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
913
-
914
- should(hci._handleBuffers).deepEqual({
915
- 1266: {
916
- length: 3,
917
- cid: 2307,
918
- data: Buffer.from([9, 8])
919
- }
842
+
843
+ // Not called
844
+ expect(aclDataPktCallback).not.toHaveBeenCalled();
845
+ expect(hci.flushAcl).not.toHaveBeenCalled();
846
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
847
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
848
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
849
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
850
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
851
+
852
+ // HCI state checks
853
+ expect(hci._aclQueue).toEqual(aclQueue);
854
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
855
+ expect(hci._aclConnections.get(4660)).toEqual({ pending: 3 });
856
+ expect(hci._aclConnections.get(4661)).toEqual({ pending: 2 });
857
+
858
+ // Check buffer was created properly
859
+ expect(hci._handleBuffers[1266]).toEqual({
860
+ length: 3,
861
+ cid: 2307,
862
+ data: expect.any(Buffer)
920
863
  });
864
+ expect(Buffer.from(hci._handleBuffers[1266].data)).toEqual(Buffer.from([9, 8]));
921
865
  });
922
-
923
- it('should do nothing - HCI_ACLDATA_PKT / ACL_CONT', () => {
866
+
867
+ test('should do nothing - HCI_ACLDATA_PKT / ACL_CONT without existing buffer', () => {
924
868
  const eventType = 2;
925
869
  const subEventTypeP1 = 0xf2;
926
870
  const subEventTypeP2 = 0x14;
927
871
  const data = Buffer.from([eventType, subEventTypeP1, subEventTypeP2, 0x34, 0x12, 0x03, 0x00, 3, 9, 9, 8]);
928
872
  hci.onSocketData(data);
929
-
930
- // called
931
-
932
- // not called
933
- assert.notCalled(aclDataPktCallback);
934
- assert.notCalled(hci.flushAcl);
935
- assert.notCalled(hci.processLeMetaEvent);
936
- assert.notCalled(encryptChangeCallback);
937
- assert.notCalled(hci.processCmdCompleteEvent);
938
- assert.notCalled(disconnCompleteCallback);
939
- assert.notCalled(leScanEnableSetCmdCallback);
940
-
941
- // hci checks
942
- should(hci._aclQueue).deepEqual(aclQueue);
943
- should(hci._aclConnections).have.keys(4660, 4661);
944
- should(hci._aclConnections.get(4660)).deepEqual({ pending: 3 });
945
- should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
946
-
947
- should(hci._handleBuffers).be.empty();
948
- });
949
-
950
- it('should concat data - HCI_ACLDATA_PKT / ACL_CONT', () => {
873
+
874
+ // Not called
875
+ expect(aclDataPktCallback).not.toHaveBeenCalled();
876
+ expect(hci.flushAcl).not.toHaveBeenCalled();
877
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
878
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
879
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
880
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
881
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
882
+
883
+ // HCI state checks
884
+ expect(hci._aclQueue).toEqual(aclQueue);
885
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
886
+ expect(hci._aclConnections.get(4660)).toEqual({ pending: 3 });
887
+ expect(hci._aclConnections.get(4661)).toEqual({ pending: 2 });
888
+ expect(hci._handleBuffers).toEqual({});
889
+ });
890
+
891
+ test('should concat data - HCI_ACLDATA_PKT / ACL_CONT with existing buffer', () => {
951
892
  const eventType = 2;
952
893
  const subEventTypeP1 = 0xf2;
953
894
  const subEventTypeP2 = 0x14;
954
895
  const data = Buffer.from([eventType, subEventTypeP1, subEventTypeP2, 0x34, 0x12, 0x03, 0x00, 3, 9, 9, 8]);
955
-
956
- const handleBuffers = {
896
+
897
+ // Setup pre-existing buffer
898
+ hci._handleBuffers = {
957
899
  1266: {
958
900
  length: 3,
959
901
  cid: 2307,
960
902
  data: Buffer.from([3, 4])
961
903
  }
962
904
  };
963
- hci._handleBuffers = handleBuffers;
964
-
905
+
965
906
  hci.onSocketData(data);
966
-
967
- // called
968
-
969
- // not called
970
- assert.notCalled(aclDataPktCallback);
971
- assert.notCalled(hci.flushAcl);
972
- assert.notCalled(hci.processLeMetaEvent);
973
- assert.notCalled(encryptChangeCallback);
974
- assert.notCalled(hci.processCmdCompleteEvent);
975
- assert.notCalled(disconnCompleteCallback);
976
- assert.notCalled(leScanEnableSetCmdCallback);
977
-
978
- // hci checks
979
- should(hci._aclQueue).deepEqual(aclQueue);
980
- should(hci._aclConnections).have.keys(4660, 4661);
981
- should(hci._aclConnections.get(4660)).deepEqual({ pending: 3 });
982
- should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
983
-
984
- should(hci._handleBuffers).deepEqual({
907
+
908
+ // Not called
909
+ expect(aclDataPktCallback).not.toHaveBeenCalled();
910
+ expect(hci.flushAcl).not.toHaveBeenCalled();
911
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
912
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
913
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
914
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
915
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
916
+
917
+ // HCI state checks
918
+ expect(hci._aclQueue).toEqual(aclQueue);
919
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
920
+ expect(hci._aclConnections.get(4660)).toEqual({ pending: 3 });
921
+ expect(hci._aclConnections.get(4661)).toEqual({ pending: 2 });
922
+
923
+ // Check buffer was updated properly
924
+ expect(hci._handleBuffers).toEqual({
985
925
  1266: {
986
926
  length: 3,
987
927
  cid: 2307,
988
- data: Buffer.from([3, 4, 3, 0, 3, 9, 9, 8])
928
+ data: expect.any(Buffer)
989
929
  }
990
930
  });
931
+
932
+ // Check buffer contents
933
+ const bufferData = hci._handleBuffers[1266].data;
934
+ expect(Buffer.from(bufferData)).toEqual(Buffer.from([3, 4, 3, 0, 3, 9, 9, 8]));
991
935
  });
992
-
993
- it('should concat data and emit aclDataPkt - HCI_ACLDATA_PKT / ACL_CONT', () => {
936
+
937
+ test('should concat data and emit aclDataPkt - HCI_ACLDATA_PKT / ACL_CONT when complete', () => {
994
938
  const eventType = 2;
995
939
  const subEventTypeP1 = 0xf2;
996
940
  const subEventTypeP2 = 0x14;
997
941
  const data = Buffer.from([eventType, subEventTypeP1, subEventTypeP2, 0x34, 0x12, 0x03, 0x00, 3, 9, 9, 8]);
998
-
999
- const handleBuffers = {
942
+
943
+ // Setup pre-existing buffer with enough expected length to trigger completion
944
+ hci._handleBuffers = {
1000
945
  1266: {
1001
946
  length: 8,
1002
947
  cid: 2307,
1003
948
  data: Buffer.from([3, 4])
1004
949
  }
1005
950
  };
1006
- hci._handleBuffers = handleBuffers;
1007
-
1008
- hci.onSocketData(data);
1009
-
1010
- // called
1011
- assert.calledOnceWithExactly(aclDataPktCallback, 1266, 2307, Buffer.from([3, 4, 3, 0, 3, 9, 9, 8]));
1012
-
1013
- // not called
1014
- assert.notCalled(hci.flushAcl);
1015
- assert.notCalled(hci.processLeMetaEvent);
1016
- assert.notCalled(encryptChangeCallback);
1017
- assert.notCalled(hci.processCmdCompleteEvent);
1018
- assert.notCalled(disconnCompleteCallback);
1019
- assert.notCalled(leScanEnableSetCmdCallback);
1020
-
1021
- // hci checks
1022
- should(hci._aclQueue).deepEqual(aclQueue);
1023
- should(hci._aclConnections).have.keys(4660, 4661);
1024
- should(hci._aclConnections.get(4660)).deepEqual({ pending: 3 });
1025
- should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
1026
-
1027
- should(hci._handleBuffers).be.empty();
1028
- });
1029
-
1030
- it('should do nothing - HCI_ACLDATA_PKT / ??', () => {
1031
- const eventType = 2;
1032
- const subEventType = 122;
1033
- const data = Buffer.from([eventType, subEventType, 0, 1, 0x34, 0x12, 3, 9, 9]);
951
+
1034
952
  hci.onSocketData(data);
1035
-
1036
- // called
1037
-
1038
- // not called
1039
- assert.notCalled(hci.flushAcl);
1040
- assert.notCalled(hci.processLeMetaEvent);
1041
- assert.notCalled(encryptChangeCallback);
1042
- assert.notCalled(hci.processCmdCompleteEvent);
1043
- assert.notCalled(disconnCompleteCallback);
1044
- assert.notCalled(aclDataPktCallback);
1045
- assert.notCalled(leScanEnableSetCmdCallback);
1046
-
1047
- // hci checks
1048
- should(hci._aclQueue).deepEqual(aclQueue);
1049
- should(hci._aclConnections).have.keys(4660, 4661);
1050
- should(hci._aclConnections.get(4660)).deepEqual({ pending: 3 });
1051
- should(hci._aclConnections.get(4661)).deepEqual({ pending: 2 });
953
+
954
+ // Called
955
+ expect(aclDataPktCallback).toHaveBeenCalledWith(
956
+ 1266,
957
+ 2307,
958
+ expect.any(Buffer)
959
+ );
960
+
961
+ // Verify buffer contents in the callback
962
+ const callData = aclDataPktCallback.mock.calls[0][2];
963
+ expect(Buffer.from(callData)).toEqual(Buffer.from([3, 4, 3, 0, 3, 9, 9, 8]));
964
+
965
+ // Not called
966
+ expect(hci.flushAcl).not.toHaveBeenCalled();
967
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
968
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
969
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
970
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
971
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
972
+
973
+ // HCI state checks
974
+ expect(hci._aclQueue).toEqual(aclQueue);
975
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
976
+ expect(hci._aclConnections.get(4660)).toEqual({ pending: 3 });
977
+ expect(hci._aclConnections.get(4661)).toEqual({ pending: 2 });
978
+
979
+ // Buffer should be emptied after processing
980
+ expect(hci._handleBuffers).toEqual({});
1052
981
  });
1053
-
1054
- it('should emit leScanEnableSetCmd - HCI_COMMAND_PKT / LE_SET_SCAN_ENABLE_CMD', () => {
982
+
983
+ test('should emit leScanEnableSetCmd - HCI_COMMAND_PKT / LE_SET_SCAN_ENABLE_CMD', () => {
1055
984
  const eventType = 1;
1056
985
  const subEventTypeP1 = 0x0c;
1057
986
  const subEventTypeP2 = 0x20;
1058
987
  const data = Buffer.from([eventType, subEventTypeP1, subEventTypeP2, 0x34, 0x01, 0]);
1059
-
1060
- const handleBuffers = {
1061
- 1266: {
1062
- length: 8,
1063
- cid: 2307,
1064
- data: Buffer.from([3, 4])
1065
- }
1066
- };
1067
- hci._handleBuffers = handleBuffers;
1068
-
988
+
1069
989
  hci.onSocketData(data);
1070
-
1071
- // called
1072
- assert.calledOnceWithExactly(leScanEnableSetCmdCallback, true, false);
1073
-
1074
- // not called
1075
- assert.notCalled(hci.flushAcl);
1076
- assert.notCalled(hci.processLeMetaEvent);
1077
- assert.notCalled(encryptChangeCallback);
1078
- assert.notCalled(hci.processCmdCompleteEvent);
1079
- assert.notCalled(disconnCompleteCallback);
1080
- assert.notCalled(aclDataPktCallback);
1081
-
1082
- // hci checks
1083
- should(hci._aclQueue).deepEqual(aclQueue);
1084
- should(hci._aclConnections).have.keys(4660, 4661);
1085
- });
1086
-
1087
- it('should not emit leScanEnableSetCmd - HCI_COMMAND_PKT / ???', () => {
990
+
991
+ // Called
992
+ expect(leScanEnableSetCmdCallback).toHaveBeenCalledWith(true, false);
993
+
994
+ // Not called
995
+ expect(hci.flushAcl).not.toHaveBeenCalled();
996
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
997
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
998
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
999
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
1000
+ expect(aclDataPktCallback).not.toHaveBeenCalled();
1001
+
1002
+ // HCI state checks
1003
+ expect(hci._aclQueue).toEqual(aclQueue);
1004
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
1005
+ });
1006
+
1007
+ test('should not emit leScanEnableSetCmd - HCI_COMMAND_PKT / unknown command', () => {
1088
1008
  const eventType = 1;
1089
1009
  const subEventTypeP1 = 0x0c;
1090
- const subEventTypeP2 = 0x21;
1010
+ const subEventTypeP2 = 0x21; // Different command code
1091
1011
  const data = Buffer.from([eventType, subEventTypeP1, subEventTypeP2, 0x34, 0x01, 0]);
1092
-
1093
- const handleBuffers = {
1094
- 1266: {
1095
- length: 8,
1096
- cid: 2307,
1097
- data: Buffer.from([3, 4])
1098
- }
1099
- };
1100
- hci._handleBuffers = handleBuffers;
1101
-
1012
+
1102
1013
  hci.onSocketData(data);
1103
-
1104
- // called
1105
-
1106
- // not called
1107
- assert.notCalled(leScanEnableSetCmdCallback);
1108
- assert.notCalled(hci.flushAcl);
1109
- assert.notCalled(hci.processLeMetaEvent);
1110
- assert.notCalled(encryptChangeCallback);
1111
- assert.notCalled(hci.processCmdCompleteEvent);
1112
- assert.notCalled(disconnCompleteCallback);
1113
- assert.notCalled(aclDataPktCallback);
1114
-
1115
- // hci checks
1116
- should(hci._aclQueue).deepEqual(aclQueue);
1117
- should(hci._aclConnections).have.keys(4660, 4661);
1118
- });
1119
-
1120
- it('should do nothing - ?? / ???', () => {
1121
- const eventType = 122;
1014
+
1015
+ // Not called
1016
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
1017
+ expect(hci.flushAcl).not.toHaveBeenCalled();
1018
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
1019
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
1020
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
1021
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
1022
+ expect(aclDataPktCallback).not.toHaveBeenCalled();
1023
+
1024
+ // HCI state checks
1025
+ expect(hci._aclQueue).toEqual(aclQueue);
1026
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
1027
+ });
1028
+
1029
+ test('should do nothing - unknown event type', () => {
1030
+ const eventType = 122; // Unknown event type
1122
1031
  const subEventTypeP1 = 0x0c;
1123
1032
  const subEventTypeP2 = 0x21;
1124
1033
  const data = Buffer.from([eventType, subEventTypeP1, subEventTypeP2, 0x34, 0x01, 0]);
1125
-
1126
- const handleBuffers = {
1127
- 1266: {
1128
- length: 8,
1129
- cid: 2307,
1130
- data: Buffer.from([3, 4])
1131
- }
1132
- };
1133
- hci._handleBuffers = handleBuffers;
1134
-
1034
+
1135
1035
  hci.onSocketData(data);
1136
-
1137
- // called
1138
-
1139
- // not called
1140
- assert.notCalled(leScanEnableSetCmdCallback);
1141
- assert.notCalled(hci.flushAcl);
1142
- assert.notCalled(hci.processLeMetaEvent);
1143
- assert.notCalled(encryptChangeCallback);
1144
- assert.notCalled(hci.processCmdCompleteEvent);
1145
- assert.notCalled(disconnCompleteCallback);
1146
- assert.notCalled(aclDataPktCallback);
1147
-
1148
- // hci checks
1149
- should(hci._aclQueue).deepEqual(aclQueue);
1150
- should(hci._aclConnections).have.keys(4660, 4661);
1036
+
1037
+ // Not called
1038
+ expect(leScanEnableSetCmdCallback).not.toHaveBeenCalled();
1039
+ expect(hci.flushAcl).not.toHaveBeenCalled();
1040
+ expect(hci.processLeMetaEvent).not.toHaveBeenCalled();
1041
+ expect(encryptChangeCallback).not.toHaveBeenCalled();
1042
+ expect(hci.processCmdCompleteEvent).not.toHaveBeenCalled();
1043
+ expect(disconnCompleteCallback).not.toHaveBeenCalled();
1044
+ expect(aclDataPktCallback).not.toHaveBeenCalled();
1045
+
1046
+ // HCI state checks
1047
+ expect(hci._aclQueue).toEqual(aclQueue);
1048
+ expect(Array.from(hci._aclConnections.keys())).toEqual(expect.arrayContaining([4660, 4661]));
1049
+ });
1050
+ });
1051
+
1052
+ // LE_READ_LOCAL_SUPPORTED_FEATURES tests
1053
+ describe('LE_READ_LOCAL_SUPPORTED_FEATURES', () => {
1054
+ beforeEach(() => {
1055
+ // Spy on methods rather than replacing them
1056
+ jest.spyOn(hci, 'setCodedPhySupport');
1057
+ jest.spyOn(hci, 'setEventMask');
1058
+ jest.spyOn(hci, 'setLeEventMask');
1059
+ jest.spyOn(hci, 'readLocalVersion');
1060
+ jest.spyOn(hci, 'writeLeHostSupported');
1061
+ jest.spyOn(hci, 'readLeHostSupported');
1062
+ jest.spyOn(hci, 'readLeBufferSize');
1063
+ jest.spyOn(hci, 'readBdAddr');
1064
+
1065
+ // Reset _isExtended flag
1066
+ hci._isExtended = false;
1067
+ });
1068
+
1069
+ afterEach(() => {
1070
+ jest.clearAllMocks();
1071
+ });
1072
+
1073
+ test('should not process on error status', () => {
1074
+ const cmd = 8195;
1075
+ const status = 1;
1076
+ const result = Buffer.from([0x00, 0x00, 0x00, 0x00]);
1077
+
1078
+ hci.processCmdCompleteEvent(cmd, status, result);
1079
+
1080
+ // Verify no methods were called
1081
+ expect(hci.setCodedPhySupport).not.toHaveBeenCalled();
1082
+ expect(hci.setEventMask).not.toHaveBeenCalled();
1083
+ expect(hci.setLeEventMask).not.toHaveBeenCalled();
1084
+ expect(hci.readLocalVersion).not.toHaveBeenCalled();
1085
+ expect(hci.writeLeHostSupported).not.toHaveBeenCalled();
1086
+ expect(hci.readLeHostSupported).not.toHaveBeenCalled();
1087
+ expect(hci.readLeBufferSize).not.toHaveBeenCalled();
1088
+ expect(hci.readBdAddr).not.toHaveBeenCalled();
1089
+
1090
+ expect(hci._isExtended).toBe(false);
1091
+ });
1092
+
1093
+ test('should process without extended features', () => {
1094
+ const cmd = 8195;
1095
+ const status = 0;
1096
+ const result = Buffer.from([0x00, 0x00, 0x00, 0x00]); // No bits set
1097
+
1098
+ hci.processCmdCompleteEvent(cmd, status, result);
1099
+
1100
+ // Verify extended-specific method not called
1101
+ expect(hci.setCodedPhySupport).not.toHaveBeenCalled();
1102
+
1103
+ // Verify other methods were called
1104
+ expect(hci.setEventMask).toHaveBeenCalled();
1105
+ expect(hci.setLeEventMask).toHaveBeenCalled();
1106
+ expect(hci.readLocalVersion).toHaveBeenCalled();
1107
+ expect(hci.writeLeHostSupported).toHaveBeenCalled();
1108
+ expect(hci.readLeHostSupported).toHaveBeenCalled();
1109
+ expect(hci.readLeBufferSize).toHaveBeenCalled();
1110
+ expect(hci.readBdAddr).toHaveBeenCalled();
1111
+
1112
+ expect(hci._isExtended).toBe(false);
1151
1113
  });
1152
1114
  });
1153
1115
 
@@ -1899,10 +1861,14 @@ describe('hci-socket hci', () => {
1899
1861
  const data = Buffer.from([1, 0, 0xff, 0xee]);
1900
1862
  const callback = sinon.spy();
1901
1863
 
1864
+ const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
1865
+
1902
1866
  hci.on('leAdvertisingReport', callback);
1903
1867
  hci.processLeAdvertisingReport(count, data);
1904
1868
 
1905
1869
  assert.notCalled(callback);
1870
+
1871
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('illegal packet'));
1906
1872
  });
1907
1873
  });
1908
1874
 
@@ -1947,10 +1913,13 @@ describe('hci-socket hci', () => {
1947
1913
  const data = Buffer.from([1, 0, 0xff, 0xee]);
1948
1914
  const callback = sinon.spy();
1949
1915
 
1916
+ const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
1917
+
1950
1918
  hci.on('leExtendedAdvertisingReport', callback);
1951
1919
  hci.processLeExtendedAdvertisingReport(count, data);
1952
1920
 
1953
1921
  assert.notCalled(callback);
1922
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('illegal packet'));
1954
1923
  });
1955
1924
  });
1956
1925