colorspec_test.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. package rgb
  2. import (
  3. "strings"
  4. "testing"
  5. )
  6. // The color notation is documented in README.md: a bare or rgb:-prefixed hex
  7. // value, and hsv:<h>,<s>,<v> in the firmware's own 0-255 units. Only the HSV
  8. // form carries a value component, and it is not a color component: the keyboard
  9. // has no value register, so the caller must be able to tell "no value given"
  10. // from "value 255".
  11. func TestParseColorSpec(t *testing.T) {
  12. tests := []struct {
  13. name string
  14. spec string
  15. want HSV
  16. // hasValue is false for the hex forms: nothing in the notation asks
  17. // for a brightness, so the caller must not write one.
  18. hasValue bool
  19. }{
  20. {"bare hex red", "ff0000", HSV{H: 0, S: 255}, false},
  21. {"bare hex green", "00ff00", HSV{H: 85, S: 255}, false},
  22. {"bare hex gray", "d0d0d0", HSV{H: 0, S: 0}, false},
  23. {"bare hex black", "000000", HSV{H: 0, S: 0}, false},
  24. {"bare hex white", "ffffff", HSV{H: 0, S: 0}, false},
  25. {"rgb prefixed", "rgb:00ff00", HSV{H: 85, S: 255}, false},
  26. {"rgb prefixed red", "rgb:ff0000", HSV{H: 0, S: 255}, false},
  27. {"hsv full", "hsv:0,255,255", HSV{H: 0, S: 255, V: 255}, true},
  28. {"hsv partial brightness", "hsv:85,255,128", HSV{H: 85, S: 255, V: 128}, true},
  29. {"hsv zero value", "hsv:85,255,0", HSV{H: 85, S: 255, V: 0}, true},
  30. {"hsv zero saturation", "hsv:120,0,200", HSV{H: 120, S: 0, V: 200}, true},
  31. {"hsv hue 254", "hsv:254,255,255", HSV{H: 254, S: 255, V: 255}, true},
  32. }
  33. for _, tt := range tests {
  34. t.Run(tt.name, func(t *testing.T) {
  35. got, err := ParseColorSpec(tt.spec)
  36. if err != nil {
  37. t.Fatalf("ParseColorSpec(%q) unexpected error: %v", tt.spec, err)
  38. }
  39. // Compare the components the notation can carry. V is only
  40. // meaningful together with HasValue, so it is checked here
  41. // rather than through struct equality.
  42. if got.H != tt.want.H || got.S != tt.want.S || got.V != tt.want.V {
  43. t.Errorf("ParseColorSpec(%q) = hue %d sat %d value %d, want hue %d sat %d value %d",
  44. tt.spec, got.H, got.S, got.V, tt.want.H, tt.want.S, tt.want.V)
  45. }
  46. if got.HasValue() != tt.hasValue {
  47. t.Errorf("ParseColorSpec(%q).HasValue() = %t, want %t", tt.spec, got.HasValue(), tt.hasValue)
  48. }
  49. })
  50. }
  51. }
  52. func TestParseColorSpecRejectsInvalidInput(t *testing.T) {
  53. tests := []struct {
  54. name string
  55. spec string
  56. want string
  57. }{
  58. {"unknown prefix", "xyz:ff0000", "unknown color notation"},
  59. {"hsv with two components", "hsv:0,255", "want hsv:<h>,<s>,<v>"},
  60. {"hsv with four components", "hsv:0,255,255,255", "want hsv:<h>,<s>,<v>"},
  61. {"hsv without components", "hsv:", "want hsv:<h>,<s>,<v>"},
  62. {"hsv bare", "hsv", "unknown color notation"},
  63. {"hsv component above range", "hsv:0,256,255", "invalid hsv component"},
  64. {"hsv negative component", "hsv:-1,255,255", "invalid hsv component"},
  65. {"hsv non numeric component", "hsv:0,ff,255", "invalid hsv component"},
  66. {"hsv empty component", "hsv:0,,255", "invalid hsv component"},
  67. {"hex too short", "ff00", "invalid hex color"},
  68. {"hex with hash", "#ff0000", "invalid hex color"},
  69. {"empty", "", "invalid hex color"},
  70. }
  71. for _, tt := range tests {
  72. t.Run(tt.name, func(t *testing.T) {
  73. _, err := ParseColorSpec(tt.spec)
  74. if err == nil {
  75. t.Fatalf("ParseColorSpec(%q) expected error, got nil", tt.spec)
  76. }
  77. if !strings.Contains(err.Error(), tt.want) {
  78. t.Errorf("ParseColorSpec(%q) error = %q, want it to contain %q", tt.spec, err, tt.want)
  79. }
  80. })
  81. }
  82. }
  83. // The error message is the only place a caller learns which notations exist, so
  84. // it has to name them.
  85. func TestUnknownNotationErrorNamesTheThreeForms(t *testing.T) {
  86. _, err := ParseColorSpec("nope:1")
  87. if err == nil {
  88. t.Fatal("ParseColorSpec(\"nope:1\") expected error, got nil")
  89. }
  90. for _, form := range []string{"ff0000", "rgb:", "hsv:"} {
  91. if !strings.Contains(err.Error(), form) {
  92. t.Errorf("error %q does not mention the %q form", err, form)
  93. }
  94. }
  95. }