Fixed bug in extras segment parsing

This commit is contained in:
2026-03-18 19:01:16 +01:00
parent e9e329ccc1
commit 04166daeee
2 changed files with 95 additions and 43 deletions

View File

@@ -6,6 +6,35 @@ import type { PositionPayload } from "../src/frame.types";
import { feetToMeters, milesToMeters } from "../src/parser";
describe("APRS extras test vectors", () => {
it("parses altitude token marker mid-comment and emits structure", () => {
const raw = "N0CALL>APRS,WIDE1-1:!4500.00N/07000.00W#RNG0001ALT/A=001234 Your Comment Here";
const frame = Frame.fromString(raw);
const res = frame.decode(true) as { payload: PositionPayload | null; structure: Dissected };
const { payload, structure } = res;
// console.log(structure[structure.length - 1]); // Log the last segment for debugging
expect(payload).not.toBeNull();
// Altitude 001234 ft -> meters
expect(Math.round((payload!.position.altitude || 0) / 0.3048)).toBe(1234);
const commentSeg = structure.find((s) => /comment/i.test(String(s.name))) as Segment | undefined;
expect(commentSeg).toBeDefined();
const fieldsAlt = (commentSeg!.fields ?? []) as Field[];
const hasAlt = fieldsAlt.some((f) => f.name === "altitude");
expect(hasAlt).toBe(true);
const commentIndex = (commentSeg!.fields ?? []).findIndex((f) => f.name === "comment");
expect(commentIndex).toBe(2); // Range marker + range go before.
const altitudeIndex = (commentSeg!.fields ?? []).findIndex((f) => f.name === "altitude");
expect(altitudeIndex).toBeGreaterThan(0); // Altitude should come after comment in the structure
expect(altitudeIndex).toBeGreaterThan(commentIndex);
const secondCommentIndex = (commentSeg!.fields ?? []).findIndex((f, i) => f.name === "comment" && i > commentIndex);
expect(secondCommentIndex).toBeGreaterThan(altitudeIndex); // Any additional comment fields should come after altitude
});
it("parses PHG from position with messaging (spec vector 1)", () => {
const raw = "NOCALL>APZRAZ,qAS,PA2RDK-14:=5154.19N/00627.77E>PHG500073 de NOCALL";
const frame = Frame.fromString(raw);
@@ -98,7 +127,7 @@ describe("APRS extras test vectors", () => {
it("parses RNG token and emits structure", () => {
const raw =
"NOCALL-S>APDG01,TCPIP*,qAC,NOCALL-GS:;DN9PJF B *181227z5148.38ND00634.32EaRNG0001/A=000010 70cm Voice (D-Star) 439.50000MHz -7.6000MHz";
"N0CALL-S>APDG01,TCPIP*,qAC,N0CALL-GS:;N0CALL B *181721z5148.38ND00634.32EaRNG0001/A=000010 70cm Voice (D-Star) 439.50000MHz -7.6000MHz";
const frame = Frame.fromString(raw);
const res = frame.decode(true) as { payload: PositionPayload | null; structure: Dissected };
const { payload, structure } = res;
@@ -112,5 +141,14 @@ describe("APRS extras test vectors", () => {
const fieldsRNG = (commentSeg!.fields ?? []) as Field[];
const hasRNG = fieldsRNG.some((f) => f.name === "range marker");
expect(hasRNG).toBe(true);
const rangeIndex = (commentSeg!.fields ?? []).findIndex((f) => f.name === "range marker");
expect(rangeIndex).toBeGreaterThanOrEqual(0);
const altitudeIndex = (commentSeg!.fields ?? []).findIndex((f) => f.name === "altitude");
expect(altitudeIndex).toBeGreaterThanOrEqual(0);
expect(rangeIndex).toBeGreaterThanOrEqual(0);
expect(altitudeIndex).toBeGreaterThan(rangeIndex); // Altitude comes after range
const commentIndex = (commentSeg!.fields ?? []).findIndex((f) => f.name === "comment");
expect(commentIndex).toBeGreaterThan(altitudeIndex); // Comment comes after altitude
});
});