@nordicsemiconductor/pc-nrfconnect-shared 104.0.0 → 106.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.
@@ -0,0 +1,1033 @@
1
+ /*
2
+ * Copyright (c) 2021 Nordic Semiconductor ASA
3
+ *
4
+ * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause
5
+ */
6
+
7
+ import type {
8
+ AutoDetectTypes,
9
+ SetOptions,
10
+ UpdateOptions,
11
+ } from '@serialport/bindings-cpp';
12
+ import type { SerialPortOpenOptions } from 'serialport';
13
+
14
+ import { SerialPort } from '../SerialPort/SerialPort';
15
+ import {
16
+ shellParser as CreateShellParser,
17
+ ShellParserSettings,
18
+ XTerminalShellParser,
19
+ } from './shellParser';
20
+
21
+ jest.useFakeTimers();
22
+
23
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
24
+ let onResponseCallback = (data: Uint8Array) => {};
25
+
26
+ const setupMocks = () => {
27
+ const mockOnData = jest.fn((handler: (data: Uint8Array) => void) => {
28
+ onResponseCallback = handler;
29
+ return () => {};
30
+ });
31
+
32
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
33
+ const mockOnClose = jest.fn((_handler: () => void) => () => {});
34
+
35
+ const mockOnUpdate = jest.fn(
36
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
37
+ (_handler: (newOptions: UpdateOptions) => void) => () => {}
38
+ );
39
+
40
+ const mockOnSet = jest.fn(
41
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
42
+ (_handler: (newOptions: SetOptions) => void) => () => {}
43
+ );
44
+
45
+ const mockOnChange = jest.fn(
46
+ (
47
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
48
+ _handler: (
49
+ newOptions: SerialPortOpenOptions<AutoDetectTypes>
50
+ ) => void
51
+ ) =>
52
+ () => {}
53
+ );
54
+
55
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
56
+ let onDataWrittenCallback = (data: Uint8Array) => {};
57
+ const mockOnDataWritten = jest.fn(
58
+ (handler: (data: Uint8Array) => void) => () => {
59
+ onDataWrittenCallback = handler;
60
+ return () => {};
61
+ }
62
+ );
63
+
64
+ const mockClose = jest.fn(async () => {});
65
+ const mockWrite = jest.fn((data: string | number[] | Buffer) =>
66
+ Promise.resolve(onDataWrittenCallback(Buffer.from(data)))
67
+ );
68
+
69
+ const mockIsOpen = jest.fn(
70
+ () =>
71
+ new Promise<boolean>(resolve => {
72
+ resolve(true);
73
+ })
74
+ );
75
+ const mockGetOptions = jest.fn(
76
+ () => new Promise<SerialPortOpenOptions<AutoDetectTypes>>(() => {})
77
+ );
78
+ const mockUpdate = jest.fn(() => Promise.resolve());
79
+ const mockSet = jest.fn(() => Promise.resolve());
80
+
81
+ const mockOnAnyCommandResponse = jest.fn(() => '');
82
+ const mockOnShellLogging = jest.fn(() => '');
83
+ const mockOnUnknown = jest.fn(() => '');
84
+
85
+ const mockOnSuccess = jest.fn(() => '');
86
+ const mockOnError = jest.fn(() => '');
87
+
88
+ const settings: ShellParserSettings = {
89
+ shellPromptUart: 'uart:~$',
90
+ logRegex:
91
+ /[[][0-9]{2,}:[0-9]{2}:[0-9]{2}.[0-9]{3},[0-9]{3}] <([^<^>]+)> ([^:]+): .*(\r\n|\r|\n)$/,
92
+ errorRegex: /error: /,
93
+ timeout: 1000,
94
+ columnWidth: 80,
95
+ };
96
+
97
+ const mockModem = jest.fn<SerialPort, []>(() => ({
98
+ path: 'fakePort',
99
+ write: mockWrite,
100
+ close: mockClose,
101
+ isOpen: mockIsOpen,
102
+ getOptions: mockGetOptions,
103
+ update: mockUpdate,
104
+ set: mockSet,
105
+ onData: mockOnData,
106
+ onClosed: mockOnClose,
107
+ onUpdate: mockOnUpdate,
108
+ onSet: mockOnSet,
109
+ onChange: mockOnChange,
110
+ onDataWritten: mockOnDataWritten,
111
+ }));
112
+
113
+ let terminalBuffer = '';
114
+
115
+ const mockGetTerminalData = jest.fn(() => terminalBuffer);
116
+ const mockClear = jest.fn(() => {
117
+ terminalBuffer = '';
118
+ });
119
+ const mockGetLastLine = jest.fn(
120
+ () => terminalBuffer.split('\r\n').pop() as string
121
+ );
122
+ const mockTerminalWrite = jest.fn(
123
+ (data: string, callback: () => void | undefined) => {
124
+ if (data !== '\r' && data !== '\n') {
125
+ terminalBuffer += data;
126
+ }
127
+ callback();
128
+ }
129
+ );
130
+
131
+ const mockTerminal = jest.fn<XTerminalShellParser, []>(() => ({
132
+ getTerminalData: mockGetTerminalData,
133
+ clear: mockClear,
134
+ getLastLine: mockGetLastLine,
135
+ write: mockTerminalWrite,
136
+ }));
137
+
138
+ return {
139
+ getTerminalBuffer: () => terminalBuffer,
140
+ setTerminalBuffer: (value: string) => {
141
+ terminalBuffer = value;
142
+ },
143
+ mockIsOpen,
144
+ mockModem,
145
+ mockOnError,
146
+ mockOnResponse: mockOnData,
147
+ mockOnAnyCommandResponse,
148
+ mockOnShellLogging,
149
+ mockOnSuccess,
150
+ mockOnUnknown,
151
+ mockTerminal,
152
+ mockWrite,
153
+ mockClose,
154
+ settings,
155
+ };
156
+ };
157
+
158
+ const {
159
+ setTerminalBuffer,
160
+ mockIsOpen,
161
+ mockModem,
162
+ mockOnError,
163
+ mockOnAnyCommandResponse,
164
+ mockOnShellLogging,
165
+ mockOnSuccess,
166
+ mockOnUnknown,
167
+ mockTerminal,
168
+ mockWrite,
169
+ mockClose,
170
+ settings,
171
+ } = setupMocks();
172
+
173
+ describe('shell command parser', () => {
174
+ beforeEach(() => {
175
+ jest.clearAllMocks();
176
+ setTerminalBuffer(settings.shellPromptUart ?? 'uart:~$');
177
+ mockIsOpen.mockReturnValue(
178
+ new Promise<boolean>(resolve => {
179
+ resolve(true);
180
+ })
181
+ );
182
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
183
+ onResponseCallback = (data: Uint8Array) => {};
184
+ });
185
+
186
+ test('Verify that shell init char is sent on open', async () => {
187
+ await CreateShellParser(mockModem(), mockTerminal());
188
+
189
+ expect(mockWrite).toBeCalledTimes(1);
190
+ expect(mockWrite).toBeCalledWith(
191
+ `${String.fromCharCode(12).toString()}${String.fromCharCode(
192
+ 21
193
+ ).toString()}`
194
+ );
195
+ });
196
+
197
+ test('Verify that no callback is called until we get a response', async () => {
198
+ mockIsOpen.mockReturnValue(
199
+ new Promise<boolean>(resolve => {
200
+ resolve(false);
201
+ })
202
+ );
203
+
204
+ const shellParser = await CreateShellParser(
205
+ mockModem(),
206
+ mockTerminal()
207
+ );
208
+
209
+ (await shellParser).onShellLoggingEvent(mockOnShellLogging);
210
+ shellParser.onUnknownCommand(mockOnUnknown);
211
+
212
+ await shellParser.enqueueRequest('Test Command');
213
+
214
+ expect(mockClose).toBeCalledTimes(0);
215
+ expect(mockWrite).toBeCalledTimes(0);
216
+
217
+ expect(mockOnShellLogging).toBeCalledTimes(0);
218
+ expect(mockOnUnknown).toBeCalledTimes(0);
219
+
220
+ expect(mockOnSuccess).toBeCalledTimes(0);
221
+ expect(mockOnError).toBeCalledTimes(0);
222
+ });
223
+
224
+ test('Verify that enqueued not sent if modem is closed', async () => {
225
+ mockIsOpen.mockReturnValue(
226
+ new Promise<boolean>(resolve => {
227
+ resolve(false);
228
+ })
229
+ );
230
+
231
+ const shellParser = await CreateShellParser(
232
+ mockModem(),
233
+ mockTerminal()
234
+ );
235
+ await shellParser.enqueueRequest('Test Command');
236
+
237
+ expect(mockWrite).toBeCalledTimes(0);
238
+ });
239
+
240
+ test('Verify one time onSuccess callback is called when we have a response in one stream', async () => {
241
+ const shellParser = await CreateShellParser(
242
+ mockModem(),
243
+ mockTerminal(),
244
+ settings
245
+ );
246
+
247
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
248
+ shellParser.onUnknownCommand(mockOnUnknown);
249
+
250
+ await shellParser.enqueueRequest('Test Command', {
251
+ onSuccess: mockOnSuccess,
252
+ onError: mockOnError,
253
+ });
254
+
255
+ expect(mockOnSuccess).toBeCalledTimes(0);
256
+
257
+ onResponseCallback(
258
+ Buffer.from('Test Command\r\nResponse Value\r\nuart:~$')
259
+ );
260
+
261
+ expect(mockOnSuccess).toBeCalledTimes(1);
262
+ expect(mockOnSuccess).toBeCalledWith('Response Value', 'Test Command');
263
+
264
+ expect(mockOnShellLogging).toBeCalledTimes(0);
265
+ expect(mockOnUnknown).toBeCalledTimes(0);
266
+ expect(mockOnError).toBeCalledTimes(0);
267
+ });
268
+
269
+ test('Verify one time onSuccess callback is called when we have a response in multiple streams', async () => {
270
+ const shellParser = await CreateShellParser(
271
+ mockModem(),
272
+ mockTerminal(),
273
+ settings
274
+ );
275
+
276
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
277
+ shellParser.onUnknownCommand(mockOnUnknown);
278
+
279
+ await shellParser.enqueueRequest('Test Command', {
280
+ onSuccess: mockOnSuccess,
281
+ onError: mockOnError,
282
+ });
283
+
284
+ expect(mockOnSuccess).toBeCalledTimes(0);
285
+
286
+ onResponseCallback(Buffer.from('Test Command\r\nResponse Val'));
287
+
288
+ expect(mockOnSuccess).toBeCalledTimes(0);
289
+
290
+ onResponseCallback(Buffer.from('ue\r\nuart:~$'));
291
+
292
+ expect(mockOnSuccess).toBeCalledTimes(1);
293
+ expect(mockOnSuccess).toBeCalledWith('Response Value', 'Test Command');
294
+
295
+ expect(mockOnShellLogging).toBeCalledTimes(0);
296
+ expect(mockOnUnknown).toBeCalledTimes(0);
297
+ expect(mockOnError).toBeCalledTimes(0);
298
+ });
299
+
300
+ test('Verify one time onFail callback is called when we have a response in one stream', async () => {
301
+ const shellParser = await CreateShellParser(
302
+ mockModem(),
303
+ mockTerminal(),
304
+ settings
305
+ );
306
+
307
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
308
+ shellParser.onUnknownCommand(mockOnUnknown);
309
+
310
+ await shellParser.enqueueRequest('Test Command', {
311
+ onSuccess: mockOnSuccess,
312
+ onError: mockOnError,
313
+ });
314
+
315
+ expect(mockOnError).toBeCalledTimes(0);
316
+
317
+ onResponseCallback(
318
+ Buffer.from('Test Command\r\nerror: Response Value\r\nuart:~$')
319
+ );
320
+
321
+ expect(mockOnError).toBeCalledTimes(1);
322
+ expect(mockOnError).toBeCalledWith(
323
+ 'error: Response Value',
324
+ 'Test Command'
325
+ );
326
+
327
+ expect(mockOnSuccess).toBeCalledTimes(0);
328
+ expect(mockOnShellLogging).toBeCalledTimes(0);
329
+ expect(mockOnUnknown).toBeCalledTimes(0);
330
+ });
331
+
332
+ test('Verify one time onFail callback is called when we have a response in multiple streams', async () => {
333
+ const shellParser = await CreateShellParser(
334
+ mockModem(),
335
+ mockTerminal(),
336
+ settings
337
+ );
338
+
339
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
340
+ shellParser.onUnknownCommand(mockOnUnknown);
341
+
342
+ await shellParser.enqueueRequest('Test Command', {
343
+ onSuccess: mockOnSuccess,
344
+ onError: mockOnError,
345
+ });
346
+
347
+ expect(mockOnError).toBeCalledTimes(0);
348
+
349
+ onResponseCallback(Buffer.from('Test Command\r\nerror: Re'));
350
+
351
+ onResponseCallback(Buffer.from('sponse Value\r\nuart'));
352
+
353
+ expect(mockOnError).toBeCalledTimes(0);
354
+
355
+ onResponseCallback(Buffer.from(':~$'));
356
+
357
+ expect(mockOnError).toBeCalledTimes(1);
358
+ expect(mockOnError).toBeCalledWith(
359
+ 'error: Response Value',
360
+ 'Test Command'
361
+ );
362
+
363
+ expect(mockOnSuccess).toBeCalledTimes(0);
364
+ expect(mockOnShellLogging).toBeCalledTimes(0);
365
+ expect(mockOnUnknown).toBeCalledTimes(0);
366
+ });
367
+
368
+ test('Verify that only one command is send at a time until we get a response', async () => {
369
+ const shellParser = await CreateShellParser(
370
+ mockModem(),
371
+ mockTerminal(),
372
+ settings
373
+ );
374
+
375
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
376
+ shellParser.onUnknownCommand(mockOnUnknown);
377
+
378
+ await shellParser.enqueueRequest('Test Command 1', {
379
+ onSuccess: mockOnSuccess,
380
+ onError: mockOnError,
381
+ });
382
+
383
+ await shellParser.enqueueRequest('Test Command 2', {
384
+ onSuccess: mockOnSuccess,
385
+ onError: mockOnError,
386
+ });
387
+
388
+ expect(mockOnSuccess).toBeCalledTimes(0);
389
+
390
+ onResponseCallback(
391
+ Buffer.from('Test Command 1\r\nResponse Value 1\r\nuart:~$')
392
+ );
393
+
394
+ expect(mockOnSuccess).toBeCalledTimes(1);
395
+ expect(mockOnSuccess).toBeCalledWith(
396
+ 'Response Value 1',
397
+ 'Test Command 1'
398
+ );
399
+
400
+ onResponseCallback(
401
+ Buffer.from('Test Command 2\r\nResponse Value 2\r\nuart:~$')
402
+ );
403
+
404
+ expect(mockOnSuccess).toBeCalledTimes(2);
405
+ expect(mockOnSuccess).toBeCalledWith(
406
+ 'Response Value 2',
407
+ 'Test Command 2'
408
+ );
409
+
410
+ expect(mockOnError).toBeCalledTimes(0);
411
+ expect(mockOnShellLogging).toBeCalledTimes(0);
412
+ expect(mockOnUnknown).toBeCalledTimes(0);
413
+ });
414
+
415
+ test('Verify that onSuccess is called for the appropriate responses', async () => {
416
+ const mockOnSuccess1 = jest.fn(() => '');
417
+ const mockOnSuccess2 = jest.fn(() => '');
418
+
419
+ const shellParser = await CreateShellParser(
420
+ mockModem(),
421
+ mockTerminal(),
422
+ settings
423
+ );
424
+
425
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
426
+ shellParser.onUnknownCommand(mockOnUnknown);
427
+
428
+ await shellParser.enqueueRequest('Test Command 1', {
429
+ onSuccess: mockOnSuccess1,
430
+ onError: mockOnError,
431
+ });
432
+
433
+ await shellParser.enqueueRequest('Test Command 2', {
434
+ onSuccess: mockOnSuccess2,
435
+ onError: mockOnError,
436
+ });
437
+
438
+ expect(mockOnSuccess1).toBeCalledTimes(0);
439
+
440
+ onResponseCallback(
441
+ Buffer.from(
442
+ 'Test Command 1\r\nResponse Value 1\r\nuart:~$Test Command 2\r\nResponse Value 2\r\nuart:~$'
443
+ )
444
+ );
445
+
446
+ expect(mockOnSuccess1).toBeCalledTimes(1);
447
+ expect(mockOnSuccess1).toBeCalledWith(
448
+ 'Response Value 1',
449
+ 'Test Command 1'
450
+ );
451
+
452
+ expect(mockOnSuccess2).toBeCalledTimes(1);
453
+ expect(mockOnSuccess2).toBeCalledWith(
454
+ 'Response Value 2',
455
+ 'Test Command 2'
456
+ );
457
+
458
+ expect(mockOnError).toBeCalledTimes(0);
459
+ expect(mockOnShellLogging).toBeCalledTimes(0);
460
+ expect(mockOnUnknown).toBeCalledTimes(0);
461
+ });
462
+
463
+ test('Verify onError and onSuccess is called for the appropriate responses', async () => {
464
+ const shellParser = await CreateShellParser(
465
+ mockModem(),
466
+ mockTerminal(),
467
+ settings
468
+ );
469
+
470
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
471
+ shellParser.onUnknownCommand(mockOnUnknown);
472
+
473
+ await shellParser.enqueueRequest('Test Command 1', {
474
+ onSuccess: mockOnSuccess,
475
+ onError: mockOnError,
476
+ });
477
+
478
+ await shellParser.enqueueRequest('Test Command 2', {
479
+ onSuccess: mockOnSuccess,
480
+ onError: mockOnError,
481
+ });
482
+
483
+ expect(mockOnError).toBeCalledTimes(0);
484
+
485
+ onResponseCallback(
486
+ Buffer.from(
487
+ 'Test Command 1\r\nerror: Response Value 1\r\nuart:~$Test Command 2\r\nResponse Value 2\r\nuart:~$'
488
+ )
489
+ );
490
+
491
+ expect(mockOnError).toBeCalledTimes(1);
492
+ expect(mockOnError).toBeCalledWith(
493
+ 'error: Response Value 1',
494
+ 'Test Command 1'
495
+ );
496
+
497
+ expect(mockOnSuccess).toBeCalledTimes(1);
498
+ expect(mockOnSuccess).toBeCalledWith(
499
+ 'Response Value 2',
500
+ 'Test Command 2'
501
+ );
502
+
503
+ expect(mockOnShellLogging).toBeCalledTimes(0);
504
+ expect(mockOnUnknown).toBeCalledTimes(0);
505
+ });
506
+
507
+ test('Verify permanent onSuccess callback is called when we have a response in one stream', async () => {
508
+ const shellParser = await CreateShellParser(
509
+ mockModem(),
510
+ mockTerminal(),
511
+ settings
512
+ );
513
+
514
+ shellParser.registerCommandCallback(
515
+ 'Test Command',
516
+ mockOnSuccess,
517
+ mockOnError
518
+ );
519
+
520
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
521
+ shellParser.onUnknownCommand(mockOnUnknown);
522
+
523
+ await shellParser.enqueueRequest('Test Command');
524
+
525
+ expect(mockOnSuccess).toBeCalledTimes(0);
526
+
527
+ onResponseCallback(
528
+ Buffer.from('Test Command\r\nResponse Value\r\nuart:~$')
529
+ );
530
+
531
+ expect(mockOnSuccess).toBeCalledTimes(1);
532
+ expect(mockOnSuccess).toBeCalledWith('Response Value', 'Test Command');
533
+
534
+ await shellParser.enqueueRequest('Test Command');
535
+
536
+ onResponseCallback(
537
+ Buffer.from('Test Command\r\nResponse Value\r\nuart:~$')
538
+ );
539
+
540
+ expect(mockOnSuccess).toBeCalledTimes(2);
541
+ expect(mockOnSuccess).toBeCalledWith('Response Value', 'Test Command');
542
+
543
+ expect(mockOnError).toBeCalledTimes(0);
544
+ expect(mockOnShellLogging).toBeCalledTimes(0);
545
+ expect(mockOnUnknown).toBeCalledTimes(0);
546
+ });
547
+
548
+ test('Verify permanent onSuccess callback is called when we have a response in multiple streams', async () => {
549
+ const shellParser = await CreateShellParser(
550
+ mockModem(),
551
+ mockTerminal(),
552
+ settings
553
+ );
554
+
555
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
556
+ shellParser.onUnknownCommand(mockOnUnknown);
557
+
558
+ shellParser.registerCommandCallback(
559
+ 'Test Command',
560
+ mockOnSuccess,
561
+ mockOnError
562
+ );
563
+ await shellParser.enqueueRequest('Test Command');
564
+
565
+ expect(mockOnSuccess).toBeCalledTimes(0);
566
+
567
+ onResponseCallback(Buffer.from('Test Com'));
568
+
569
+ onResponseCallback(Buffer.from('mand\r\nResponse Val'));
570
+
571
+ expect(mockOnSuccess).toBeCalledTimes(0);
572
+
573
+ onResponseCallback(Buffer.from('ue\r\nuart:~$'));
574
+
575
+ expect(mockOnSuccess).toBeCalledTimes(1);
576
+ expect(mockOnSuccess).toBeCalledWith('Response Value', 'Test Command');
577
+
578
+ expect(mockOnError).toBeCalledTimes(0);
579
+ expect(mockOnShellLogging).toBeCalledTimes(0);
580
+ expect(mockOnUnknown).toBeCalledTimes(0);
581
+ });
582
+
583
+ test('Verify onAnyCommand is called with success when we have a response', async () => {
584
+ const shellParser = await CreateShellParser(
585
+ mockModem(),
586
+ mockTerminal(),
587
+ settings
588
+ );
589
+
590
+ shellParser.onAnyCommandResponse(mockOnAnyCommandResponse);
591
+
592
+ await shellParser.enqueueRequest('Test Command');
593
+
594
+ onResponseCallback(
595
+ Buffer.from('Test Command\r\nResponse Value\r\nuart:~$')
596
+ );
597
+
598
+ expect(mockOnAnyCommandResponse).toBeCalledTimes(1);
599
+ expect(mockOnAnyCommandResponse).toBeCalledWith({
600
+ response: 'Response Value',
601
+ command: 'Test Command',
602
+ error: false,
603
+ });
604
+ });
605
+
606
+ test('Verify onAnyCommand is called with error when we have a response', async () => {
607
+ const shellParser = await CreateShellParser(
608
+ mockModem(),
609
+ mockTerminal(),
610
+ settings
611
+ );
612
+
613
+ shellParser.onAnyCommandResponse(mockOnAnyCommandResponse);
614
+
615
+ await shellParser.enqueueRequest('Test Command');
616
+
617
+ onResponseCallback(
618
+ Buffer.from('Test Command\r\nResponse Value\r\nuart:~$')
619
+ );
620
+
621
+ expect(mockOnAnyCommandResponse).toBeCalledTimes(1);
622
+ expect(mockOnAnyCommandResponse).toBeCalledWith({
623
+ response: 'Response Value',
624
+ command: 'Test Command',
625
+ error: false,
626
+ });
627
+ });
628
+
629
+ test('Verify permanent onFail callback is called when we have a response in one stream', async () => {
630
+ const shellParser = await CreateShellParser(
631
+ mockModem(),
632
+ mockTerminal(),
633
+ settings
634
+ );
635
+
636
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
637
+ shellParser.onUnknownCommand(mockOnUnknown);
638
+
639
+ shellParser.registerCommandCallback(
640
+ 'Test Command',
641
+ mockOnSuccess,
642
+ mockOnError
643
+ );
644
+ await shellParser.enqueueRequest('Test Command');
645
+
646
+ expect(mockOnError).toBeCalledTimes(0);
647
+
648
+ onResponseCallback(
649
+ Buffer.from('Test Command\r\nerror: Response Value\r\nuart:~$')
650
+ );
651
+
652
+ expect(mockOnError).toBeCalledTimes(1);
653
+ expect(mockOnError).toBeCalledWith(
654
+ 'error: Response Value',
655
+ 'Test Command'
656
+ );
657
+
658
+ expect(mockOnSuccess).toBeCalledTimes(0);
659
+
660
+ onResponseCallback(
661
+ Buffer.from('Test Command\r\nerror: Response Value\r\nuart:~$')
662
+ );
663
+
664
+ expect(mockOnError).toBeCalledTimes(2);
665
+ expect(mockOnError).toBeCalledWith(
666
+ 'error: Response Value',
667
+ 'Test Command'
668
+ );
669
+
670
+ expect(mockOnSuccess).toBeCalledTimes(0);
671
+ expect(mockOnShellLogging).toBeCalledTimes(0);
672
+ expect(mockOnUnknown).toBeCalledTimes(0);
673
+ });
674
+
675
+ test('Verify one time onFail callback is called when we have a response in multiple streams', async () => {
676
+ const shellParser = await CreateShellParser(
677
+ mockModem(),
678
+ mockTerminal(),
679
+ settings
680
+ );
681
+
682
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
683
+ shellParser.onUnknownCommand(mockOnUnknown);
684
+
685
+ shellParser.registerCommandCallback(
686
+ 'Test Command',
687
+ mockOnSuccess,
688
+ mockOnError
689
+ );
690
+ await shellParser.enqueueRequest('Test Command');
691
+
692
+ expect(mockOnError).toBeCalledTimes(0);
693
+
694
+ onResponseCallback(Buffer.from('Test Command\r\nerror: Re'));
695
+
696
+ onResponseCallback(Buffer.from('sponse Value\r\nuart'));
697
+
698
+ expect(mockOnError).toBeCalledTimes(0);
699
+
700
+ onResponseCallback(Buffer.from(':~$'));
701
+
702
+ expect(mockOnError).toBeCalledTimes(1);
703
+ expect(mockOnError).toBeCalledWith(
704
+ 'error: Response Value',
705
+ 'Test Command'
706
+ );
707
+
708
+ expect(mockOnSuccess).toBeCalledTimes(0);
709
+ expect(mockOnShellLogging).toBeCalledTimes(0);
710
+ expect(mockOnUnknown).toBeCalledTimes(0);
711
+ });
712
+
713
+ test('Verify permanent and one time onSuccess both callback is called when we have a response', async () => {
714
+ const shellParser = await CreateShellParser(
715
+ mockModem(),
716
+ mockTerminal(),
717
+ settings
718
+ );
719
+
720
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
721
+ shellParser.onUnknownCommand(mockOnUnknown);
722
+
723
+ shellParser.registerCommandCallback(
724
+ 'Test Command',
725
+ mockOnSuccess,
726
+ mockOnError
727
+ );
728
+
729
+ await shellParser.enqueueRequest('Test Command', {
730
+ onSuccess: mockOnSuccess,
731
+ onError: mockOnError,
732
+ });
733
+
734
+ expect(mockOnSuccess).toBeCalledTimes(0);
735
+
736
+ onResponseCallback(
737
+ Buffer.from('Test Command\r\nResponse Value\r\nuart:~$')
738
+ );
739
+
740
+ expect(mockOnSuccess).toBeCalledTimes(2);
741
+ expect(mockOnSuccess).toBeCalledWith('Response Value', 'Test Command');
742
+
743
+ expect(mockOnShellLogging).toBeCalledTimes(0);
744
+ expect(mockOnUnknown).toBeCalledTimes(0);
745
+ expect(mockOnError).toBeCalledTimes(0);
746
+ });
747
+
748
+ test('Verify permanent and one time onFail callback is called when we have a response', async () => {
749
+ const shellParser = await CreateShellParser(
750
+ mockModem(),
751
+ mockTerminal(),
752
+ settings
753
+ );
754
+
755
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
756
+ shellParser.onUnknownCommand(mockOnUnknown);
757
+
758
+ shellParser.registerCommandCallback(
759
+ 'Test Command',
760
+ mockOnSuccess,
761
+ mockOnError
762
+ );
763
+ await shellParser.enqueueRequest('Test Command', {
764
+ onSuccess: mockOnSuccess,
765
+ onError: mockOnError,
766
+ });
767
+
768
+ expect(mockOnError).toBeCalledTimes(0);
769
+
770
+ onResponseCallback(
771
+ Buffer.from('Test Command\r\nerror: Response Value\r\nuart:~$')
772
+ );
773
+
774
+ expect(mockOnError).toBeCalledTimes(2);
775
+ expect(mockOnError).toBeCalledWith(
776
+ 'error: Response Value',
777
+ 'Test Command'
778
+ );
779
+
780
+ expect(mockOnSuccess).toBeCalledTimes(0);
781
+ expect(mockOnShellLogging).toBeCalledTimes(0);
782
+ expect(mockOnUnknown).toBeCalledTimes(0);
783
+ });
784
+
785
+ test('Verify onShellLogging callback is called when we have a response logging shell in one stream', async () => {
786
+ const shellParser = await CreateShellParser(
787
+ mockModem(),
788
+ mockTerminal(),
789
+ settings
790
+ );
791
+
792
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
793
+ shellParser.onUnknownCommand(mockOnUnknown);
794
+
795
+ onResponseCallback(
796
+ Buffer.from(
797
+ '[00:01:46.862,640] <inf> main: v=3.595881,i=0.176776\r\n'
798
+ )
799
+ );
800
+
801
+ expect(mockOnShellLogging).toBeCalledTimes(1);
802
+ expect(mockOnShellLogging).toBeCalledWith(
803
+ '[00:01:46.862,640] <inf> main: v=3.595881,i=0.176776'
804
+ );
805
+
806
+ expect(mockOnError).toBeCalledTimes(0);
807
+ expect(mockOnSuccess).toBeCalledTimes(0);
808
+ expect(mockOnUnknown).toBeCalledTimes(0);
809
+ });
810
+
811
+ test('Verify onShellLogging callback is called when we have a response logging shell in multiple streams', async () => {
812
+ const shellParser = await CreateShellParser(
813
+ mockModem(),
814
+ mockTerminal(),
815
+ settings
816
+ );
817
+
818
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
819
+ shellParser.onUnknownCommand(mockOnUnknown);
820
+
821
+ onResponseCallback(
822
+ Buffer.from('[00:00:01.114,532] <inf> main: v=3.595881,i=0')
823
+ );
824
+
825
+ expect(mockOnShellLogging).toBeCalledTimes(0);
826
+
827
+ onResponseCallback(Buffer.from('.176776\r\n'));
828
+
829
+ expect(mockOnShellLogging).toBeCalledTimes(1);
830
+ expect(mockOnShellLogging).toBeCalledWith(
831
+ '[00:00:01.114,532] <inf> main: v=3.595881,i=0.176776'
832
+ );
833
+
834
+ expect(mockOnError).toBeCalledTimes(0);
835
+ expect(mockOnSuccess).toBeCalledTimes(0);
836
+ expect(mockOnUnknown).toBeCalledTimes(0);
837
+ });
838
+
839
+ test('Verify onShellLogging callback is called large timestamp', async () => {
840
+ const shellParser = await CreateShellParser(
841
+ mockModem(),
842
+ mockTerminal(),
843
+ settings
844
+ );
845
+
846
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
847
+ shellParser.onUnknownCommand(mockOnUnknown);
848
+
849
+ onResponseCallback(
850
+ Buffer.from(
851
+ '[1000:00:01.114,532] <inf> main: v=3.595881,i=0.176776\r\n'
852
+ )
853
+ );
854
+
855
+ expect(mockOnShellLogging).toBeCalledTimes(1);
856
+ expect(mockOnShellLogging).toBeCalledWith(
857
+ '[1000:00:01.114,532] <inf> main: v=3.595881,i=0.176776'
858
+ );
859
+
860
+ expect(mockOnError).toBeCalledTimes(0);
861
+ expect(mockOnSuccess).toBeCalledTimes(0);
862
+ expect(mockOnUnknown).toBeCalledTimes(0);
863
+ });
864
+
865
+ test('Verify onUnknown callback is called when we have a response that is not logging nor is it a registered command one stream', async () => {
866
+ const shellParser = await CreateShellParser(
867
+ mockModem(),
868
+ mockTerminal(),
869
+ settings
870
+ );
871
+
872
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
873
+ shellParser.onUnknownCommand(mockOnUnknown);
874
+
875
+ onResponseCallback(
876
+ Buffer.from('Test Command\r\nResponse Value\r\nuart:~$')
877
+ );
878
+
879
+ expect(mockOnUnknown).toBeCalledTimes(1);
880
+ expect(mockOnUnknown).toBeCalledWith('Test Command\r\nResponse Value');
881
+
882
+ expect(mockOnError).toBeCalledTimes(0);
883
+ expect(mockOnSuccess).toBeCalledTimes(0);
884
+ expect(mockOnShellLogging).toBeCalledTimes(0);
885
+ });
886
+
887
+ test('Verify onUnknown callback is called when we have a response that is not logging nor is it a registered command multiple streams', async () => {
888
+ const shellParser = await CreateShellParser(
889
+ mockModem(),
890
+ mockTerminal(),
891
+ settings
892
+ );
893
+ expect(mockOnUnknown).toBeCalledTimes(0);
894
+
895
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
896
+ shellParser.onUnknownCommand(mockOnUnknown);
897
+
898
+ onResponseCallback(Buffer.from('Test Command\r\nRespons'));
899
+
900
+ expect(mockOnUnknown).toBeCalledTimes(0);
901
+
902
+ onResponseCallback(Buffer.from('e Value\r\nuart:~$'));
903
+
904
+ expect(mockOnUnknown).toBeCalledTimes(1);
905
+ expect(mockOnUnknown).toBeCalledWith('Test Command\r\nResponse Value');
906
+
907
+ expect(mockOnError).toBeCalledTimes(0);
908
+ expect(mockOnSuccess).toBeCalledTimes(0);
909
+ expect(mockOnShellLogging).toBeCalledTimes(0);
910
+ });
911
+
912
+ test('Verify permanent callback unregister removes the callback', async () => {
913
+ const shellParser = await CreateShellParser(
914
+ mockModem(),
915
+ mockTerminal(),
916
+ settings
917
+ );
918
+
919
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
920
+ shellParser.onUnknownCommand(mockOnUnknown);
921
+
922
+ const unregister = shellParser.registerCommandCallback(
923
+ 'Test Command',
924
+ mockOnSuccess,
925
+ mockOnError
926
+ );
927
+
928
+ await shellParser.enqueueRequest('Test Command');
929
+
930
+ onResponseCallback(
931
+ Buffer.from('Test Command\r\nResponse Value\r\nuart:~$')
932
+ );
933
+
934
+ expect(mockOnSuccess).toBeCalledTimes(1);
935
+ expect(mockOnSuccess).toBeCalledWith('Response Value', 'Test Command');
936
+
937
+ unregister();
938
+
939
+ await shellParser.enqueueRequest('Test Command');
940
+
941
+ onResponseCallback(
942
+ Buffer.from('Test Command\r\nResponse Value\r\nuart:~$')
943
+ );
944
+
945
+ expect(mockOnSuccess).toBeCalledTimes(1);
946
+ expect(mockOnUnknown).toBeCalledTimes(0);
947
+ expect(mockOnError).toBeCalledTimes(0);
948
+ expect(mockOnShellLogging).toBeCalledTimes(0);
949
+ });
950
+
951
+ test('Verify permanent callback unregister removes the right callback', async () => {
952
+ const mockOnSuccess1 = jest.fn(() => '');
953
+ const mockOnSuccess2 = jest.fn(() => '');
954
+ const mockOnSuccess3 = jest.fn(() => '');
955
+
956
+ const shellParser = await CreateShellParser(
957
+ mockModem(),
958
+ mockTerminal(),
959
+ settings
960
+ );
961
+
962
+ shellParser.onShellLoggingEvent(mockOnShellLogging);
963
+ shellParser.onUnknownCommand(mockOnUnknown);
964
+
965
+ shellParser.registerCommandCallback(
966
+ 'Test Command',
967
+ mockOnSuccess1,
968
+ mockOnError
969
+ );
970
+
971
+ const unregister2 = shellParser.registerCommandCallback(
972
+ 'Test Command',
973
+ mockOnSuccess2,
974
+ mockOnError
975
+ );
976
+
977
+ const unregister3 = shellParser.registerCommandCallback(
978
+ 'Test Command',
979
+ mockOnSuccess3,
980
+ mockOnError
981
+ );
982
+
983
+ await shellParser.enqueueRequest('Test Command');
984
+
985
+ onResponseCallback(
986
+ Buffer.from('Test Command\r\nResponse Value\r\nuart:~$')
987
+ );
988
+
989
+ expect(mockOnSuccess1).toBeCalledTimes(1);
990
+ expect(mockOnSuccess1).toBeCalledWith('Response Value', 'Test Command');
991
+
992
+ expect(mockOnSuccess2).toBeCalledTimes(1);
993
+ expect(mockOnSuccess2).toBeCalledWith('Response Value', 'Test Command');
994
+
995
+ expect(mockOnSuccess3).toBeCalledTimes(1);
996
+ expect(mockOnSuccess3).toBeCalledWith('Response Value', 'Test Command');
997
+
998
+ unregister2();
999
+
1000
+ await shellParser.enqueueRequest('Test Command');
1001
+
1002
+ onResponseCallback(
1003
+ Buffer.from('Test Command\r\nResponse Value\r\nuart:~$')
1004
+ );
1005
+
1006
+ expect(mockOnSuccess1).toBeCalledTimes(2);
1007
+ expect(mockOnSuccess1).toBeCalledWith('Response Value', 'Test Command');
1008
+
1009
+ expect(mockOnSuccess2).toBeCalledTimes(1);
1010
+
1011
+ expect(mockOnSuccess3).toBeCalledTimes(2);
1012
+ expect(mockOnSuccess3).toBeCalledWith('Response Value', 'Test Command');
1013
+
1014
+ unregister3();
1015
+
1016
+ await shellParser.enqueueRequest('Test Command');
1017
+
1018
+ onResponseCallback(
1019
+ Buffer.from('Test Command\r\nResponse Value\r\nuart:~$')
1020
+ );
1021
+
1022
+ expect(mockOnSuccess1).toBeCalledTimes(3);
1023
+ expect(mockOnSuccess1).toBeCalledWith('Response Value', 'Test Command');
1024
+ expect(mockOnSuccess2).toBeCalledTimes(1);
1025
+ expect(mockOnSuccess3).toBeCalledTimes(2);
1026
+
1027
+ expect(mockOnUnknown).toBeCalledTimes(0);
1028
+ expect(mockOnError).toBeCalledTimes(0);
1029
+ expect(mockOnShellLogging).toBeCalledTimes(0);
1030
+ });
1031
+ });
1032
+
1033
+ export {};