homelabby/internal/usb/device_test.go
Mikkel Georgsen f5b1d3156c feat(04-01): USB device types, KnownDevices registry, VID/PID enumeration
- DeviceSpec, DeviceRole, DeviceState, DeviceEvent, Command types
- KnownDevices registry with PRT Qutie placeholder (0525:a4a7)
- enumerateConnected() with system_profiler JSON parsing + injectable test seams
- ParseVIDPID() helper with error on malformed input
- All 5 device_test.go tests pass
- go.bug.st/serial v1.6.4 added to go.mod
2026-04-10 06:43:43 +00:00

111 lines
2.9 KiB
Go

package usb
import (
"testing"
)
// Test 1: KnownDevices registry contains PRT Qutie with correct role
func TestKnownDevicesContainsPRTQutie(t *testing.T) {
spec, ok := KnownDevices["0525:a4a7"]
if !ok {
t.Fatal("KnownDevices missing entry for 0525:a4a7 (PRT Qutie)")
}
if spec.Role != RolePrinter {
t.Errorf("expected RolePrinter, got %v", spec.Role)
}
if spec.VID != "0525" {
t.Errorf("expected VID=0525, got %s", spec.VID)
}
if spec.PID != "a4a7" {
t.Errorf("expected PID=a4a7, got %s", spec.PID)
}
}
// Test 2: enumerateConnected with mock sysProfilerCmd returns only known VID/PID ports
func TestEnumerateConnectedMockOutput(t *testing.T) {
// Mock system_profiler JSON that contains a device matching PRT Qutie VID/PID
// and a port path in the serial port list.
mockJSON := `{
"SPUSBDataType": [
{
"_name": "USB31Bus",
"_items": [
{
"_name": "PRT Qutie",
"vendor_id": "0x0525",
"product_id": "0xa4a7",
"bsd_name": "cu.usbmodem12345"
},
{
"_name": "Unknown Device",
"vendor_id": "0x1234",
"product_id": "0xabcd",
"bsd_name": "cu.usbmodem99999"
}
]
}
]
}`
// Override the injectable command function
orig := sysProfilerCmd
defer func() { sysProfilerCmd = orig }()
sysProfilerCmd = func() ([]byte, error) {
return []byte(mockJSON), nil
}
// Override serial port list
origPorts := serialPortsListCmd
defer func() { serialPortsListCmd = origPorts }()
serialPortsListCmd = func() ([]string, error) {
return []string{"/dev/cu.usbmodem12345", "/dev/cu.usbmodem99999"}, nil
}
result, err := enumerateConnected()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Should only contain known device (PRT Qutie), not the unknown one
if len(result) != 1 {
t.Errorf("expected 1 device, got %d: %v", len(result), result)
}
path, ok := result["0525:a4a7"]
if !ok {
t.Error("expected 0525:a4a7 in result")
}
if path != "/dev/cu.usbmodem12345" {
t.Errorf("expected path /dev/cu.usbmodem12345, got %s", path)
}
}
// Test 3: DeviceSpec.String() returns "VID:PID (Name)" format
func TestDeviceSpecString(t *testing.T) {
spec := DeviceSpec{VID: "0525", PID: "a4a7", Name: "PRT Qutie", Role: RolePrinter}
expected := "0525:a4a7 (PRT Qutie)"
if got := spec.String(); got != expected {
t.Errorf("expected %q, got %q", expected, got)
}
}
// Test 4: ParseVIDPID("0525:a4a7") returns correct values
func TestParseVIDPIDValid(t *testing.T) {
vid, pid, err := ParseVIDPID("0525:a4a7")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if vid != "0525" {
t.Errorf("expected vid=0525, got %s", vid)
}
if pid != "a4a7" {
t.Errorf("expected pid=a4a7, got %s", pid)
}
}
// Test 5: ParseVIDPID("badvalue") returns error
func TestParseVIDPIDInvalid(t *testing.T) {
_, _, err := ParseVIDPID("badvalue")
if err == nil {
t.Error("expected error for invalid VID:PID format, got nil")
}
}