Initial import
This commit is contained in:
99
test/frame.test.ts
Normal file
99
test/frame.test.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { encodeAX25, Frame, UnnumberedFrame, InformationFrame, SupervisoryFrame, buildIControl, buildSControl, buildUControl, encodeFrame, toHDLC } from '../src/frame';
|
||||
import { Address } from '../src/address';
|
||||
import { unescapeBuffer, computeFcs } from '../src/hdlc';
|
||||
|
||||
describe('Frame.buildSControl', () => {
|
||||
it('builds S control byte', () => {
|
||||
const c = buildSControl('RNR', 4, 0);
|
||||
// bits 0-1 == 01 and s-code 1 in bits 2-3
|
||||
expect((c & 0x03)).toBe(0x01);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Frame.encodeFrame', () => {
|
||||
it('builds I control byte and roundtrips encode/parse', () => {
|
||||
const dst = new Address('DST', 0);
|
||||
const src = new Address('SRC', 1);
|
||||
const ns = 3;
|
||||
const nr = 5;
|
||||
const pf = 1;
|
||||
const control = buildIControl(ns, nr, pf);
|
||||
const info = new TextEncoder().encode('payload');
|
||||
const f = new InformationFrame(src, dst, control, info, ns, nr, pf);
|
||||
const buf = encodeFrame(f);
|
||||
const parsed = Frame.fromBytes(buf);
|
||||
expect(parsed instanceof InformationFrame).toBe(true);
|
||||
const p = parsed as InformationFrame;
|
||||
expect(p.ns).toBe(ns);
|
||||
expect(p.nr).toBe(nr);
|
||||
expect(p.pf).toBe(pf);
|
||||
expect(new TextDecoder().decode(p.info)).toBe('payload');
|
||||
});
|
||||
|
||||
it('encodes UI unnumbered frames including PID and info', () => {
|
||||
const dst = new Address('APRS', 0);
|
||||
const src = new Address('N0CALL', 0);
|
||||
const control = buildUControl('UI', 0);
|
||||
const info = new TextEncoder().encode('!Hello');
|
||||
const f = new UnnumberedFrame(src, dst, control, 'UI', 0, info);
|
||||
f.pid = 0xf0;
|
||||
const buf = encodeFrame(f);
|
||||
const parsed = Frame.fromBytes(buf);
|
||||
expect(parsed instanceof UnnumberedFrame).toBe(true);
|
||||
const u = parsed as UnnumberedFrame;
|
||||
expect(u.pid).toBe(0xf0);
|
||||
expect(new TextDecoder().decode(u.info)).toBe('!Hello');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Frame.fromBytes', () => {
|
||||
it('parses a simple UI frame', () => {
|
||||
const info = new TextEncoder().encode('hello');
|
||||
const payload = encodeAX25('DEST-0', 'SRC-1', info, { ui: true });
|
||||
const f = Frame.fromBytes(payload);
|
||||
expect(f.source).toBeInstanceOf(Address);
|
||||
expect(f.destination).toBeInstanceOf(Address);
|
||||
expect(f.source.toString()).toBe('SRC-1');
|
||||
expect(f.destination.toString()).toBe('DEST-0');
|
||||
expect(new TextDecoder().decode(f.info)).toBe('hello');
|
||||
});
|
||||
it('parses frames with multiple address fields', () => {
|
||||
const dest = new Address('DST', 0);
|
||||
const src = new Address('SRC', 1);
|
||||
const digi = new Address('DIGI', 2);
|
||||
const parts: number[] = [];
|
||||
parts.push(...dest.toBytes(false));
|
||||
parts.push(...src.toBytes(false));
|
||||
parts.push(...digi.toBytes(true));
|
||||
parts.push(0x03); // control
|
||||
parts.push(0xf0); // pid
|
||||
parts.push(...new TextEncoder().encode('spec'));
|
||||
const payload = Uint8Array.from(parts);
|
||||
const f = Frame.fromBytes(payload);
|
||||
expect(f.source.toString()).toBe('SRC-1');
|
||||
expect(f.destination.toString()).toBe('DST-0');
|
||||
expect(new TextDecoder().decode(f.info)).toBe('spec');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Frame.toHDLC', () => {
|
||||
it('produces HDLC frame with FCS via toHDLC', () => {
|
||||
const dst = new Address('APRS', 0);
|
||||
const src = new Address('N0CALL', 0);
|
||||
const control = buildUControl('UI', 0);
|
||||
const info = new TextEncoder().encode('!Hello');
|
||||
const f = new UnnumberedFrame(src, dst, control, 'UI', 0, info);
|
||||
f.pid = 0xf0;
|
||||
const h = toHDLC(f);
|
||||
expect(h[0]).toBe(0x7e);
|
||||
expect(h[h.length - 1]).toBe(0x7e);
|
||||
const inner = h.slice(1, h.length - 1);
|
||||
const unescaped = unescapeBuffer(inner);
|
||||
// last two bytes of unescaped payload must equal computed FCS (LE)
|
||||
const ax = encodeFrame(f);
|
||||
const fcs = computeFcs(ax);
|
||||
expect(unescaped[unescaped.length - 2]).toBe(fcs & 0xff);
|
||||
expect(unescaped[unescaped.length - 1]).toBe((fcs >> 8) & 0xff);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user