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 cloneTemplateIntoScenarioData,
7 createAssetLibraryFile,
8 createTemplateFromScenarioItem,
10 prepareTemplatesForCatalog,
11} from './assetTemplates';
12import { defaultGlobalParameters } from './scenarioStore/defaults';
13import type { ScenarioData } from './scenarioStore/types';
15function createScenarioFixture(): ScenarioData {
18 ...defaultGlobalParameters,
19 simulation_name: 'Library Fixture',
26 waveformType: 'pulsed_from_file',
28 carrier_frequency: 1e9,
29 filename: '/tmp/pulse.h5',
39 randomFreqOffsetStdev: null,
41 randomPhaseOffsetStdev: null,
42 noiseEntries: [{ id: '7002', alpha: 0.2, weight: 0.5 }],
53 design_frequency: 1e9,
65 interpolation: 'static',
78 interpolation: 'static',
111 rotationPathPoints: [{ azimuth: 0, elevation: 0 }],
117describe('asset templates', () => {
118 test('creates top-level asset snapshots', () => {
119 const scenario = createScenarioFixture();
120 const template = createTemplateFromScenarioItem(scenario, '5001', {
122 timestamp: '2026-04-13T00:00:00.000Z',
125 expect(template).toMatchObject({
136 test('captures platform dependencies and strips runtime path caches', () => {
137 const scenario = createScenarioFixture();
138 const template = createTemplateFromScenarioItem(scenario, '1001', {
140 timestamp: '2026-04-13T00:00:00.000Z',
143 expect(template?.kind).toBe('platform');
144 if (template?.kind !== 'platform') {
145 throw new Error('Expected platform template.');
148 expect(template.dependencies.antennas).toHaveLength(1);
149 expect(template.dependencies.waveforms).toHaveLength(1);
150 expect(template.dependencies.timings).toHaveLength(1);
151 expect(template.payload).not.toHaveProperty('pathPoints');
152 expect(template.payload).not.toHaveProperty('rotationPathPoints');
155 test('loads platform templates with fresh IDs and remapped dependencies', () => {
156 const scenario = createScenarioFixture();
157 const template = createTemplateFromScenarioItem(scenario, '1001');
158 if (template?.kind !== 'platform') {
159 throw new Error('Expected platform template.');
162 const { scenarioData, result } = cloneTemplateIntoScenarioData(
166 const insertedPlatform = scenarioData.platforms.at(-1);
167 const insertedComponent = insertedPlatform?.components[0];
169 expect(result.warnings).toEqual([]);
170 expect(insertedPlatform?.id).not.toBe('1001');
171 expect(insertedPlatform?.name).toBe('Aircraft A Copy');
172 expect(insertedComponent?.id).not.toBe('2001');
173 expect(insertedComponent?.type).toBe('transmitter');
174 if (insertedComponent?.type !== 'transmitter') {
175 throw new Error('Expected transmitter component.');
177 expect(insertedComponent.antennaId).not.toBe('5001');
178 expect(insertedComponent.waveformId).not.toBe('6001');
179 expect(insertedComponent.timingId).not.toBe('7001');
181 scenarioData.antennas.some(
182 (antenna) => antenna.id === insertedComponent.antennaId
186 scenarioData.waveforms.some(
187 (waveform) => waveform.id === insertedComponent.waveformId
191 scenarioData.timings.some(
192 (timing) => timing.id === insertedComponent.timingId
197 test('uses template display names when loading renamed assets', () => {
198 const scenario = createScenarioFixture();
199 const template = createTemplateFromScenarioItem(scenario, '6001');
200 if (template?.kind !== 'waveform') {
201 throw new Error('Expected waveform template.');
204 const { scenarioData, result } = cloneTemplateIntoScenarioData(
208 name: 'Reusable Pulse',
212 expect(result.insertedName).toBe('Reusable Pulse Copy');
213 expect(scenarioData.waveforms.at(-1)?.name).toBe('Reusable Pulse Copy');
216 test('clears missing platform dependency references with warnings', () => {
217 const scenario = createScenarioFixture();
218 const template = createTemplateFromScenarioItem(scenario, '1001');
219 if (template?.kind !== 'platform') {
220 throw new Error('Expected platform template.');
222 const templateWithoutDependencies = {
231 const { scenarioData, result } = cloneTemplateIntoScenarioData(
233 templateWithoutDependencies
235 const insertedComponent = scenarioData.platforms.at(-1)?.components[0];
237 expect(result.warnings).toHaveLength(3);
238 expect(insertedComponent?.type).toBe('transmitter');
239 if (insertedComponent?.type !== 'transmitter') {
240 throw new Error('Expected transmitter component.');
242 expect(insertedComponent.antennaId).toBeNull();
243 expect(insertedComponent.waveformId).toBeNull();
244 expect(insertedComponent.timingId).toBeNull();
247 test('parses catalog files and assigns imported templates new catalog IDs', () => {
248 const scenario = createScenarioFixture();
249 const template = createTemplateFromScenarioItem(scenario, '6001', {
250 id: 'template-original',
253 throw new Error('Expected waveform template.');
256 const parsed = parseAssetTemplates(createAssetLibraryFile([template]));
257 const prepared = prepareTemplatesForCatalog(parsed);
259 expect(parsed).toHaveLength(1);
260 expect(prepared).toHaveLength(1);
261 expect(prepared[0].id).not.toBe('template-original');
262 expect(prepared[0].payload.id).toBe('6001');