Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions lib/plugins/Label_20_POS.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { MessageDecoder } from '../MessageDecoder';
import { Label_20_POS } from './Label_20_POS';

describe('Label_20_POS', () => {
const decoder = new MessageDecoder();
const plugin = new Label_20_POS(decoder);

const decode = (text: string) => {
return plugin.decode({ text });
};

it('decodes POS variation with 11 fields (coordinates only required)', () => {
const text = 'POSN38160W077075,,211733,360,OTT,212041,,N42,19689,40,544';
const res = decode(text);

expect(res.decoded).toBe(true);
expect(res.decoder.name).toBe('label-20-pos');
expect(res.decoder.decodeLevel).toBe('full');
expect(res.formatted.description).toBe('Position Report');

expect(res.raw.preamble).toBe('POS');
expect(res.raw.position).toBeDefined();
expect(res.raw.position.latitude).toBeCloseTo(38.160, 3);
expect(res.raw.position.longitude).toBeCloseTo(-77.075, 3);

const posItem = res.formatted.items.find(i => i.code === 'POS');
expect(posItem).toBeDefined();
expect(posItem.value).toContain('38.160');
expect(posItem.value).toContain('77.075');
});

it('decodes POS variation with 5 fields (coordinates only)', () => {
const text = 'POSN38160W077075,,211733,360,OTT';
const res = decode(text);

expect(res.decoded).toBe(true);
expect(res.decoder.name).toBe('label-20-pos');
expect(res.decoder.decodeLevel).toBe('full');
expect(res.formatted.description).toBe('Position Report');

expect(res.raw.preamble).toBe('POS');
expect(res.raw.position).toBeDefined();
expect(res.raw.position.latitude).toBeCloseTo(38.160, 3);
expect(res.raw.position.longitude).toBeCloseTo(-77.075, 3);

const posItem = res.formatted.items.find(i => i.code === 'POS');
expect(posItem).toBeDefined();
expect(posItem.value).toContain('38.160');
expect(posItem.value).toContain('77.075');
});

it('marks unknown variation as not decoded', () => {
const text = 'POSUNKNOWN';
const res = decode(text);

expect(res.decoded).toBe(false);
expect(res.decoder.decodeLevel).toBe('none');
expect(res.formatted.description).toBe('Position Report');
});
});
71 changes: 71 additions & 0 deletions lib/plugins/Label_SQ.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { MessageDecoder } from '../MessageDecoder';
import { Label_SQ } from './Label_SQ';

describe('Label_SQ', () => {
const decoder = new MessageDecoder();
const plugin = new Label_SQ(decoder);

const decode = (text: string) => {
return plugin.decode({ text });
};

it('decodes version 2 ARINC ground station squitter with coordinates and frequency', () => {
const text = 'V2AA' + '0' + '1X' + 'A' + 'JFK' + 'KJFK' + '3' + '4075' + 'N' + '7398' + 'W' + 'V136975' + '/extra';
const res = decode(text);

expect(res.decoded).toBe(true);
expect(res.decoder.name).toBe('label-sq');
expect(res.decoder.decodeLevel).toBe('full');

expect(res.raw.preamble).toBe(text.substring(0, 4));
expect(res.raw.version).toBe('2');
expect(res.raw.network).toBe('A');

expect(res.raw.groundStation).toBeDefined();
expect(res.raw.groundStation.number).toBe('3');
expect(res.raw.groundStation.iataCode).toBe('JFK');
expect(res.raw.groundStation.icaoCode).toBe('KJFK');

expect(res.raw.groundStation.coordinates.latitude).toBeCloseTo(40.75, 5);
expect(res.raw.groundStation.coordinates.longitude).toBeCloseTo(-73.98, 5);

expect(res.raw.vdlFrequency).toBeCloseTo(136.975, 6);

const items = res.formatted.items;
expect(items.find(i => i.code === 'NETT')?.value).toBe('ARINC');
expect(items.find(i => i.code === 'VER')?.value).toBe('2');
expect(items.find(i => i.code === 'GNDSTN')?.value).toBe('KJFK3');
expect(items.find(i => i.code === 'IATA')?.value).toBe('JFK');
expect(items.find(i => i.code === 'ICAO')?.value).toBe('KJFK');
expect(items.find(i => i.code === 'VDLFRQ')?.value).toContain('136.975');
});

it('maps SITA network and handles absence of regex match gracefully', () => {
const text = 'V2AS' + '0' + 'XXXXNOTMATCHING';
const res = decode(text);

expect(res.decoded).toBe(true);
expect(res.raw.version).toBe('2');
expect(res.raw.network).toBe('S');

const items = res.formatted.items;
expect(items.find(i => i.code === 'NETT')?.value).toBe('SITA');
expect(items.find(i => i.code === 'VER')?.value).toBe('2');

expect(res.raw.groundStation).toBeUndefined();
expect(res.raw.vdlFrequency).toBeUndefined();
});

it('handles non-version-2 payloads (no regex path)', () => {
const text = 'V1AA' + 'WHATEVER';
const res = decode(text);

expect(res.decoded).toBe(true);
expect(res.raw.version).toBe('1');
expect(res.raw.network).toBe('A');

const items = res.formatted.items;
expect(items.find(i => i.code === 'NETT')?.value).toBe('ARINC');
expect(items.find(i => i.code === 'VER')?.value).toBe('1');
});
});