FERS 0.1.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
simulationProgress.test.ts
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (c) 2026-present FERS Contributors (see AUTHORS.md).
3
4import { describe, expect, test } from 'bun:test';
5import type { SimulationProgressState } from '@/stores/simulationProgressStore';
6import {
7 addSimulationProgressEvent,
8 getSimulationProgressPercent,
9 normalizeCompletedProgressSnapshot,
10} from './simulationProgress';
11
12const trackProgress = (events: SimulationProgressState[]) => {
13 const tracked: Record<string, SimulationProgressState> = {};
14
15 for (const event of events) {
16 Object.assign(tracked, addSimulationProgressEvent(tracked, event));
17 }
18
19 return tracked;
20};
21
22describe('simulation progress normalization', () => {
23 test('keeps CW receiver phases on one stable row', () => {
24 const tracked = trackProgress([
25 {
26 message: 'Finalizing CW Receiver CWRadar',
27 current: 0,
28 total: 100,
29 },
30 {
31 message: 'Rendering Interference for CWRadar',
32 current: 25,
33 total: 100,
34 },
35 {
36 message: 'Applying Noise for CWRadar',
37 current: 50,
38 total: 100,
39 },
40 {
41 message: 'Writing HDF5 for CWRadar',
42 current: 75,
43 total: 100,
44 },
45 {
46 message: 'Finalized CWRadar',
47 current: 100,
48 total: 100,
49 },
50 ]);
51
52 expect(Object.keys(tracked)).toEqual(['receiver:CWRadar']);
53 expect(tracked['receiver:CWRadar']).toEqual({
54 message: 'Finalized CWRadar',
55 current: 100,
56 total: 100,
57 details: [
58 {
59 id: 'streaming-finalizing',
60 message: 'Finalizing CW Receiver CWRadar',
61 current: 0,
62 total: 100,
63 },
64 {
65 id: 'streaming-rendering-interference',
66 message: 'Rendering Interference for CWRadar',
67 current: 25,
68 total: 100,
69 },
70 {
71 id: 'streaming-applying-noise',
72 message: 'Applying Noise for CWRadar',
73 current: 50,
74 total: 100,
75 },
76 {
77 id: 'streaming-writing-hdf5',
78 message: 'Writing HDF5 for CWRadar',
79 current: 75,
80 total: 100,
81 },
82 {
83 id: 'streaming-finalized',
84 message: 'Finalized CWRadar',
85 current: 100,
86 total: 100,
87 },
88 ],
89 });
90 });
91
92 test('keeps FMCW receiver phases on one stable row', () => {
93 const tracked = trackProgress([
94 {
95 message: 'Finalizing FMCW Receiver TrackerDriftFMCW',
96 current: 0,
97 total: 100,
98 },
99 {
100 message: 'Rendering Interference for TrackerDriftFMCW',
101 current: 25,
102 total: 100,
103 },
104 {
105 message: 'Applying Noise for TrackerDriftFMCW',
106 current: 50,
107 total: 100,
108 },
109 {
110 message: 'Writing HDF5 for TrackerDriftFMCW',
111 current: 75,
112 total: 100,
113 },
114 {
115 message: 'Finalized TrackerDriftFMCW',
116 current: 100,
117 total: 100,
118 },
119 ]);
120
121 expect(Object.keys(tracked)).toEqual(['receiver:TrackerDriftFMCW']);
122 expect(tracked['receiver:TrackerDriftFMCW']).toMatchObject({
123 message: 'Finalized TrackerDriftFMCW',
124 current: 100,
125 total: 100,
126 details: [
127 {
128 id: 'streaming-finalizing',
129 message: 'Finalizing FMCW Receiver TrackerDriftFMCW',
130 },
131 {
132 id: 'streaming-rendering-interference',
133 message: 'Rendering Interference for TrackerDriftFMCW',
134 },
135 {
136 id: 'streaming-applying-noise',
137 message: 'Applying Noise for TrackerDriftFMCW',
138 },
139 {
140 id: 'streaming-writing-hdf5',
141 message: 'Writing HDF5 for TrackerDriftFMCW',
142 },
143 {
144 id: 'streaming-finalized',
145 message: 'Finalized TrackerDriftFMCW',
146 },
147 ],
148 });
149 });
150
151 test('keeps pulsed export chunks and completion on one stable row', () => {
152 const tracked = trackProgress([
153 {
154 message: 'Exporting PulsedRadar: Chunk 9928',
155 current: 9928,
156 total: 0,
157 },
158 {
159 message: 'Finished Exporting PulsedRadar',
160 current: 100,
161 total: 100,
162 },
163 ]);
164
165 expect(Object.keys(tracked)).toEqual(['receiver:PulsedRadar']);
166 expect(tracked['receiver:PulsedRadar']).toEqual({
167 message: 'Finished Exporting PulsedRadar',
168 current: 100,
169 total: 100,
170 details: [
171 {
172 id: 'export-chunk',
173 message: 'Exporting PulsedRadar: Chunk 9928',
174 current: 9928,
175 total: 0,
176 },
177 {
178 id: 'export-finished',
179 message: 'Finished Exporting PulsedRadar',
180 current: 100,
181 total: 100,
182 },
183 ],
184 });
185 });
186
187 test('keeps only the latest chunk detail for high-volume export updates', () => {
188 const tracked = trackProgress([
189 {
190 message: 'Exporting PulsedRadar: Chunk 10',
191 current: 10,
192 total: 0,
193 },
194 {
195 message: 'Exporting PulsedRadar: Chunk 9928',
196 current: 9928,
197 total: 0,
198 },
199 ]);
200
201 expect(tracked['receiver:PulsedRadar'].details).toEqual([
202 {
203 id: 'export-chunk',
204 message: 'Exporting PulsedRadar: Chunk 9928',
205 current: 9928,
206 total: 0,
207 },
208 ]);
209 });
210
211 test('keeps main simulation messages out of the detail list', () => {
212 const tracked = trackProgress([
213 {
214 message: 'Simulating... 1.00s / 10.00s',
215 current: 10,
216 total: 100,
217 },
218 {
219 message: 'Main simulation finished. Waiting for data export...',
220 current: 100,
221 total: 100,
222 },
223 {
224 message: 'Simulation complete',
225 current: 100,
226 total: 100,
227 },
228 ]);
229
230 expect(Object.keys(tracked)).toEqual(['main']);
231 expect(tracked.main).toEqual({
232 message: 'Simulation complete',
233 current: 100,
234 total: 100,
235 });
236 });
237
238 test('marks known stale receiver and export rows complete after success', () => {
239 const completed = normalizeCompletedProgressSnapshot({
240 CW: {
241 message: 'Finalizing CW Receiver CWRadar',
242 current: 0,
243 total: 100,
244 },
245 HDF5: {
246 message: 'Writing HDF5 for CWRadar',
247 current: 75,
248 total: 100,
249 },
250 PulsedRadar: {
251 message: 'Exporting PulsedRadar: Chunk 9928',
252 current: 9928,
253 total: 0,
254 },
255 main: {
256 message: 'Main simulation finished. Waiting for data export...',
257 current: 100,
258 total: 100,
259 },
260 });
261
262 expect(completed).toEqual({
263 'receiver:CWRadar': {
264 message: 'Finalized CWRadar',
265 current: 100,
266 total: 100,
267 details: [
268 {
269 id: 'streaming-finalizing',
270 message: 'Finalizing CW Receiver CWRadar',
271 current: 0,
272 total: 100,
273 },
274 {
275 id: 'streaming-writing-hdf5',
276 message: 'Writing HDF5 for CWRadar',
277 current: 75,
278 total: 100,
279 },
280 {
281 id: 'streaming-finalized',
282 message: 'Finalized CWRadar',
283 current: 100,
284 total: 100,
285 },
286 ],
287 },
288 'receiver:PulsedRadar': {
289 message: 'Finished Exporting PulsedRadar',
290 current: 100,
291 total: 100,
292 details: [
293 {
294 id: 'export-chunk',
295 message: 'Exporting PulsedRadar: Chunk 9928',
296 current: 9928,
297 total: 0,
298 },
299 {
300 id: 'export-finished',
301 message: 'Finished Exporting PulsedRadar',
302 current: 100,
303 total: 100,
304 },
305 ],
306 },
307 main: {
308 message: 'Simulation complete',
309 current: 100,
310 total: 100,
311 },
312 });
313 });
314
315 test('clamps determinate progress percentages', () => {
316 expect(
317 getSimulationProgressPercent({
318 message: 'below',
319 current: -10,
320 total: 100,
321 })
322 ).toBe(0);
323 expect(
324 getSimulationProgressPercent({
325 message: 'above',
326 current: 125,
327 total: 100,
328 })
329 ).toBe(100);
330 expect(
331 getSimulationProgressPercent({
332 message: 'chunk',
333 current: 9928,
334 total: 0,
335 })
336 ).toBeNull();
337 });
338});