sportident.js 1.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 (151) hide show
  1. package/.dependency-cruiser.js +233 -0
  2. package/.editorconfig +12 -0
  3. package/.eslintignore +6 -0
  4. package/.github/ISSUE_TEMPLATE/bug_report.md +35 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
  6. package/.github/workflows/npm.yml +17 -0
  7. package/LICENSE +21 -0
  8. package/README.md +31 -0
  9. package/babel.config.js +21 -0
  10. package/build-docs.sh +25 -0
  11. package/docs/index.md +9 -0
  12. package/docs/typedoc/index.md +11 -0
  13. package/eslint.base.js +232 -0
  14. package/install.sh +6 -0
  15. package/jest.config.ts +49 -0
  16. package/nx.json +39 -0
  17. package/package.json +51 -0
  18. package/src/SiCard/BaseSiCard.test.ts +187 -0
  19. package/src/SiCard/BaseSiCard.ts +101 -0
  20. package/src/SiCard/IRaceResultData.ts +16 -0
  21. package/src/SiCard/ISiCard.ts +23 -0
  22. package/src/SiCard/ISiCardExamples.ts +4 -0
  23. package/src/SiCard/index.ts +2 -0
  24. package/src/SiCard/raceResultTools.test.ts +260 -0
  25. package/src/SiCard/raceResultTools.ts +150 -0
  26. package/src/SiCard/types/FCard.test.ts +19 -0
  27. package/src/SiCard/types/FCard.ts +14 -0
  28. package/src/SiCard/types/ModernSiCard.test.ts +186 -0
  29. package/src/SiCard/types/ModernSiCard.ts +241 -0
  30. package/src/SiCard/types/PCard.test.ts +19 -0
  31. package/src/SiCard/types/PCard.ts +14 -0
  32. package/src/SiCard/types/SIAC.test.ts +84 -0
  33. package/src/SiCard/types/SIAC.ts +19 -0
  34. package/src/SiCard/types/SiCard10.test.ts +85 -0
  35. package/src/SiCard/types/SiCard10.ts +17 -0
  36. package/src/SiCard/types/SiCard11.test.ts +84 -0
  37. package/src/SiCard/types/SiCard11.ts +19 -0
  38. package/src/SiCard/types/SiCard5.test.ts +149 -0
  39. package/src/SiCard/types/SiCard5.ts +129 -0
  40. package/src/SiCard/types/SiCard6.test.ts +179 -0
  41. package/src/SiCard/types/SiCard6.ts +222 -0
  42. package/src/SiCard/types/SiCard8.test.ts +137 -0
  43. package/src/SiCard/types/SiCard8.ts +129 -0
  44. package/src/SiCard/types/SiCard9.test.ts +132 -0
  45. package/src/SiCard/types/SiCard9.ts +128 -0
  46. package/src/SiCard/types/TCard.test.ts +19 -0
  47. package/src/SiCard/types/TCard.ts +14 -0
  48. package/src/SiCard/types/index.test.ts +26 -0
  49. package/src/SiCard/types/index.ts +15 -0
  50. package/src/SiCard/types/modernSiCardExamples.ts +364 -0
  51. package/src/SiCard/types/siCard5Examples.ts +73 -0
  52. package/src/SiCard/types/siCard6Examples.ts +262 -0
  53. package/src/SiCard/types/siCard8Examples.ts +152 -0
  54. package/src/SiCard/types/siCard9Examples.ts +143 -0
  55. package/src/SiDevice/INavigatorWebSerial.ts +78 -0
  56. package/src/SiDevice/INavigatorWebUsb.ts +62 -0
  57. package/src/SiDevice/ISiDevice.ts +48 -0
  58. package/src/SiDevice/ISiDeviceDriver.ts +35 -0
  59. package/src/SiDevice/README.md +13 -0
  60. package/src/SiDevice/SiDevice.test.ts +354 -0
  61. package/src/SiDevice/SiDevice.ts +132 -0
  62. package/src/SiDevice/WebSerialSiDeviceDriver.ts +146 -0
  63. package/src/SiDevice/WebUsbSiDeviceDriver.ts +343 -0
  64. package/src/SiDevice/index.ts +3 -0
  65. package/src/SiDevice/testUtils/index.ts +2 -0
  66. package/src/SiDevice/testUtils/testISiDeviceDriver.ts +63 -0
  67. package/src/SiDevice/testUtils/testISiDeviceDriverWithAutodetection.ts +72 -0
  68. package/src/SiStation/BaseSiStation.test.ts +221 -0
  69. package/src/SiStation/BaseSiStation.ts +253 -0
  70. package/src/SiStation/CoupledSiStation.test.ts +41 -0
  71. package/src/SiStation/CoupledSiStation.ts +130 -0
  72. package/src/SiStation/ISiMainStation.ts +29 -0
  73. package/src/SiStation/ISiSendTask.ts +9 -0
  74. package/src/SiStation/ISiStation.ts +88 -0
  75. package/src/SiStation/ISiTargetMultiplexer.ts +51 -0
  76. package/src/SiStation/SiMainStation.test.ts +222 -0
  77. package/src/SiStation/SiMainStation.ts +133 -0
  78. package/src/SiStation/SiSendTask.ts +50 -0
  79. package/src/SiStation/SiTargetMultiplexer.targeting.test.ts +112 -0
  80. package/src/SiStation/SiTargetMultiplexer.test.ts +605 -0
  81. package/src/SiStation/SiTargetMultiplexer.ts +241 -0
  82. package/src/SiStation/index.ts +5 -0
  83. package/src/SiStation/siStationExamples.ts +103 -0
  84. package/src/constants.test.ts +17 -0
  85. package/src/constants.ts +92 -0
  86. package/src/fakes/FakeSiCard/BaseFakeSiCard.test.ts +11 -0
  87. package/src/fakes/FakeSiCard/BaseFakeSiCard.ts +10 -0
  88. package/src/fakes/FakeSiCard/IFakeSiCard.ts +6 -0
  89. package/src/fakes/FakeSiCard/index.ts +2 -0
  90. package/src/fakes/FakeSiCard/types/FakeModernSiCard.test.ts +62 -0
  91. package/src/fakes/FakeSiCard/types/FakeModernSiCard.ts +43 -0
  92. package/src/fakes/FakeSiCard/types/FakeSIAC.ts +17 -0
  93. package/src/fakes/FakeSiCard/types/FakeSiCard10.ts +17 -0
  94. package/src/fakes/FakeSiCard/types/FakeSiCard11.ts +17 -0
  95. package/src/fakes/FakeSiCard/types/FakeSiCard5.test.ts +42 -0
  96. package/src/fakes/FakeSiCard/types/FakeSiCard5.ts +40 -0
  97. package/src/fakes/FakeSiCard/types/FakeSiCard6.test.ts +62 -0
  98. package/src/fakes/FakeSiCard/types/FakeSiCard6.ts +44 -0
  99. package/src/fakes/FakeSiCard/types/FakeSiCard8.ts +16 -0
  100. package/src/fakes/FakeSiCard/types/FakeSiCard9.ts +16 -0
  101. package/src/fakes/FakeSiCard/types/index.ts +7 -0
  102. package/src/fakes/FakeSiDeviceDriver.ts +148 -0
  103. package/src/fakes/FakeSiMainStation.test.ts +141 -0
  104. package/src/fakes/FakeSiMainStation.ts +118 -0
  105. package/src/fakes/IFakeSiMainStation.ts +15 -0
  106. package/src/fakes/index.ts +2 -0
  107. package/src/index.ts +24 -0
  108. package/src/siProtocol.test.ts +509 -0
  109. package/src/siProtocol.ts +417 -0
  110. package/src/storage/SiArray.test.ts +103 -0
  111. package/src/storage/SiArray.ts +56 -0
  112. package/src/storage/SiBool.test.ts +81 -0
  113. package/src/storage/SiBool.ts +47 -0
  114. package/src/storage/SiDataType.test.ts +81 -0
  115. package/src/storage/SiDataType.ts +60 -0
  116. package/src/storage/SiDict.test.ts +115 -0
  117. package/src/storage/SiDict.ts +60 -0
  118. package/src/storage/SiEnum.test.ts +77 -0
  119. package/src/storage/SiEnum.ts +48 -0
  120. package/src/storage/SiFieldValue.test.ts +58 -0
  121. package/src/storage/SiFieldValue.ts +23 -0
  122. package/src/storage/SiInt.test.ts +80 -0
  123. package/src/storage/SiInt.ts +84 -0
  124. package/src/storage/SiModified.test.ts +135 -0
  125. package/src/storage/SiModified.ts +59 -0
  126. package/src/storage/SiStorage.test.ts +51 -0
  127. package/src/storage/SiStorage.ts +44 -0
  128. package/src/storage/index.test.ts +222 -0
  129. package/src/storage/index.ts +12 -0
  130. package/src/storage/interfaces.ts +41 -0
  131. package/src/storage/siStringEncoding.ts +1361 -0
  132. package/src/testUtils.test.ts +266 -0
  133. package/src/testUtils.ts +75 -0
  134. package/src/utils/NumberRange.test.ts +66 -0
  135. package/src/utils/NumberRange.ts +46 -0
  136. package/src/utils/NumberRangeRegistry.test.ts +49 -0
  137. package/src/utils/NumberRangeRegistry.ts +43 -0
  138. package/src/utils/bytes.test.ts +126 -0
  139. package/src/utils/bytes.ts +69 -0
  140. package/src/utils/errors.test.ts +29 -0
  141. package/src/utils/errors.ts +20 -0
  142. package/src/utils/events.test.ts +112 -0
  143. package/src/utils/events.ts +68 -0
  144. package/src/utils/general.test.ts +139 -0
  145. package/src/utils/general.ts +69 -0
  146. package/src/utils/index.ts +8 -0
  147. package/src/utils/mixins.test.ts +40 -0
  148. package/src/utils/mixins.ts +13 -0
  149. package/src/utils/typed.ts +3 -0
  150. package/tsconfig.base.json +22 -0
  151. package/tsconfig.json +15 -0
