104 lines
2.7 KiB
Go
104 lines
2.7 KiB
Go
package udp
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// A representative N1MM+ <contactinfo> datagram (trimmed to the fields we
|
|
// read). rxfreq 1402500 tens-of-Hz == 14.025 MHz → 20m.
|
|
const sampleContactInfo = `<?xml version="1.0" encoding="utf-8"?>
|
|
<contactinfo>
|
|
<contestname>DX</contestname>
|
|
<timestamp>2024-03-15 14:25:30</timestamp>
|
|
<mycall>K1ABC</mycall>
|
|
<band>14</band>
|
|
<rxfreq>1402500</rxfreq>
|
|
<txfreq>1402500</txfreq>
|
|
<operator>K1ABC</operator>
|
|
<mode>CW</mode>
|
|
<call>VE9AA</call>
|
|
<snt>599</snt>
|
|
<sntnr>1</sntnr>
|
|
<rcv>599</rcv>
|
|
<rcvnr>42</rcvnr>
|
|
<gridsquare>FN65</gridsquare>
|
|
<name>Mike</name>
|
|
<comment>tnx</comment>
|
|
<power>100</power>
|
|
</contactinfo>`
|
|
|
|
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{
|
|
"<call:5>VE9AA": "callsign",
|
|
"<qso_date:8>20240315": "date",
|
|
"<time_on:6>142530": "time",
|
|
"<band:3>20m": "band",
|
|
"<mode:2>CW": "mode",
|
|
"<freq:9>14.025000": "freq",
|
|
"<rst_sent:3>599": "rst sent",
|
|
"<rst_rcvd:3>599": "rst rcvd",
|
|
"<gridsquare:4>FN65": "grid",
|
|
"<name:4>Mike": "name",
|
|
"<stx:1>1": "stx serial",
|
|
"<srx:2>42": "srx serial",
|
|
"<eor>": "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 := `<contactinfo><call>F4XYZ</call><mode>USB</mode><band>14</band><rxfreq>1420000</rxfreq><timestamp>2024-01-01 00:00:00</timestamp></contactinfo>`
|
|
adif, ok, err := ParseN1MM([]byte(pkt))
|
|
if err != nil || !ok {
|
|
t.Fatalf("ParseN1MM ok=%v err=%v", ok, err)
|
|
}
|
|
if !strings.Contains(adif, "<mode:3>SSB") {
|
|
t.Errorf("USB should map to SSB, got:\n%s", adif)
|
|
}
|
|
}
|
|
|
|
func TestParseN1MMIgnoresNonContacts(t *testing.T) {
|
|
for _, pkt := range []string{
|
|
`<RadioInfo><app>N1MM</app><freq>1402500</freq></RadioInfo>`,
|
|
`<spot><dxcall>VE9AA</dxcall><frequency>14025</frequency></spot>`,
|
|
`<contactdelete><call>VE9AA</call></contactdelete>`,
|
|
} {
|
|
_, 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)
|
|
}
|
|
}
|
|
}
|