protocol/aprs: refactored
This commit is contained in:
136
protocol/aprs/frame_test.go
Normal file
136
protocol/aprs/frame_test.go
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user