protocol/aprs: refactored
Some checks failed
Run tests / test (1.25) (push) Failing after 1m37s
Run tests / test (stable) (push) Failing after 1m37s

This commit is contained in:
2026-03-02 22:28:17 +01:00
parent 452f521866
commit 63040a44b3
24 changed files with 3506 additions and 1533 deletions

136
protocol/aprs/frame_test.go Normal file
View File

@@ -0,0 +1,136 @@
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)
}