package aprs import ( "bufio" "io" "math" "os" "path/filepath" "strconv" "strings" "testing" ) func TestParse(t *testing.T) { tests := []struct { Line string Want *Frame }{ { `PD0MZ-10>APLRG1,WIDE1-1,qAC:=L4:I#P),la !GLoRa APRS iGate / 433.775MHz / 125kHz / SF12 / CR5 Batt=4.25V`, &Frame{ Source: Address{Call: "PD0MZ", SSID: "10"}, Destination: Address{Call: "APLRG1"}, Path: Path{{Call: "WIDE1", SSID: "1"}, {Call: "qAC"}}, Data: &Position{ Latitude: 51.860004, Longitude: 6.309997, HasMessaging: true, Symbol: "La", Comment: "LoRa APRS iGate / 433.775MHz / 125kHz / SF12 / CR5 Batt=4.25V", }, }, }, } for _, test := range tests { t.Run(test.Line, func(t *testing.T) { f, err := Parse(test.Line) if err != nil { t.Fatal(err) } //if !reflect.DeepEqual(f, test.Want) { // t.Errorf("expected %+#v, got %#+v", test.Want, f) //} testCompareFrame(t, test.Want, f) }) } } func TestParseSamples(t *testing.T) { f, err := os.Open(filepath.Join("testdata", "packets.txt")) if err != nil { t.Skip(err) return } defer func() { _ = f.Close() }() r := bufio.NewReader(f) for { l, err := r.ReadString('\n') if err != nil { if err == io.EOF { return } t.Fatal(err) } l = testUnescapeHex(strings.TrimSpace(l[25:])) if _, err = Parse(l); err != nil { t.Errorf("%s: %v", l, err) } } } // testUnescapeHex replaces occurrences of <0xHH> (case-insensitive) // with the corresponding single byte. // Invalid sequences are left unchanged. func testUnescapeHex(s string) string { if !strings.Contains(s, "<0x") && !strings.Contains(s, "<0X") { return s } var b strings.Builder b.Grow(len(s)) // upper bound; result will not exceed input length for i := 0; i < len(s); { // Minimal length for "<0xHH>" is 6 if i+6 <= len(s) && s[i] == '<' && (s[i+1] == '0') && (s[i+2] == 'x' || s[i+2] == 'X') && testIsHex(s[i+3]) && testIsHex(s[i+4]) && s[i+5] == '>' { // Parse the hex byte v, err := strconv.ParseUint(s[i+3:i+5], 16, 8) if err == nil { b.WriteByte(byte(v)) i += 6 continue } } // Default: copy one byte and continue b.WriteByte(s[i]) i++ } return b.String() } func testIsHex(c byte) bool { return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F') } func testAlmostEqual(a, b float64) bool { return math.Abs(a-b) < 1e-5 } func testCompareFrame(t *testing.T, want, test *Frame) { t.Helper() if !test.Source.EqualTo(want.Source) { t.Errorf("expected source %s, got %s", want.Source, test.Source) } if !test.Destination.EqualTo(want.Destination) { t.Errorf("expected destination %s, got %s", want.Destination, test.Destination) } if !test.Path.EqualTo(want.Path) { t.Errorf("expected path %q, got %q", want.Path, test.Path) } testCompareData(t, want.Data, test.Data) }