Skip to content
Open
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
13 changes: 13 additions & 0 deletions lib/DateTimeUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,16 @@ describe('DateTimeUtils.UTCDateTimeToString', () => {
expect(out).toContain('12:30:45');
});
});

describe('DateTimeUtils.timestampToString', () => {
it('returns an empty string for NaN instead of throwing RangeError', () => {
// new Date(NaN).toISOString() throws "Invalid time value". A malformed
// time field (e.g. convertHHMMSSToTod("ABCD")) must not abort the decode.
expect(() => DateTimeUtils.timestampToString(NaN)).not.toThrow();
expect(DateTimeUtils.timestampToString(NaN)).toBe('');
});

it('still formats a valid time-of-day', () => {
expect(DateTimeUtils.timestampToString(4980)).toBe('01:23:00');
});
});
3 changes: 3 additions & 0 deletions lib/DateTimeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ export class DateTimeUtils {
* @returns
*/
public static timestampToString(time: number): string {
if (isNaN(time)) {
return '';
}
const date = new Date(time * 1000);

if (time < 86400) {
Expand Down
25 changes: 25 additions & 0 deletions lib/plugins/Label_44_ETA.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,31 @@ describe('Label 44 Preamble ETA', () => {
expect(decodeResult.formatted.items[8].value).toBe('8.1');
});

test('skips a malformed timestamp field instead of throwing (issue #498)', () => {
// convertHHMMSSToTod('ABCD') yields NaN; before the fix this aborted
// the decode with "RangeError: Invalid time value".
message.text = '00ETA03,N38241W081357,330,KBNA,KBWI,1107,ABCD,0208,008.1';
let decodeResult;
expect(() => {
decodeResult = plugin.decode(message);
}).not.toThrow();
expect(decodeResult.decoded).toBe(true);
expect(decodeResult.decoder.decodeLevel).toBe('full');
expect(decodeResult.raw.message_timestamp).toBeUndefined();
expect(decodeResult.raw.eta_time).toBe(7680);
expect(decodeResult.raw.departure_icao).toBe('KBNA');
expect(decodeResult.raw.arrival_icao).toBe('KBWI');
// 9 items minus the skipped Message Timestamp
expect(decodeResult.formatted.items.length).toBe(8);
expect(decodeResult.formatted.items[6].label).toBe(
'Estimated Time of Arrival',
);
expect(decodeResult.formatted.items[6].value).toBe('02:08:00');
expect(
decodeResult.formatted.items.some((i) => i.code === 'TIMESTAMP'),
).toBe(false);
});

test('does not decode invalid', () => {
message.text = '00OFF01 Bogus message';
const decodeResult = plugin.decode(message);
Expand Down
32 changes: 32 additions & 0 deletions lib/utils/result_formatter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,35 @@ describe('ResultFormatter.checksum', () => {
expect(item.value).toBe('0x0abc');
});
});

describe('ResultFormatter timestamp family NaN guards', () => {
// Malformed time fields (e.g. convertHHMMSSToTod('ABCD') -> NaN) must not
// abort the whole decode via timestampToString's RangeError (issue #498).
const cases: Array<[string, (dr: DecodeResult) => void, string]> = [
['timestamp', (dr) => ResultFormatter.timestamp(dr, NaN), 'message_timestamp'],
['eta', (dr) => ResultFormatter.eta(dr, NaN), 'eta_time'],
['out', (dr) => ResultFormatter.out(dr, NaN), 'out_time'],
['off', (dr) => ResultFormatter.off(dr, NaN), 'off_time'],
['on', (dr) => ResultFormatter.on(dr, NaN), 'on_time'],
['in', (dr) => ResultFormatter.in(dr, NaN), 'in_time'],
['engineStart', (dr) => ResultFormatter.engineStart(dr, NaN), 'engine_start_time'],
['engineStop', (dr) => ResultFormatter.engineStop(dr, NaN), 'engine_stop_time'],
];

test.each(cases)(
'%s skips NaN instead of throwing',
(_name, invoke, rawKey) => {
const dr = makeDecodeResult();
expect(() => invoke(dr)).not.toThrow();
expect(dr.formatted.items.length).toBe(0);
expect((dr.raw as Record<string, unknown>)[rawKey]).toBeUndefined();
},
);

test('eta still formats a valid time-of-day', () => {
const dr = makeDecodeResult();
ResultFormatter.eta(dr, 7680);
expect(dr.raw.eta_time).toBe(7680);
expect(dr.formatted.items[0].value).toBe('02:08:00');
});
});
24 changes: 24 additions & 0 deletions lib/utils/result_formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ export class ResultFormatter {
}

static eta(decodeResult: DecodeResult, time: number) {
if (isNaN(time)) {
return;
}
decodeResult.raw.eta_time = time;
decodeResult.formatted.items.push({
type: 'time',
Expand Down Expand Up @@ -380,6 +383,9 @@ export class ResultFormatter {
}

static out(decodeResult: DecodeResult, time: number) {
if (isNaN(time)) {
return;
}
decodeResult.raw.out_time = time;
decodeResult.formatted.items.push({
type: 'time',
Expand All @@ -390,6 +396,9 @@ export class ResultFormatter {
}

static off(decodeResult: DecodeResult, time: number) {
if (isNaN(time)) {
return;
}
decodeResult.raw.off_time = time;
decodeResult.formatted.items.push({
type: 'time',
Expand All @@ -400,6 +409,9 @@ export class ResultFormatter {
}

static on(decodeResult: DecodeResult, time: number) {
if (isNaN(time)) {
return;
}
decodeResult.raw.on_time = time;
decodeResult.formatted.items.push({
type: 'time',
Expand All @@ -410,6 +422,9 @@ export class ResultFormatter {
}

static in(decodeResult: DecodeResult, time: number) {
if (isNaN(time)) {
return;
}
decodeResult.raw.in_time = time;
decodeResult.formatted.items.push({
type: 'time',
Expand All @@ -420,6 +435,9 @@ export class ResultFormatter {
}

static engineStart(decodeResult: DecodeResult, time: number) {
if (isNaN(time)) {
return;
}
decodeResult.raw.engine_start_time = time;
decodeResult.formatted.items.push({
type: 'time',
Expand All @@ -429,6 +447,9 @@ export class ResultFormatter {
});
}
static engineStop(decodeResult: DecodeResult, time: number) {
if (isNaN(time)) {
return;
}
decodeResult.raw.engine_stop_time = time;
decodeResult.formatted.items.push({
type: 'time',
Expand Down Expand Up @@ -651,6 +672,9 @@ export class ResultFormatter {
}

static timestamp(decodeResult: DecodeResult, value: number) {
if (isNaN(value)) {
return;
}
decodeResult.raw.message_timestamp = value;
decodeResult.formatted.items.push({
type: 'time',
Expand Down