package udp import ( "bytes" "encoding/binary" "testing" ) // A grid reaches OpsLog in TWO kinds of message, not one. The reply that // answers a CQ with a locator — "C91RU IZ5EME JN52" — is the commonest of them // on a busy band, and reading only CQs meant any station whose CQ we happened // to miss had no known grid at all, so it could never be flagged as a new one. func TestDecodeGridFromBothMessageShapes(t *testing.T) { for _, tc := range []struct { msg string call string cq bool grid string why string }{ {"CQ RW9MZ MO74", "RW9MZ", true, "MO74", "a plain CQ"}, {"CQ DX F4BPO JN36", "F4BPO", true, "JN36", "a CQ with a modifier"}, {"C91RU IZ5EME JN52", "IZ5EME", false, "JN52", "a reply answering with its grid"}, {"YB1EWD YO6GLT KN36", "YO6GLT", false, "KN36", "the same, other way round"}, // Everything else in the third slot is a report or a sign-off, and must // never be mistaken for a locator. {"C91RU IZ5EME -05", "IZ5EME", false, "", "a signal report is not a grid"}, {"C91RU IZ5EME R-05", "IZ5EME", false, "", "a rogered report is not a grid"}, {"C91RU IZ5EME RRR", "IZ5EME", false, "", "RRR is not a grid"}, {"C91RU IZ5EME RR73", "IZ5EME", false, "", "RR73 has the shape of one and is not"}, {"C91RU IZ5EME 73", "IZ5EME", false, "", "73 is not a grid"}, {" 8F81SU RR73", "8F81SU", false, "", "a hashed call, signing off"}, } { call, cq, grid := wsjtSender(tc.msg) if call != tc.call || cq != tc.cq || grid != tc.grid { t.Errorf("wsjtSender(%q) = (%q, %v, %q), want (%q, %v, %q) — %s", tc.msg, call, cq, grid, tc.call, tc.cq, tc.grid, tc.why) } } } // The Reply replays the decode field for field, so the message must survive the // trip UNTRIMMED. DecodeMsg is trimmed for display; DecodeMsgRaw is what goes // back, and a stripped trailing space is a mismatch the far end reports nowhere. func TestDecodeKeepsTheUntrimmedMessage(t *testing.T) { qstr := func(b *bytes.Buffer, v string) { binary.Write(b, binary.BigEndian, int32(len(v))) b.WriteString(v) } const padded = "CQ RW9MZ MO74 " var p bytes.Buffer binary.Write(&p, binary.BigEndian, uint32(wsjtMagic)) binary.Write(&p, binary.BigEndian, uint32(2)) binary.Write(&p, binary.BigEndian, uint32(wsjtMsgDecode)) qstr(&p, "JTDX") binary.Write(&p, binary.BigEndian, uint8(1)) binary.Write(&p, binary.BigEndian, uint32(45_000_000)) binary.Write(&p, binary.BigEndian, int32(-6)) binary.Write(&p, binary.BigEndian, float64(0.2)) binary.Write(&p, binary.BigEndian, uint32(1500)) qstr(&p, "~") qstr(&p, padded) ev, ok, err := ParseWSJT(p.Bytes()) if err != nil || !ok { t.Fatalf("parse: %v ok=%v", err, ok) } if ev.DecodeMsgRaw != padded { t.Errorf("DecodeMsgRaw = %q, want %q — a Reply built from this will not match", ev.DecodeMsgRaw, padded) } if ev.DecodeMsg != "CQ RW9MZ MO74" { t.Errorf("DecodeMsg = %q, want it trimmed for display", ev.DecodeMsg) } }