device_test.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package device
  2. import (
  3. "encoding/json"
  4. "strings"
  5. "testing"
  6. )
  7. func TestIndexDevices(t *testing.T) {
  8. tests := []struct {
  9. name string
  10. devices []Device
  11. want []string
  12. }{
  13. {
  14. name: "empty",
  15. devices: nil,
  16. want: nil,
  17. },
  18. {
  19. name: "single",
  20. devices: []Device{{Path: "/dev/hidraw7", VendorID: 0x36b0, ProductID: 0x309f}},
  21. want: []string{"/dev/hidraw7"},
  22. },
  23. {
  24. name: "sorted by vendor then product then path",
  25. devices: []Device{
  26. {Path: "/dev/hidraw9", VendorID: 0x9999, ProductID: 0x0001},
  27. {Path: "/dev/hidraw5", VendorID: 0x1111, ProductID: 0x0002},
  28. {Path: "/dev/hidraw2", VendorID: 0x1111, ProductID: 0x0001},
  29. },
  30. want: []string{"/dev/hidraw2", "/dev/hidraw5", "/dev/hidraw9"},
  31. },
  32. {
  33. name: "identical vendor and product sorted by path",
  34. devices: []Device{
  35. {Path: "/dev/hidrawB", VendorID: 0x36b0, ProductID: 0x309f},
  36. {Path: "/dev/hidrawA", VendorID: 0x36b0, ProductID: 0x309f},
  37. },
  38. want: []string{"/dev/hidrawA", "/dev/hidrawB"},
  39. },
  40. }
  41. for _, tt := range tests {
  42. t.Run(tt.name, func(t *testing.T) {
  43. got := indexDevices(tt.devices)
  44. if len(got) != len(tt.want) {
  45. t.Fatalf("indexDevices() returned %d devices, want %d", len(got), len(tt.want))
  46. }
  47. for i, wantPath := range tt.want {
  48. if got[i].Path != wantPath {
  49. t.Errorf("indexDevices()[%d].Path = %q, want %q", i, got[i].Path, wantPath)
  50. }
  51. if got[i].Index != i+1 {
  52. t.Errorf("indexDevices()[%d].Index = %d, want %d", i, got[i].Index, i+1)
  53. }
  54. }
  55. })
  56. }
  57. }
  58. func TestIndexDevicesDoesNotMutateInput(t *testing.T) {
  59. input := []Device{
  60. {Path: "/dev/hidraw9", VendorID: 0x9999, ProductID: 0x0001},
  61. {Path: "/dev/hidraw2", VendorID: 0x1111, ProductID: 0x0001},
  62. }
  63. indexDevices(input)
  64. if input[0].Path != "/dev/hidraw9" {
  65. t.Errorf("indexDevices() mutated input: input[0].Path = %q, want %q", input[0].Path, "/dev/hidraw9")
  66. }
  67. if input[0].Index != 0 {
  68. t.Errorf("indexDevices() mutated input: input[0].Index = %d, want 0", input[0].Index)
  69. }
  70. }
  71. func TestDeviceJSONFieldNames(t *testing.T) {
  72. dev := Device{
  73. Index: 1,
  74. Path: "/dev/hidraw7",
  75. VendorID: 0x36b0,
  76. ProductID: 0x309f,
  77. Name: "Impact 80",
  78. }
  79. data, err := json.Marshal(dev)
  80. if err != nil {
  81. t.Fatalf("Marshal() returned error: %v", err)
  82. }
  83. var got map[string]any
  84. if err := json.Unmarshal(data, &got); err != nil {
  85. t.Fatalf("Unmarshal() returned error: %v", err)
  86. }
  87. for _, field := range []string{"index", "path", "vendorId", "productId", "name"} {
  88. if _, ok := got[field]; !ok {
  89. t.Errorf("Device JSON = %s, missing field %q", data, field)
  90. }
  91. }
  92. // The field "known" used to say whether a data file listed the board. It is gone:
  93. // whether this tool has effect names for a board is reported by the info
  94. // command, which can look, instead of by a file that can go stale.
  95. if _, ok := got["known"]; ok {
  96. t.Errorf("Device JSON = %s, must not contain the removed field \"known\"", data)
  97. }
  98. if _, ok := got["supported"]; ok {
  99. t.Errorf("Device JSON = %s, must not contain the misleading field \"supported\"", data)
  100. }
  101. }
  102. // A keyboard that reports no USB product string has no name, and the field is
  103. // omitted rather than sent empty: a consumer can tell "no name" from a name.
  104. func TestDeviceJSONOmitsUnnamedName(t *testing.T) {
  105. data, err := json.Marshal(Device{Index: 2, Path: "/dev/hidraw9"})
  106. if err != nil {
  107. t.Fatalf("Marshal() returned error: %v", err)
  108. }
  109. if strings.Contains(string(data), `"name"`) {
  110. t.Errorf("Device JSON = %s, want the name omitted for a keyboard that reports none", data)
  111. }
  112. }
  113. // The name is the keyboard's own, from the USB product string, so a data file
  114. // cannot go stale and disagree with the hardware.
  115. func TestDeviceTakesTheNameFromTheProductString(t *testing.T) {
  116. d := Device{Index: 1, Path: "p", VendorID: 0x36B0, ProductID: 0x309F, Name: "Impact 80"}
  117. if d.Name != "Impact 80" {
  118. t.Errorf("Name = %q, want the product string the keyboard reports", d.Name)
  119. }
  120. }