import { describe, it, expect } from 'vitest' import { parseTakStreamFrame, parseTraditionalXmlFrame, parseCotPayload } from '../../../server/utils/cotParser.js' const encodeVarint = (value, bytes = []) => { const byte = value & 0x7F const remaining = value >>> 7 if (remaining === 0) { return [...bytes, byte] } return encodeVarint(remaining, [...bytes, byte | 0x80]) } function buildTakFrame(payload) { const buf = Buffer.from(payload, 'utf8') const varint = encodeVarint(buf.length) return Buffer.concat([Buffer.from([0xBF]), Buffer.from(varint), buf]) } describe('cotParser', () => { describe('parseTakStreamFrame', () => { it('parses valid frame', () => { const payload = '' const frame = buildTakFrame(payload) const result = parseTakStreamFrame(frame) expect(result).not.toBeNull() expect(result.payload.toString('utf8')).toBe(payload) expect(result.bytesConsumed).toBe(frame.length) }) it('returns null for incomplete buffer', () => { const frame = buildTakFrame('') const partial = frame.subarray(0, 2) expect(parseTakStreamFrame(partial)).toBeNull() }) it('returns null for wrong magic', () => { const payload = '' const buf = Buffer.concat([Buffer.from([0x00]), Buffer.from([payload.length]), Buffer.from(payload)]) expect(parseTakStreamFrame(buf)).toBeNull() }) it('returns null for payload length exceeding max', () => { const hugeLen = 64 * 1024 + 1 const varint = encodeVarint(hugeLen) const buf = Buffer.concat([Buffer.from([0xBF]), Buffer.from(varint)]) expect(parseTakStreamFrame(buf)).toBeNull() }) }) describe('parseTraditionalXmlFrame', () => { it('parses one XML message delimited by ', () => { const xml = '' const buf = Buffer.from(xml, 'utf8') const result = parseTraditionalXmlFrame(buf) expect(result).not.toBeNull() expect(result.payload.toString('utf8')).toBe(xml) expect(result.bytesConsumed).toBe(buf.length) }) it('returns null when buffer does not start with <', () => { expect(parseTraditionalXmlFrame(Buffer.from('x'))).toBeNull() expect(parseTraditionalXmlFrame(Buffer.from([0xBF, 0x00]))).toBeNull() }) it('returns null when not yet received', () => { const partial = Buffer.from('', 'utf8') expect(parseTraditionalXmlFrame(partial)).toBeNull() }) it('extracted payload parses as auth CoT', () => { const xml = '' const buf = Buffer.from(xml, 'utf8') const result = parseTraditionalXmlFrame(buf) expect(result).not.toBeNull() const parsed = parseCotPayload(result.payload) expect(parsed).not.toBeNull() expect(parsed.type).toBe('auth') expect(parsed.username).toBe('itak') expect(parsed.password).toBe('mypass') }) }) describe('parseCotPayload', () => { it('parses position CoT XML', () => { const xml = '' const result = parseCotPayload(Buffer.from(xml, 'utf8')) expect(result).not.toBeNull() expect(result.type).toBe('cot') expect(result.id).toBe('device-1') expect(result.lat).toBe(37.7) expect(result.lng).toBe(-122.4) expect(result.label).toBe('Bravo') }) it('parses auth CoT with detail.auth', () => { const xml = '' const result = parseCotPayload(Buffer.from(xml, 'utf8')) expect(result).not.toBeNull() expect(result.type).toBe('auth') expect(result.username).toBe('user1') expect(result.password).toBe('secret123') }) it('parses auth CoT with __auth', () => { const xml = '<__auth username="u2" password="p2"/>' const result = parseCotPayload(Buffer.from(xml, 'utf8')) expect(result).not.toBeNull() expect(result.type).toBe('auth') expect(result.username).toBe('u2') expect(result.password).toBe('p2') }) it('returns null for auth with empty username', () => { const xml = '' const result = parseCotPayload(Buffer.from(xml, 'utf8')) expect(result).toBeNull() }) it('parses position with point.lat and point.lon (no @_ prefix)', () => { const xml = '' const result = parseCotPayload(Buffer.from(xml, 'utf8')) expect(result).not.toBeNull() expect(result.lat).toBe(5) expect(result.lng).toBe(10) }) it('returns null for non-XML payload', () => { expect(parseCotPayload(Buffer.from('not xml'))).toBeNull() }) it('uses uid as label when no contact/callsign', () => { const xml = '' const result = parseCotPayload(Buffer.from(xml, 'utf8')) expect(result).not.toBeNull() expect(result.type).toBe('cot') expect(result.label).toBe('device-99') }) it('uses point inside event when not at root', () => { const xml = '' const result = parseCotPayload(Buffer.from(xml, 'utf8')) expect(result).not.toBeNull() expect(result.lat).toBe(10) expect(result.lng).toBe(20) }) }) })