package via import ( "errors" "strings" "testing" ) // probeQueue scripts one answer per channel the probe visits, so a test can say // which channels the keyboard has. func probeQueue(present ...Channel) [][]byte { queue := make([][]byte, 0, probeChannelMax) for c := 1; c <= probeChannelMax; c++ { buf := make([]byte, 32) if containsChannel(present, Channel(c)) { buf[0] = byte(CustomGet) buf[3] = 160 } else { buf[0] = byte(Unhandled) } buf[1] = byte(c) buf[2] = probeValueID queue = append(queue, buf) } return queue } func containsChannel(channels []Channel, want Channel) bool { for _, c := range channels { if c == want { return true } } return false } func TestDetectChannelsFindsTheAnsweredChannels(t *testing.T) { transport := &fakeTransport{queue: probeQueue(ChannelRgblight, ChannelRgbMatrix, ChannelAudio)} protocol := Protocol{handle: transport} got, err := protocol.DetectChannels() if err != nil { t.Fatalf("DetectChannels() error = %v", err) } want := []Channel{ChannelRgblight, ChannelRgbMatrix, ChannelAudio} if len(got) != len(want) { t.Fatalf("DetectChannels() = %v, want %v", got, want) } for i := range want { if got[i] != want[i] { t.Errorf("DetectChannels()[%d] = %d, want %d", i, got[i], want[i]) } } } func TestDetectChannelsAsksBrightnessOnEveryChannelFromOneToFifteen(t *testing.T) { transport := &fakeTransport{queue: probeQueue()} protocol := Protocol{handle: transport} if _, err := protocol.DetectChannels(); err != nil { t.Fatalf("DetectChannels() error = %v", err) } if len(transport.reports) != probeChannelMax { t.Fatalf("requests = %d, want %d", len(transport.reports), probeChannelMax) } for i, report := range transport.reports { wantChannel := byte(i + 1) if report[0] != byte(CustomGet) { t.Errorf("request %d command = 0x%02x, want 0x%02x", i, report[0], CustomGet) } if report[1] != wantChannel { t.Errorf("request %d channel = %d, want %d", i, report[1], wantChannel) } if report[2] != probeValueID { t.Errorf("request %d value = 0x%02x, want 0x%02x (brightness)", i, report[2], probeValueID) } } } // A channel list missing entries is indistinguishable from a complete one, so a // transport failure has to abort the probe instead of shrinking it. func TestDetectChannelsFailsOnATransportErrorMidProbe(t *testing.T) { transport := &fakeTransport{ queue: probeQueue(ChannelRgblight, ChannelRgbMatrix, ChannelAudio), readErr: errors.New("read: interrupted system call"), readErrAfter: 3, } protocol := Protocol{handle: transport} _, err := protocol.DetectChannels() if err == nil { t.Fatal("DetectChannels() expected an error, got nil") } if !strings.Contains(err.Error(), "channel 4") { t.Errorf("error = %q, want it to name the channel that failed", err) } } func TestDetectChannelsReportsNoChannelsWhenNoneArePresent(t *testing.T) { transport := &fakeTransport{queue: probeQueue()} protocol := Protocol{handle: transport} got, err := protocol.DetectChannels() if err != nil { t.Fatalf("DetectChannels() error = %v", err) } if len(got) != 0 { t.Errorf("DetectChannels() = %v, want empty", got) } } func TestChannelSubsystemNames(t *testing.T) { tests := []struct { channel Channel want string }{ {ChannelBacklight, "backlight"}, {ChannelRgblight, "rgblight"}, {ChannelRgbMatrix, "rgb_matrix"}, {ChannelAudio, "audio"}, {ChannelLedMatrix, "led_matrix"}, {Channel(9), ""}, } for _, tt := range tests { if got := tt.channel.Subsystem(); got != tt.want { t.Errorf("Channel(%d).Subsystem() = %q, want %q", tt.channel, got, tt.want) } } }