| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- package rgb
- import (
- "strings"
- "testing"
- )
- // The color notation is documented in README.md: a bare or rgb:-prefixed hex
- // value, and hsv:<h>,<s>,<v> in the firmware's own 0-255 units. Only the HSV
- // form carries a value component, and it is not a color component: the keyboard
- // has no value register, so the caller must be able to tell "no value given"
- // from "value 255".
- func TestParseColorSpec(t *testing.T) {
- tests := []struct {
- name string
- spec string
- want HSV
- // hasValue is false for the hex forms: nothing in the notation asks
- // for a brightness, so the caller must not write one.
- hasValue bool
- }{
- {"bare hex red", "ff0000", HSV{H: 0, S: 255}, false},
- {"bare hex green", "00ff00", HSV{H: 85, S: 255}, false},
- {"bare hex gray", "d0d0d0", HSV{H: 0, S: 0}, false},
- {"bare hex black", "000000", HSV{H: 0, S: 0}, false},
- {"bare hex white", "ffffff", HSV{H: 0, S: 0}, false},
- {"rgb prefixed", "rgb:00ff00", HSV{H: 85, S: 255}, false},
- {"rgb prefixed red", "rgb:ff0000", HSV{H: 0, S: 255}, false},
- {"hsv full", "hsv:0,255,255", HSV{H: 0, S: 255, V: 255}, true},
- {"hsv partial brightness", "hsv:85,255,128", HSV{H: 85, S: 255, V: 128}, true},
- {"hsv zero value", "hsv:85,255,0", HSV{H: 85, S: 255, V: 0}, true},
- {"hsv zero saturation", "hsv:120,0,200", HSV{H: 120, S: 0, V: 200}, true},
- {"hsv hue 254", "hsv:254,255,255", HSV{H: 254, S: 255, V: 255}, true},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got, err := ParseColorSpec(tt.spec)
- if err != nil {
- t.Fatalf("ParseColorSpec(%q) unexpected error: %v", tt.spec, err)
- }
- // Compare the components the notation can carry. V is only
- // meaningful together with HasValue, so it is checked here
- // rather than through struct equality.
- if got.H != tt.want.H || got.S != tt.want.S || got.V != tt.want.V {
- t.Errorf("ParseColorSpec(%q) = hue %d sat %d value %d, want hue %d sat %d value %d",
- tt.spec, got.H, got.S, got.V, tt.want.H, tt.want.S, tt.want.V)
- }
- if got.HasValue() != tt.hasValue {
- t.Errorf("ParseColorSpec(%q).HasValue() = %t, want %t", tt.spec, got.HasValue(), tt.hasValue)
- }
- })
- }
- }
- func TestParseColorSpecRejectsInvalidInput(t *testing.T) {
- tests := []struct {
- name string
- spec string
- want string
- }{
- {"unknown prefix", "xyz:ff0000", "unknown color notation"},
- {"hsv with two components", "hsv:0,255", "want hsv:<h>,<s>,<v>"},
- {"hsv with four components", "hsv:0,255,255,255", "want hsv:<h>,<s>,<v>"},
- {"hsv without components", "hsv:", "want hsv:<h>,<s>,<v>"},
- {"hsv bare", "hsv", "unknown color notation"},
- {"hsv component above range", "hsv:0,256,255", "invalid hsv component"},
- {"hsv negative component", "hsv:-1,255,255", "invalid hsv component"},
- {"hsv non numeric component", "hsv:0,ff,255", "invalid hsv component"},
- {"hsv empty component", "hsv:0,,255", "invalid hsv component"},
- {"hex too short", "ff00", "invalid hex color"},
- {"hex with hash", "#ff0000", "invalid hex color"},
- {"empty", "", "invalid hex color"},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- _, err := ParseColorSpec(tt.spec)
- if err == nil {
- t.Fatalf("ParseColorSpec(%q) expected error, got nil", tt.spec)
- }
- if !strings.Contains(err.Error(), tt.want) {
- t.Errorf("ParseColorSpec(%q) error = %q, want it to contain %q", tt.spec, err, tt.want)
- }
- })
- }
- }
- // The error message is the only place a caller learns which notations exist, so
- // it has to name them.
- func TestUnknownNotationErrorNamesTheThreeForms(t *testing.T) {
- _, err := ParseColorSpec("nope:1")
- if err == nil {
- t.Fatal("ParseColorSpec(\"nope:1\") expected error, got nil")
- }
- for _, form := range []string{"ff0000", "rgb:", "hsv:"} {
- if !strings.Contains(err.Error(), form) {
- t.Errorf("error %q does not mention the %q form", err, form)
- }
- }
- }
|