| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- package device
- import (
- "encoding/json"
- "os"
- "path/filepath"
- "strings"
- "testing"
- )
- func TestIndexDevices(t *testing.T) {
- tests := []struct {
- name string
- devices []Device
- want []string
- }{
- {
- name: "empty",
- devices: nil,
- want: nil,
- },
- {
- name: "single",
- devices: []Device{{Path: "/dev/hidraw7", VendorID: 0x36b0, ProductID: 0x309f}},
- want: []string{"/dev/hidraw7"},
- },
- {
- name: "sorted by vendor then product then path",
- devices: []Device{
- {Path: "/dev/hidraw9", VendorID: 0x9999, ProductID: 0x0001},
- {Path: "/dev/hidraw5", VendorID: 0x1111, ProductID: 0x0002},
- {Path: "/dev/hidraw2", VendorID: 0x1111, ProductID: 0x0001},
- },
- want: []string{"/dev/hidraw2", "/dev/hidraw5", "/dev/hidraw9"},
- },
- {
- name: "identical vendor and product sorted by path",
- devices: []Device{
- {Path: "/dev/hidrawB", VendorID: 0x36b0, ProductID: 0x309f},
- {Path: "/dev/hidrawA", VendorID: 0x36b0, ProductID: 0x309f},
- },
- want: []string{"/dev/hidrawA", "/dev/hidrawB"},
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := indexDevices(tt.devices)
- if len(got) != len(tt.want) {
- t.Fatalf("indexDevices() returned %d devices, want %d", len(got), len(tt.want))
- }
- for i, wantPath := range tt.want {
- if got[i].Path != wantPath {
- t.Errorf("indexDevices()[%d].Path = %q, want %q", i, got[i].Path, wantPath)
- }
- if got[i].Index != i+1 {
- t.Errorf("indexDevices()[%d].Index = %d, want %d", i, got[i].Index, i+1)
- }
- }
- })
- }
- }
- func TestIndexDevicesDoesNotMutateInput(t *testing.T) {
- input := []Device{
- {Path: "/dev/hidraw9", VendorID: 0x9999, ProductID: 0x0001},
- {Path: "/dev/hidraw2", VendorID: 0x1111, ProductID: 0x0001},
- }
- indexDevices(input)
- if input[0].Path != "/dev/hidraw9" {
- t.Errorf("indexDevices() mutated input: input[0].Path = %q, want %q", input[0].Path, "/dev/hidraw9")
- }
- if input[0].Index != 0 {
- t.Errorf("indexDevices() mutated input: input[0].Index = %d, want 0", input[0].Index)
- }
- }
- func TestDeviceJSONFieldNames(t *testing.T) {
- dev := Device{
- Index: 1,
- Path: "/dev/hidraw7",
- VendorID: 0x36b0,
- ProductID: 0x309f,
- Name: "Wobkey Impact 80",
- Known: true,
- }
- data, err := json.Marshal(dev)
- if err != nil {
- t.Fatalf("Marshal() returned error: %v", err)
- }
- var got map[string]any
- if err := json.Unmarshal(data, &got); err != nil {
- t.Fatalf("Unmarshal() returned error: %v", err)
- }
- for _, field := range []string{"index", "path", "vendorId", "productId", "name", "known"} {
- if _, ok := got[field]; !ok {
- t.Errorf("Device JSON = %s, missing field %q", data, field)
- }
- }
- if _, ok := got["supported"]; ok {
- t.Errorf("Device JSON = %s, must not contain the misleading field \"supported\"", data)
- }
- }
- func TestDeviceJSONOmitsUnnamedName(t *testing.T) {
- data, err := json.Marshal(Device{Index: 2, Path: "/dev/hidraw9", Known: false})
- if err != nil {
- t.Fatalf("Marshal() returned error: %v", err)
- }
- if strings.Contains(string(data), `"name"`) {
- t.Errorf("Device JSON = %s, want the name omitted for an unknown keyboard", data)
- }
- }
- func TestKeyboardIgnoresUnknownFields(t *testing.T) {
- tmpDir := t.TempDir()
- tmpFile := filepath.Join(tmpDir, "keyboards.json")
- // Entries may still carry fields the tool does not use; loading must
- // succeed and yield only the fields the code actually reads.
- testData := `[
- {"name":"Impact 80","vendorId":14000,"productId":12447,
- "protocol":"via","viaVersion":3,"ledLayout":"rgblight","futureField":"ignored"}
- ]`
- if err := os.WriteFile(tmpFile, []byte(testData), 0644); err != nil {
- t.Fatalf("failed to write test file: %v", err)
- }
- origFind := findKeyboardsJSON
- findKeyboardsJSON = func() (string, error) { return tmpFile, nil }
- defer func() { findKeyboardsJSON = origFind }()
- keyboards, err := LoadKeyboards()
- if err != nil {
- t.Fatalf("LoadKeyboards() returned error: %v", err)
- }
- if len(keyboards) != 1 {
- t.Fatalf("LoadKeyboards() returned %d keyboards, want 1", len(keyboards))
- }
- if keyboards[0].Name != "Impact 80" {
- t.Errorf("Name = %q, want %q", keyboards[0].Name, "Impact 80")
- }
- }
- func TestKeyboardJSONOmitsRemovedFields(t *testing.T) {
- data, err := json.Marshal(Keyboard{Name: "Impact 80", VendorID: 0x36b0, ProductID: 0x309f})
- if err != nil {
- t.Fatalf("Marshal() returned error: %v", err)
- }
- for _, dead := range []string{"protocol", "viaVersion", "ledLayout"} {
- if strings.Contains(string(data), dead) {
- t.Errorf("Keyboard JSON = %s, want no %q field", data, dead)
- }
- }
- }
- func TestLoadKeyboards(t *testing.T) {
- tmpDir := t.TempDir()
- tmpFile := filepath.Join(tmpDir, "keyboards.json")
- testData := `[
- {"name": "Test Keyboard 1", "vendorId": 22222, "productId": 1, "protocol": "via"},
- {"name": "Test Keyboard 2", "vendorId": 33333, "productId": 2, "protocol": "viapro"}
- ]`
- if err := os.WriteFile(tmpFile, []byte(testData), 0644); err != nil {
- t.Fatalf("failed to write test file: %v", err)
- }
- origFind := findKeyboardsJSON
- findKeyboardsJSON = func() (string, error) {
- return tmpFile, nil
- }
- defer func() { findKeyboardsJSON = origFind }()
- keyboards, err := LoadKeyboards()
- if err != nil {
- t.Fatalf("LoadKeyboards() returned error: %v", err)
- }
- if len(keyboards) != 2 {
- t.Errorf("LoadKeyboards() returned %d keyboards, want 2", len(keyboards))
- }
- if keyboards[0].Name != "Test Keyboard 1" {
- t.Errorf("First keyboard name = %q, want %q", keyboards[0].Name, "Test Keyboard 1")
- }
- if keyboards[0].VendorID != 22222 {
- t.Errorf("First keyboard VID = %d, want %d", keyboards[0].VendorID, 22222)
- }
- if keyboards[1].ProductID != 2 {
- t.Errorf("Second keyboard PID = %d, want %d", keyboards[1].ProductID, 2)
- }
- }
- func TestLoadKeyboardsInvalid(t *testing.T) {
- tmpDir := t.TempDir()
- tmpFile := filepath.Join(tmpDir, "keyboards.json")
- invalidData := `[this is not valid json`
- if err := os.WriteFile(tmpFile, []byte(invalidData), 0644); err != nil {
- t.Fatalf("failed to write test file: %v", err)
- }
- origFind := findKeyboardsJSON
- findKeyboardsJSON = func() (string, error) {
- return tmpFile, nil
- }
- defer func() { findKeyboardsJSON = origFind }()
- _, err := LoadKeyboards()
- if err == nil {
- t.Error("LoadKeyboards() expected error for invalid JSON, got nil")
- }
- }
- func TestLoadKeyboardsEmptyFile(t *testing.T) {
- tmpDir := t.TempDir()
- tmpFile := filepath.Join(tmpDir, "keyboards.json")
- if err := os.WriteFile(tmpFile, []byte("[]"), 0644); err != nil {
- t.Fatalf("failed to write test file: %v", err)
- }
- origFind := findKeyboardsJSON
- findKeyboardsJSON = func() (string, error) {
- return tmpFile, nil
- }
- defer func() { findKeyboardsJSON = origFind }()
- keyboards, err := LoadKeyboards()
- if err != nil {
- t.Fatalf("LoadKeyboards() returned error: %v", err)
- }
- if len(keyboards) != 0 {
- t.Errorf("LoadKeyboards() returned %d keyboards, want 0", len(keyboards))
- }
- }
|