package udp import ( "strings" "testing" ) // A representative N1MM+ datagram (trimmed to the fields we // read). rxfreq 1402500 tens-of-Hz == 14.025 MHz → 20m. const sampleContactInfo = ` DX 2024-03-15 14:25:30 K1ABC 14 1402500 1402500 K1ABC CW VE9AA 599 1 599 42 FN65 Mike tnx 100 ` func TestParseN1MMContactInfo(t *testing.T) { adif, ok, err := ParseN1MM([]byte(sampleContactInfo)) if err != nil { t.Fatalf("ParseN1MM error: %v", err) } if !ok { t.Fatal("expected a loggable contact, got ok=false") } want := map[string]string{ "VE9AA": "callsign", "20240315": "date", "142530": "time", "20m": "band", "CW": "mode", "14.025000": "freq", "599": "rst sent", "599": "rst rcvd", "FN65": "grid", "Mike": "name", "1": "stx serial", "42": "srx serial", "": "terminator", } for sub, label := range want { if !strings.Contains(adif, sub) { t.Errorf("missing %s field %q in:\n%s", label, sub, adif) } } } func TestParseN1MMSSBMapping(t *testing.T) { pkt := `F4XYZUSB1414200002024-01-01 00:00:00` adif, ok, err := ParseN1MM([]byte(pkt)) if err != nil || !ok { t.Fatalf("ParseN1MM ok=%v err=%v", ok, err) } if !strings.Contains(adif, "SSB") { t.Errorf("USB should map to SSB, got:\n%s", adif) } } func TestParseN1MMIgnoresNonContacts(t *testing.T) { for _, pkt := range []string{ `N1MM1402500`, `VE9AA14025`, `VE9AA`, } { _, ok, err := ParseN1MM([]byte(pkt)) if err != nil { t.Errorf("unexpected error for %q: %v", pkt, err) } if ok { t.Errorf("expected ok=false (ignored) for %q", pkt) } } } func TestBandFromHz(t *testing.T) { cases := map[int64]string{ 14_025_000: "20m", 7_100_000: "40m", 3_650_000: "80m", 28_400_000: "10m", 144_200_000: "2m", 0: "", 15_000_000: "", // between 20m and 17m → no band } for hz, want := range cases { if got := bandFromHz(hz); got != want { t.Errorf("bandFromHz(%d) = %q, want %q", hz, got, want) } } }