package udp import ( "bytes" "testing" ) // The Halt Tx datagram, byte for byte. A wrong byte here does not fail loudly — // WSJT-X drops a malformed packet in silence, and the operator sees a Halt // button that simply does nothing. func TestEncodeHaltTx(t *testing.T) { tests := []struct { name string id string autoTxOnly bool want []byte }{ { name: "halt now", id: "WSJT-X", want: []byte{ 0xad, 0xbc, 0xcb, 0xda, // magic 0x00, 0x00, 0x00, 0x02, // schema 2 0x00, 0x00, 0x00, 0x08, // type 8 — Halt Tx 0x00, 0x00, 0x00, 0x06, // id length 'W', 'S', 'J', 'T', '-', 'X', 0x00, // auto_tx_only = false → stop mid-over }, }, { name: "finish the over first", id: "MSHV", autoTxOnly: true, want: []byte{ 0xad, 0xbc, 0xcb, 0xda, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 'M', 'S', 'H', 'V', 0x01, }, }, { // An empty id is length 0, never the -1 that means a null QString: // a null where text is expected makes WSJT-X discard the packet. name: "empty id is a zero-length string", id: "", want: []byte{ 0xad, 0xbc, 0xcb, 0xda, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, }, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { got := EncodeHaltTx(tc.id, tc.autoTxOnly) if !bytes.Equal(got, tc.want) { t.Errorf("EncodeHaltTx(%q, %v)\n got %#v\nwant %#v", tc.id, tc.autoTxOnly, got, tc.want) } }) } } // SendHaltTx must refuse an empty id rather than broadcast a halt at whatever // application happens to answer: with two receivers sharing a multicast group, // halting the wrong one is worse than doing nothing. func TestSendHaltTxRejectsEmptyID(t *testing.T) { m := &Manager{} if err := m.SendHaltTx(" ", false); err == nil { t.Fatal("expected an error for a blank program id") } }