import { describe, it, expect } from 'vitest'; import { base91ToNumber, knotsToKmh, kmhToKnots, feetToMeters, metersToFeet, celsiusToFahrenheit, fahrenheitToCelsius, } from '../src/parser'; describe('parser utilities', () => { describe('base91ToNumber', () => { it('decodes all-! to 0', () => { expect(base91ToNumber('!!!!')).toBe(0); }); it('decodes single character correctly', () => { // 'A' === 65, digit = 65 - 33 = 32 expect(base91ToNumber('A')).toBe(32); }); it('should decode multiple Base91 characters', () => { // "!!" = 0 * 91 + 0 = 0 expect(base91ToNumber('!!')).toBe(0); // "!#" = 0 * 91 + 2 = 2 expect(base91ToNumber('!#')).toBe(2); // "#!" = 2 * 91 + 0 = 182 expect(base91ToNumber('#!')).toBe(182); // "##" = 2 * 91 + 2 = 184 expect(base91ToNumber('##')).toBe(184); }); it('should decode 4-character Base91 strings (used in APRS)', () => { // Test with printable ASCII Base91 characters (33-123) const testValue = base91ToNumber('!#%\''); expect(testValue).toBeGreaterThan(0); expect(testValue).toBeLessThan(91 * 91 * 91 * 91); }); it('should decode maximum valid Base91 value', () => { // Maximum is '{' (ASCII 123, digit 90) repeated const maxValue = base91ToNumber('{{{{'); const expected = 90 * 91 * 91 * 91 + 90 * 91 * 91 + 90 * 91 + 90; expect(maxValue).toBe(expected); }); it('should handle APRS compressed position example', () => { // Using actual characters from APRS test vector const latStr = '/:*E'; const lonStr = 'qZ=O'; const latValue = base91ToNumber(latStr); const lonValue = base91ToNumber(lonStr); // Just verify they decode without error and produce valid numbers expect(typeof latValue).toBe('number'); expect(typeof lonValue).toBe('number'); expect(latValue).toBeGreaterThanOrEqual(0); expect(lonValue).toBeGreaterThanOrEqual(0); }); it('throws on invalid character', () => { expect(() => base91ToNumber(' ')).toThrow(); // space (code 32) is invalid }); }); describe('unit conversions', () => { it('converts knots <-> km/h', () => { expect(knotsToKmh(10)).toBeCloseTo(18.52, 5); expect(kmhToKnots(18.52)).toBeCloseTo(10, 3); }); it('converts feet <-> meters', () => { expect(feetToMeters(10)).toBeCloseTo(3.048, 6); expect(metersToFeet(3.048)).toBeCloseTo(10, 6); }); it('converts celsius <-> fahrenheit', () => { expect(celsiusToFahrenheit(0)).toBeCloseTo(32, 6); expect(fahrenheitToCelsius(32)).toBeCloseTo(0, 6); expect(celsiusToFahrenheit(100)).toBeCloseTo(212, 6); expect(fahrenheitToCelsius(212)).toBeCloseTo(100, 6); }); }); });