1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (c) 2026-present FERS Contributors (see AUTHORS.md).
4import { describe, expect, test } from 'bun:test';
6 normalizeSimulationOutputMetadata,
7 type RawSimulationOutputMetadata,
8 type SimulationOutputMetadata,
9} from './simulationProgressStore';
13 simulation_name: 'Metadata Fixture',
14 output_directory: '/tmp/fers',
19} satisfies Omit<SimulationOutputMetadata, 'files'>;
21describe('simulation output metadata', () => {
22 test('keeps FMCW metadata and streaming segments', () => {
23 const metadata: SimulationOutputMetadata = {
28 receiver_name: 'FMCW Rx',
30 path: '/tmp/fers/fmcw.h5',
34 sample_end_exclusive: 128,
36 min_pulse_length_samples: 0,
37 max_pulse_length_samples: 0,
38 uniform_pulse_length: true,
46 sample_end_exclusive: 128,
47 first_chirp_start_time: 0,
48 emitted_chirp_count: 4,
52 chirp_bandwidth: 20e6,
53 chirp_duration: 250e-6,
56 chirp_rate_signed: -80e9,
57 chirp_direction: 'down',
58 start_frequency_offset: 0,
64 transmitter_name: 'FMCW Tx',
66 waveform_name: 'FMCW Wave',
67 carrier_frequency: 10e9,
68 chirp_bandwidth: 20e6,
69 chirp_duration: 250e-6,
72 chirp_rate_signed: -80e9,
73 chirp_direction: 'down',
74 start_frequency_offset: 0,
80 first_chirp_start_time: 0,
81 emitted_chirp_count: 4,
91 normalizeSimulationOutputMetadata(metadata).files[0]
96 first_chirp_start_time: 0,
97 emitted_chirp_count: 4,
101 chirp_bandwidth: 20e6,
102 chirp_duration: 250e-6,
103 chirp_period: 500e-6,
104 chirp_direction: 'down',
112 first_chirp_start_time: 0,
113 emitted_chirp_count: 4,
121 test('adapts legacy cw_segments metadata to streaming_segments', () => {
122 const legacyMetadata = {
127 receiver_name: 'CW Rx',
129 path: '/tmp/fers/cw.h5',
133 sample_end_exclusive: 64,
135 min_pulse_length_samples: 0,
136 max_pulse_length_samples: 0,
137 uniform_pulse_length: true,
145 sample_end_exclusive: 64,
150 } satisfies RawSimulationOutputMetadata;
152 const normalizedFile =
153 normalizeSimulationOutputMetadata(legacyMetadata).files[0];
155 expect(normalizedFile.streaming_segments).toHaveLength(1);
156 expect(normalizedFile.fmcw_sources).toEqual([]);
157 expect('cw_segments' in normalizedFile).toBe(false);
160 test('normalizes mixed sampling-rate metadata', () => {
164 sampling_rates: [1e6, 2e6],
168 receiver_name: 'Rx 1',
170 path: '/tmp/fers/rx1.h5',
174 sample_end_exclusive: 64,
176 min_pulse_length_samples: 0,
177 max_pulse_length_samples: 0,
178 uniform_pulse_length: true,
180 streaming_segments: [],
184 receiver_name: 'Rx 2',
186 path: '/tmp/fers/rx2.h5',
190 sample_end_exclusive: 128,
192 min_pulse_length_samples: 0,
193 max_pulse_length_samples: 0,
194 uniform_pulse_length: true,
196 streaming_segments: [],
197 fmcw_dechirp_mode: 'none',
198 fmcw_dechirp_reference_source: 'none',
201 } satisfies RawSimulationOutputMetadata;
203 const normalized = normalizeSimulationOutputMetadata(metadata);
205 expect(normalized.sampling_rate).toBeNull();
206 expect(normalized.sampling_rates).toEqual([1e6, 2e6]);
207 expect(normalized.files.map((file) => file.sampling_rate)).toEqual([
212 test('preserves VITA49 metadata section', () => {
217 endpoint: '127.0.0.1:4991',
218 endpoint_host: '127.0.0.1',
220 epoch_unix_nanoseconds: '1700000000123456789',
221 class_id: '0xFA52530001000101',
223 max_udp_payload: 1400,
231 reference_frequency: 9.6e9,
233 samples_emitted: 512,
237 late_packet_count: 0,
238 context_packet_count: 2,
239 first_sample_time: 0,
242 integer_seconds: 1700000000,
243 fractional_picoseconds: 123456789000,
246 integer_seconds: 1700000010,
247 fractional_picoseconds: 123456789000,
252 } satisfies RawSimulationOutputMetadata;
254 expect(normalizeSimulationOutputMetadata(metadata).vita49).toEqual(