@@ -0,0 +1,605 @@
1
+ import { describe, expect, test } from '@jest/globals';
2
+ import { proto } from '../constants';
3
+ import * as siProtocol from '../siProtocol';
4
+ import * as testUtils from '../testUtils';
5
+ import { SiDeviceState, SiDeviceReceiveEvent, type ISiDeviceDriverData } from '../SiDevice/ISiDevice';
6
+ import type { ISiDeviceDriver } from '../SiDevice/ISiDeviceDriver';
7
+ import { SiDevice } from '../SiDevice/SiDevice';
8
+ import { SiTargetMultiplexerDirectMessageEvent, SiTargetMultiplexerMessageEvent, SiTargetMultiplexerRemoteMessageEvent, SiTargetMultiplexerTarget } from './ISiTargetMultiplexer';
9
+ import { SiSendTaskState } from './ISiSendTask';
10
+ import { DIRECT_DEVICE_INITIATED_COMMANDS, SiTargetMultiplexer } from './SiTargetMultiplexer';
11
+
12
+ testUtils.useFakeTimers();
13
+
14
+ function mockDriver(driver: Partial<ISiDeviceDriver<ISiDeviceDriverData<unknown>>>) {
15
+ return driver as unknown as ISiDeviceDriver<ISiDeviceDriverData<unknown>>;
16
+ }
17
+
18
+ describe('SiTargetMultiplexer', () => {
19
+ test('is unique per device', () => {
20
+ const siDevice = new SiDevice('isUniquePerDevice', {
21
+ driver: mockDriver({ name: 'FakeSiDevice' })
22
+ });
23
+ siDevice.setState(SiDeviceState.Opened);
24
+ const muxer1 = SiTargetMultiplexer.fromSiDevice(siDevice);
25
+ expect(muxer1 instanceof SiTargetMultiplexer).toBe(true);
26
+ const muxer2 = SiTargetMultiplexer.fromSiDevice(siDevice);
27
+ expect(muxer2).toBe(muxer1);
28
+ });
29
+
30
+ test('handles receiving', () => {
31
+ const siDevice = new SiDevice('handlesReceiving', {
32
+ driver: mockDriver({})
33
+ });
34
+ siDevice.setState(SiDeviceState.Opened);
35
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
36
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
37
+
38
+ const receivedMessages: siProtocol.SiMessage[] = [];
39
+ const recordMessage = (e: SiTargetMultiplexerMessageEvent) => {
40
+ receivedMessages.push(e.message);
41
+ };
42
+ muxer.addEventListener('message', recordMessage);
43
+
44
+ const receivedDirectMessages: siProtocol.SiMessage[] = [];
45
+ const recordDirectMessage = (e: SiTargetMultiplexerDirectMessageEvent) => {
46
+ receivedDirectMessages.push(e.message);
47
+ };
48
+ muxer.addEventListener('directMessage', recordDirectMessage);
49
+
50
+ const receivedRemoteMessages: siProtocol.SiMessage[] = [];
51
+ const recordRemoteMessage = (e: SiTargetMultiplexerRemoteMessageEvent) => {
52
+ receivedRemoteMessages.push(e.message);
53
+ };
54
+ muxer.addEventListener('remoteMessage', recordRemoteMessage);
55
+
56
+ const directOnlyCommands = Object.keys(DIRECT_DEVICE_INITIATED_COMMANDS).map(Number);
57
+ const randomMessage1 = testUtils.getRandomMessage({
58
+ command: testUtils.getRandomByteExcept(directOnlyCommands)
59
+ });
60
+ siDevice.dispatchEvent('receive', new SiDeviceReceiveEvent(siDevice, siProtocol.render(randomMessage1)));
61
+ expect(receivedMessages).toEqual([randomMessage1]);
62
+ expect(receivedDirectMessages).toEqual([]);
63
+ expect(receivedRemoteMessages).toEqual([]);
64
+
65
+ const randomMessage2 = testUtils.getRandomMessage({
66
+ command: testUtils.getRandomByteExcept(directOnlyCommands)
67
+ });
68
+ muxer.target = SiTargetMultiplexerTarget.Direct;
69
+ siDevice.dispatchEvent('receive', new SiDeviceReceiveEvent(siDevice, siProtocol.render(randomMessage2)));
70
+ expect(receivedMessages).toEqual([randomMessage1, randomMessage2]);
71
+ expect(receivedDirectMessages).toEqual([randomMessage2]);
72
+ expect(receivedRemoteMessages).toEqual([]);
73
+
74
+ const randomMessage3 = testUtils.getRandomMessage({
75
+ command: testUtils.getRandomByteExcept(directOnlyCommands)
76
+ });
77
+ muxer.target = SiTargetMultiplexerTarget.Remote;
78
+ siDevice.dispatchEvent('receive', new SiDeviceReceiveEvent(siDevice, siProtocol.render(randomMessage3)));
79
+ expect(receivedMessages).toEqual([randomMessage1, randomMessage2, randomMessage3]);
80
+ expect(receivedDirectMessages).toEqual([randomMessage2]);
81
+ expect(receivedRemoteMessages).toEqual([randomMessage3]);
82
+
83
+ muxer.removeEventListener('message', recordMessage);
84
+ muxer.removeEventListener('directMessage', recordDirectMessage);
85
+ muxer.removeEventListener('remoteMessage', recordRemoteMessage);
86
+ });
87
+
88
+ test('handles simple sending', async () => {
89
+ const siDevice = new SiDevice('handlesSending0', {
90
+ driver: mockDriver({
91
+ send: () => Promise.resolve()
92
+ })
93
+ });
94
+ siDevice.setState(SiDeviceState.Opened);
95
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
96
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
97
+
98
+ const randomMessage = testUtils.getRandomMessage({});
99
+ const timeState = { sendingFinished: false };
100
+ muxer.sendMessageToLatestTarget(randomMessage, 0, 1).then((responses) => {
101
+ expect(responses.length).toBe(0);
102
+ expect(muxer._test.sendQueue.length).toBe(0);
103
+ timeState.sendingFinished = true;
104
+ });
105
+ await testUtils.advanceTimersByTime(0);
106
+ expect(timeState).toEqual({ sendingFinished: true });
107
+ });
108
+
109
+ test('handles sending and waiting for 1 response', async () => {
110
+ const siDevice = new SiDevice('handlesSending1', {
111
+ driver: mockDriver({
112
+ send: () => Promise.resolve()
113
+ })
114
+ });
115
+ siDevice.setState(SiDeviceState.Opened);
116
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
117
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
118
+
119
+ const randomMessage = testUtils.getRandomMessage({});
120
+ const timeState = { sendingFinished: false };
121
+ muxer.sendMessageToLatestTarget(randomMessage, 1, 2).then((responses) => {
122
+ expect(responses.length).toBe(1);
123
+ expect(muxer._test.sendQueue.length).toBe(0);
124
+ timeState.sendingFinished = true;
125
+ });
126
+ setTimeout(() => {
127
+ siDevice.dispatchEvent('receive', new SiDeviceReceiveEvent(siDevice, siProtocol.render(randomMessage)));
128
+ }, 1);
129
+ await testUtils.advanceTimersByTime(0);
130
+ expect(timeState).toEqual({ sendingFinished: false });
131
+ await testUtils.advanceTimersByTime(1);
132
+ expect(timeState).toEqual({ sendingFinished: true });
133
+ });
134
+
135
+ test('handles sending and waiting for 1 NAK', async () => {
136
+ const siDevice = new SiDevice('handlesSending1NAK', {
137
+ driver: mockDriver({
138
+ send: () => Promise.resolve()
139
+ })
140
+ });
141
+ siDevice.setState(SiDeviceState.Opened);
142
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
143
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
144
+
145
+ const randomMessage = testUtils.getRandomMessage({});
146
+ const timeState = { sendingFailed: false };
147
+ muxer.sendMessageToLatestTarget(randomMessage, 1, 2).catch(() => {
148
+ expect(muxer._test.sendQueue.length).toBe(0);
149
+ timeState.sendingFailed = true;
150
+ });
151
+ setTimeout(() => {
152
+ siDevice.dispatchEvent('receive', new SiDeviceReceiveEvent(siDevice, siProtocol.render({ mode: proto.NAK })));
153
+ }, 1);
154
+ await testUtils.advanceTimersByTime(0);
155
+ expect(timeState).toEqual({ sendingFailed: false });
156
+ await testUtils.advanceTimersByTime(1);
157
+ expect(timeState).toEqual({ sendingFailed: true });
158
+ });
159
+
160
+ test('handles sending and waiting for 2 responses', async () => {
161
+ const siDevice = new SiDevice('handlesSending2', {
162
+ driver: mockDriver({
163
+ send: () => Promise.resolve()
164
+ })
165
+ });
166
+ siDevice.setState(SiDeviceState.Opened);
167
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
168
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
169
+
170
+ const randomMessage = testUtils.getRandomMessage({});
171
+ const timeState = { receive1: false, receive2: false, sendingFinished: false };
172
+ muxer.sendMessageToLatestTarget(randomMessage, 2, 3).then((responses) => {
173
+ expect(responses.length).toBe(2);
174
+ expect(muxer._test.sendQueue.length).toBe(0);
175
+ timeState.sendingFinished = true;
176
+ });
177
+ setTimeout(() => {
178
+ siDevice.dispatchEvent('receive', new SiDeviceReceiveEvent(siDevice, siProtocol.render(randomMessage)));
179
+ timeState.receive1 = true;
180
+ }, 1);
181
+ setTimeout(() => {
182
+ siDevice.dispatchEvent('receive', new SiDeviceReceiveEvent(siDevice, siProtocol.render(randomMessage)));
183
+ timeState.receive2 = true;
184
+ }, 2);
185
+ await testUtils.advanceTimersByTime(0);
186
+ expect(timeState).toEqual({ receive1: false, receive2: false, sendingFinished: false });
187
+ await testUtils.advanceTimersByTime(1);
188
+ expect(timeState).toEqual({ receive1: true, receive2: false, sendingFinished: false });
189
+ await testUtils.nTimesAsync(10, () => testUtils.advanceTimersByTime(1));
190
+ expect(timeState).toEqual({ receive1: true, receive2: true, sendingFinished: true });
191
+ });
192
+
193
+ test('handles sending and timing out waiting for 1 response', async () => {
194
+ const siDevice = new SiDevice('handlesSending1Timeout', {
195
+ driver: mockDriver({
196
+ send: () => Promise.resolve()
197
+ })
198
+ });
199
+ siDevice.setState(SiDeviceState.Opened);
200
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
201
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
202
+
203
+ const randomMessage = testUtils.getRandomMessage({});
204
+ const timeState = { timedOut: false };
205
+ muxer.sendMessageToLatestTarget(randomMessage, 1, 1).catch(() => {
206
+ expect(muxer._test.sendQueue.length).toBe(0);
207
+ timeState.timedOut = true;
208
+ });
209
+ await testUtils.advanceTimersByTime(0);
210
+ expect(timeState).toEqual({ timedOut: false });
211
+ await testUtils.advanceTimersByTime(1);
212
+ expect(timeState).toEqual({ timedOut: true });
213
+ });
214
+
215
+ test('handles sending and timing out waiting for 2 responses', async () => {
216
+ const siDevice = new SiDevice('handlesSending2Timeout', {
217
+ driver: mockDriver({
218
+ send: () => Promise.resolve()
219
+ })
220
+ });
221
+ siDevice.setState(SiDeviceState.Opened);
222
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
223
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
224
+
225
+ const randomMessage = testUtils.getRandomMessage({});
226
+ const timeState = { receive1: false, timedOut: false };
227
+ muxer.sendMessageToLatestTarget(randomMessage, 2, 2).catch(() => {
228
+ expect(muxer._test.sendQueue.length).toBe(0);
229
+ timeState.timedOut = true;
230
+ });
231
+ setTimeout(() => {
232
+ siDevice.dispatchEvent('receive', new SiDeviceReceiveEvent(siDevice, siProtocol.render(randomMessage)));
233
+ timeState.receive1 = true;
234
+ }, 1);
235
+ await testUtils.advanceTimersByTime(0);
236
+ expect(timeState).toEqual({ receive1: false, timedOut: false });
237
+ await testUtils.advanceTimersByTime(1);
238
+ expect(timeState).toEqual({ receive1: true, timedOut: false });
239
+ await testUtils.advanceTimersByTime(1);
240
+ expect(timeState).toEqual({ receive1: true, timedOut: true });
241
+ });
242
+
243
+ test('does not time out, if it already succeeded', async () => {
244
+ const siDevice = new SiDevice('noTimeoutIfSucceeded', {
245
+ driver: mockDriver({
246
+ send: () => Promise.resolve()
247
+ })
248
+ });
249
+ siDevice.setState(SiDeviceState.Opened);
250
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
251
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
252
+
253
+ const randomMessage = testUtils.getRandomMessage({});
254
+ const timeoutInMiliseconds = 2;
255
+ const timeState = {
256
+ madeSuccessful: false,
257
+ timeoutPassed: false,
258
+ timedOut: false,
259
+ succeeded: false
260
+ };
261
+ muxer
262
+ .sendMessageToLatestTarget(randomMessage, 1, timeoutInMiliseconds)
263
+ .then(() => {
264
+ timeState.succeeded = true;
265
+ })
266
+ .catch(() => {
267
+ timeState.timedOut = true;
268
+ });
269
+ setTimeout(() => {
270
+ muxer._test.sendQueue[0].state = SiSendTaskState.Succeeded;
271
+ timeState.madeSuccessful = true;
272
+ }, 1);
273
+ setTimeout(() => {
274
+ timeState.timeoutPassed = true;
275
+ }, timeoutInMiliseconds);
276
+ await testUtils.advanceTimersByTime(0);
277
+ expect(timeState).toEqual({
278
+ madeSuccessful: false,
279
+ timeoutPassed: false,
280
+ timedOut: false,
281
+ succeeded: false
282
+ });
283
+ await testUtils.advanceTimersByTime(1);
284
+ expect(timeState).toEqual({
285
+ madeSuccessful: true,
286
+ timeoutPassed: false,
287
+ timedOut: false,
288
+ succeeded: false
289
+ });
290
+ await testUtils.advanceTimersByTime(1);
291
+ expect(timeState).toEqual({
292
+ madeSuccessful: true,
293
+ timeoutPassed: true,
294
+ timedOut: false,
295
+ succeeded: false
296
+ });
297
+ });
298
+
299
+ test('does not succeed, if response for different command arrives', async () => {
300
+ const siDevice = new SiDevice('differentCommand', {
301
+ driver: mockDriver({
302
+ send: () => Promise.resolve()
303
+ })
304
+ });
305
+ siDevice.setState(SiDeviceState.Opened);
306
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
307
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
308
+
309
+ const randomMessage = testUtils.getRandomMessage({});
310
+ const timeState = { receive1: false, timedOut: false, succeeded: false };
311
+ muxer
312
+ .sendMessageToLatestTarget(randomMessage, 1, 2)
313
+ .then(() => {
314
+ timeState.succeeded = true;
315
+ })
316
+ .catch(() => {
317
+ expect(muxer._test.sendQueue.length).toBe(0);
318
+ timeState.timedOut = true;
319
+ });
320
+ setTimeout(() => {
321
+ siDevice.dispatchEvent(
322
+ 'receive',
323
+ new SiDeviceReceiveEvent(
324
+ siDevice,
325
+ siProtocol.render({
326
+ command: testUtils.getRandomByteExcept([randomMessage.command]),
327
+ parameters: randomMessage.parameters
328
+ })
329
+ )
330
+ );
331
+ timeState.receive1 = true;
332
+ }, 1);
333
+ await testUtils.advanceTimersByTime(0);
334
+ expect(timeState).toEqual({ receive1: false, timedOut: false, succeeded: false });
335
+ await testUtils.advanceTimersByTime(1);
336
+ expect(timeState).toEqual({ receive1: true, timedOut: false, succeeded: false });
337
+ await testUtils.advanceTimersByTime(1);
338
+ expect(timeState).toEqual({ receive1: true, timedOut: true, succeeded: false });
339
+ });
340
+
341
+ test('cannot send to unopened SiDevice', async () => {
342
+ const siDevice = new SiDevice('cannotSendToUnopened', {
343
+ driver: mockDriver({})
344
+ });
345
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
346
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
347
+
348
+ const randomMessage = testUtils.getRandomMessage({});
349
+ const timeState = { timedOut: false };
350
+ muxer.sendMessageToLatestTarget(randomMessage, 1, 1).catch(() => {
351
+ expect(muxer._test.sendQueue.length).toBe(0);
352
+ timeState.timedOut = true;
353
+ });
354
+ await testUtils.advanceTimersByTime(0);
355
+ expect(timeState).toEqual({ timedOut: false });
356
+ await testUtils.advanceTimersByTime(1);
357
+ expect(timeState).toEqual({ timedOut: true });
358
+ });
359
+
360
+ test('handles sending as soon as device is openend', async () => {
361
+ const siDevice = new SiDevice('handlesSendingAsSoonAsOpened', {
362
+ driver: mockDriver({
363
+ send: () => Promise.resolve()
364
+ })
365
+ });
366
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
367
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
368
+
369
+ const randomMessage = testUtils.getRandomMessage({});
370
+ const timeState = { deviceOpened: false, sendingFinished: false };
371
+ muxer.sendMessageToLatestTarget(randomMessage, 0, 3).then(() => {
372
+ expect(muxer._test.sendQueue.length).toBe(0);
373
+ timeState.sendingFinished = true;
374
+ });
375
+ setTimeout(() => {
376
+ siDevice.setState(SiDeviceState.Opened);
377
+ timeState.deviceOpened = true;
378
+ }, 1);
379
+ await testUtils.advanceTimersByTime(0);
380
+ expect(timeState).toEqual({ deviceOpened: false, sendingFinished: false });
381
+ await testUtils.advanceTimersByTime(1);
382
+ expect(timeState).toEqual({ deviceOpened: true, sendingFinished: false });
383
+ await testUtils.advanceTimersByTime(1);
384
+ expect(timeState).toEqual({ deviceOpened: true, sendingFinished: true });
385
+ });
386
+
387
+ test('sends all as soon as device is openend', async () => {
388
+ const siDevice = new SiDevice('sendsAllAsSoonAsOpened', {
389
+ driver: mockDriver({
390
+ send: () => Promise.resolve()
391
+ })
392
+ });
393
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
394
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
395
+
396
+ const randomMessage = testUtils.getRandomMessage({});
397
+ const timeState = { deviceOpened: false, numSuccess: 0, allSendingFinished: false };
398
+ const getMuxerPromise = () =>
399
+ muxer.sendMessageToLatestTarget(randomMessage, 0, 4).then(() => {
400
+ timeState.numSuccess = (timeState.numSuccess || 0) + 1;
401
+ });
402
+ Promise.all([getMuxerPromise(), getMuxerPromise()]).then(() => {
403
+ expect(muxer._test.sendQueue.length).toBe(0);
404
+ timeState.allSendingFinished = true;
405
+ });
406
+ setTimeout(() => {
407
+ siDevice.setState(SiDeviceState.Opened);
408
+ timeState.deviceOpened = true;
409
+ }, 1);
410
+ await testUtils.advanceTimersByTime(0);
411
+ expect(timeState).toEqual({ deviceOpened: false, numSuccess: 0, allSendingFinished: false });
412
+ await testUtils.advanceTimersByTime(1);
413
+ expect(timeState).toEqual({ deviceOpened: true, numSuccess: 0, allSendingFinished: false });
414
+ await testUtils.advanceTimersByTime(1);
415
+ expect(timeState).toEqual({ deviceOpened: true, numSuccess: 1, allSendingFinished: false });
416
+ await testUtils.advanceTimersByTime(1);
417
+ expect(timeState).toEqual({ deviceOpened: true, numSuccess: 2, allSendingFinished: false });
418
+ await testUtils.advanceTimersByTime(0); // for Promise.all
419
+ expect(timeState).toEqual({ deviceOpened: true, numSuccess: 2, allSendingFinished: true });
420
+ });
421
+
422
+ test('aborts sending as soon as device is closed', async () => {
423
+ const siDevice = new SiDevice('abortsAllAsSoonAsClosed', {
424
+ driver: mockDriver({
425
+ send: () => Promise.resolve()
426
+ })
427
+ });
428
+ siDevice.setState(SiDeviceState.Opened);
429
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
430
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
431
+
432
+ const randomMessage = testUtils.getRandomMessage({});
433
+ const timeState = {
434
+ numSuccess: 0,
435
+ numAbort: 0,
436
+ deviceClosed: false,
437
+ allSendingFinished: false
438
+ };
439
+ const getMuxerPromise = () =>
440
+ muxer
441
+ .sendMessageToLatestTarget(randomMessage, 0, 4)
442
+ .then(
443
+ () => {
444
+ timeState.numSuccess = (timeState.numSuccess || 0) + 1;
445
+ },
446
+ () => {}
447
+ )
448
+ .then(
449
+ () => {
450
+ timeState.numAbort = (timeState.numAbort || 0) + 1;
451
+ },
452
+ () => {}
453
+ );
454
+ Promise.all([getMuxerPromise(), getMuxerPromise(), getMuxerPromise()]).then(
455
+ () => {
456
+ expect(muxer._test.sendQueue.length).toBe(0);
457
+ timeState.allSendingFinished = true;
458
+ },
459
+ () => {}
460
+ );
461
+ setTimeout(() => {
462
+ siDevice.setState(SiDeviceState.Closing);
463
+ timeState.deviceClosed = true;
464
+ }, 1);
465
+ await testUtils.advanceTimersByTime(0);
466
+ expect(timeState).toEqual({
467
+ numSuccess: 1,
468
+ numAbort: 0,
469
+ deviceClosed: false,
470
+ allSendingFinished: false
471
+ });
472
+ await testUtils.advanceTimersByTime(1);
473
+ expect(timeState).toEqual({
474
+ numSuccess: 1,
475
+ numAbort: 2,
476
+ deviceClosed: true,
477
+ allSendingFinished: false
478
+ });
479
+ await testUtils.advanceTimersByTime(0); // for Promise.all (not called)
480
+ expect(timeState).toEqual({
481
+ numSuccess: 1,
482
+ numAbort: 2,
483
+ deviceClosed: true,
484
+ allSendingFinished: false
485
+ });
486
+ });
487
+
488
+ test('handles device failing to send', async () => {
489
+ const siDevice = new SiDevice('handlesDeviceFailingToSend', {
490
+ driver: mockDriver({
491
+ send: () => Promise.reject(new Error('test'))
492
+ })
493
+ });
494
+ siDevice.setState(SiDeviceState.Opened);
495
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
496
+ expect(muxer instanceof SiTargetMultiplexer).toBe(true);
497
+
498
+ const randomMessage = testUtils.getRandomMessage({});
499
+ const timeState = { timedOut: false };
500
+ muxer.sendMessageToLatestTarget(randomMessage, 1, 1).catch(() => {
501
+ expect(muxer._test.sendQueue.length).toBe(0);
502
+ timeState.timedOut = true;
503
+ });
504
+ await testUtils.advanceTimersByTime(0);
505
+ expect(timeState).toEqual({ timedOut: false });
506
+ await testUtils.advanceTimersByTime(1);
507
+ expect(timeState).toEqual({ timedOut: true });
508
+ });
509
+
510
+ test('cannot send to unknown target', async () => {
511
+ const siDevice = new SiDevice('undefinedTarget', { driver: mockDriver({}) });
512
+ siDevice.setState(SiDeviceState.Opened);
513
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
514
+ muxer.latestTarget = SiTargetMultiplexerTarget.Direct;
515
+ const randomMessage = testUtils.getRandomMessage({});
516
+ const timeState = { setToUnknownFailed: false };
517
+ muxer.sendMessage(SiTargetMultiplexerTarget.Unknown, randomMessage, 1, 1).catch(() => {
518
+ expect(muxer._test.sendQueue.length).toBe(0);
519
+ timeState.setToUnknownFailed = true;
520
+ });
521
+ await testUtils.advanceTimersByTime(0);
522
+ expect(timeState).toEqual({ setToUnknownFailed: true });
523
+ });
524
+ test('cannot send to switching target', async () => {
525
+ const siDevice = new SiDevice('switchingTarget', { driver: mockDriver({}) });
526
+ siDevice.setState(SiDeviceState.Opened);
527
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
528
+ muxer.latestTarget = SiTargetMultiplexerTarget.Direct;
529
+ const randomMessage = testUtils.getRandomMessage({});
530
+ const timeState = { setToSwitchingFailed: false };
531
+ muxer.sendMessage(SiTargetMultiplexerTarget.Switching, randomMessage, 1, 1).catch(() => {
532
+ expect(muxer._test.sendQueue.length).toBe(0);
533
+ timeState.setToSwitchingFailed = true;
534
+ });
535
+ await testUtils.advanceTimersByTime(0);
536
+ expect(timeState).toEqual({ setToSwitchingFailed: true });
537
+ });
538
+ test('handles error switching target', async () => {
539
+ const siDevice = new SiDevice('errorSwitchingTarget', {
540
+ driver: mockDriver({
541
+ send: () => Promise.reject(new Error('test'))
542
+ })
543
+ });
544
+ siDevice.setState(SiDeviceState.Opened);
545
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
546
+ muxer.latestTarget = SiTargetMultiplexerTarget.Direct;
547
+ const randomMessage = testUtils.getRandomMessage({});
548
+ const timeState = { setTargetFailed: false };
549
+ muxer.sendMessage(SiTargetMultiplexerTarget.Remote, randomMessage, 1, 1).catch(() => {
550
+ timeState.setTargetFailed = true;
551
+ });
552
+ await testUtils.nTimesAsync(2, () => testUtils.advanceTimersByTime(0));
553
+ expect(muxer.target).toEqual(SiTargetMultiplexerTarget.Unknown);
554
+ expect(timeState).toEqual({ setTargetFailed: true });
555
+ });
556
+ test('handles unclear target switch response', async () => {
557
+ const siDevice = new SiDevice('errorSwitchingTarget', {
558
+ driver: mockDriver({
559
+ send: () => {
560
+ setTimeout(() => {
561
+ siDevice.dispatchEvent(
562
+ 'receive',
563
+ new SiDeviceReceiveEvent(
564
+ siDevice,
565
+ siProtocol.render({
566
+ command: proto.cmd.SET_MS,
567
+ parameters: [SiTargetMultiplexerTarget.Direct]
568
+ })
569
+ )
570
+ );
571
+ }, 0);
572
+ return Promise.resolve();
573
+ }
574
+ })
575
+ });
576
+ siDevice.setState(SiDeviceState.Opened);
577
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
578
+ muxer.latestTarget = SiTargetMultiplexerTarget.Direct;
579
+ const randomMessage = testUtils.getRandomMessage({});
580
+ const timeState = { setTargetFailed: false };
581
+ muxer.sendMessage(SiTargetMultiplexerTarget.Remote, randomMessage, 1, 1).catch(() => {
582
+ timeState.setTargetFailed = true;
583
+ });
584
+ await testUtils.nTimesAsync(2, () => testUtils.advanceTimersByTime(0));
585
+ expect(muxer.target).toEqual(SiTargetMultiplexerTarget.Unknown);
586
+ expect(timeState).toEqual({ setTargetFailed: true });
587
+ });
588
+ test('handles direct device-initiated command', async () => {
589
+ const siDevice = new SiDevice('errorSwitchingTarget', {
590
+ driver: mockDriver({
591
+ send: () => Promise.reject(new Error('test'))
592
+ })
593
+ });
594
+ siDevice.setState(SiDeviceState.Opened);
595
+ const muxer = SiTargetMultiplexer.fromSiDevice(siDevice);
596
+ const deviceInitiatedMessage = siProtocol.render({
597
+ command: proto.cmd.SI5_DET,
598
+ parameters: [0x00, 0x0a, 0x00, 0x04, 0x19, 0x02]
599
+ });
600
+ siDevice.dispatchEvent('receive', new SiDeviceReceiveEvent(siDevice, deviceInitiatedMessage));
601
+ await testUtils.nTimesAsync(10, () => testUtils.advanceTimersByTime(1));
602
+ expect(muxer.target).toEqual(SiTargetMultiplexerTarget.Direct);
603
+ expect(muxer.latestTarget).toEqual(SiTargetMultiplexerTarget.Direct);
604
+ });
605
+ });