fix(serial): list a COM port once, in the order a human reads it
An operator's keyer dropdown showed COM1 and COM3 twice, in the order COM1 COM1 COM3 COM8 COM9 COM4 COM3, with "COM3COM3" as the selected value — two entries sharing one value both counted as selected. Not our bug to start with, but ours to absorb. Windows enumerates serial ports from HARDWARE\DEVICEMAP\SERIALCOMM, which maps a DEVICE PATH to a COM name, so the same name legitimately appears twice when two devices claim it: a driver uninstalled without cleaning up after itself, or virtual-port software. go.bug.st/serial returns one entry per device, faithfully. Deduplicated and naturally sorted in the one binding every port dropdown in the app calls, so CAT, rotators, amplifiers and the keyer all get it. COM4 now sits between COM3 and COM8 rather than after COM9, which is how a port gets overlooked on a machine with a dozen. A dropped duplicate is logged rather than swallowed: two devices holding one COM name is also a good reason for one of them to report that port busy, and that is not something an operator can work out from a list.
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// The exact list an operator's machine produced: COM1 and COM3 each claimed by
|
||||
// two devices in the Windows port map, and no order to speak of. The dropdown
|
||||
// showed every duplicate, and rendered its own value as "COM3COM3" because two
|
||||
// entries with the same value both counted as selected.
|
||||
func TestTidySerialPortsDeduplicatesAndOrders(t *testing.T) {
|
||||
got := tidySerialPorts([]string{"COM1", "COM1", "COM3", "COM8", "COM9", "COM4", "COM3"})
|
||||
want := []string{"COM1", "COM3", "COM4", "COM8", "COM9"}
|
||||
if strings.Join(got, ",") != strings.Join(want, ",") {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// COM10 after COM9, not between COM1 and COM2 — lexical order is how a port
|
||||
// gets overlooked on a machine with a dozen of them.
|
||||
func TestTidySerialPortsSortsNaturally(t *testing.T) {
|
||||
got := tidySerialPorts([]string{"COM10", "COM2", "COM1", "COM20", "COM3"})
|
||||
want := []string{"COM1", "COM2", "COM3", "COM10", "COM20"}
|
||||
if strings.Join(got, ",") != strings.Join(want, ",") {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Not every port is a COMn: a device path or a Unix name must survive, after
|
||||
// the numbered ones, in its own order.
|
||||
func TestTidySerialPortsKeepsOtherNames(t *testing.T) {
|
||||
got := tidySerialPorts([]string{"/dev/ttyUSB1", "COM3", "/dev/ttyUSB0", "COM1", "", " "})
|
||||
want := []string{"COM1", "COM3", "/dev/ttyUSB0", "/dev/ttyUSB1"}
|
||||
if strings.Join(got, ",") != strings.Join(want, ",") {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Case is not identity on Windows: "com3" and "COM3" are one port, and letting
|
||||
// both through would put the same duplicate back in the list.
|
||||
func TestTidySerialPortsIgnoresCase(t *testing.T) {
|
||||
if got := tidySerialPorts([]string{"COM3", "com3"}); len(got) != 1 || got[0] != "COM3" {
|
||||
t.Errorf("got %v, want [COM3]", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user