| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- package main
- import (
- "bytes"
- "errors"
- "strings"
- "testing"
- "netdome.biz/paul/qmk-rgb/internal/via"
- )
- // verifyingProtocol records writes and reports what the keyboard actually
- // applied, which on real hardware is not always the requested value.
- type verifyingProtocol struct {
- reports []commandReport
- applied map[via.Channel]uint8
- channels []via.Channel
- getErr error
- getCalls int
- }
- // impact80Display is the channel naming the Impact 80's keyboards.json entry
- // supplies, so summary lines name logo, backlight and side.
- func impact80Display() map[uint16]string {
- return map[uint16]string{2: "logo", 3: "backlight", 4: "side"}
- }
- func impact80Channels() []via.Channel {
- return []via.Channel{via.ChannelRgblight, via.ChannelRgbMatrix, via.ChannelAudio}
- }
- // DetectChannels reports the three channels of the board under test unless a
- // test asks for a different set.
- func (f *verifyingProtocol) DetectChannels() ([]via.Channel, error) {
- if f.channels == nil {
- return []via.Channel{via.ChannelRgblight, via.ChannelRgbMatrix, via.ChannelAudio}, nil
- }
- return f.channels, nil
- }
- func (f *verifyingProtocol) SetValue(channel via.Channel, param, value uint8) error {
- f.reports = append(f.reports, commandReport{channel: channel, param: param, value: value})
- return nil
- }
- func (f *verifyingProtocol) SetColor(via.Channel, uint8, uint8) error { return nil }
- func (f *verifyingProtocol) GetValue(channel via.Channel, _ uint8) ([]byte, error) {
- f.getCalls++
- if f.getErr != nil {
- return nil, f.getErr
- }
- return []byte{f.applied[channel]}, nil
- }
- func (f *verifyingProtocol) Close() error { return nil }
- func appliedFor(p *verifyingProtocol, channel via.Channel) uint8 { return p.applied[channel] }
- func TestSetBrightnessVerifiedReportsAppliedValue(t *testing.T) {
- tests := []struct {
- name string
- requested uint8
- applied uint8
- wantWarning bool
- }{
- {"keyboard honours the value", 100, 100, false},
- {"keyboard clamps to 160", 200, 160, true},
- {"keyboard scales up", 100, 159, true},
- {"both zones clamp", 255, 160, true},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- proto := &verifyingProtocol{
- applied: map[via.Channel]uint8{
- via.ChannelRgblight: tt.applied,
- via.ChannelRgbMatrix: tt.applied,
- via.ChannelAudio: tt.applied,
- },
- }
- zones := []via.Channel{via.ChannelRgblight}
- results, err := setBrightnessVerified(proto, zones, impact80Display(), tt.requested)
- if err != nil {
- t.Fatalf("setBrightnessVerified() error = %v", err)
- }
- if len(results) != 1 {
- t.Fatalf("results = %d entries, want 1", len(results))
- }
- got := results[0]
- if got.Name != "logo" {
- t.Errorf("results[0].Name = %q, want %q", got.Name, "logo")
- }
- if got.Requested != tt.requested {
- t.Errorf("results[0].Requested = %d, want %d", got.Requested, tt.requested)
- }
- if got.Applied != tt.applied {
- t.Errorf("results[0].Applied = %d, want %d", got.Applied, tt.applied)
- }
- if got.Mismatch() != tt.wantWarning {
- t.Errorf("results[0].Mismatch() = %t, want %t", got.Mismatch(), tt.wantWarning)
- }
- })
- }
- }
- // The read-back must happen once per written zone, on the right channel.
- func TestSetBrightnessVerifiedReadsBackEveryZone(t *testing.T) {
- proto := &verifyingProtocol{
- applied: map[via.Channel]uint8{
- via.ChannelRgblight: 160,
- via.ChannelRgbMatrix: 255,
- via.ChannelAudio: 160,
- },
- }
- results, err := setBrightnessVerified(proto, impact80Channels(), impact80Display(), 200)
- if err != nil {
- t.Fatalf("setBrightnessVerified() error = %v", err)
- }
- if len(results) != 3 {
- t.Fatalf("results = %d entries, want 3", len(results))
- }
- if proto.getCalls != 3 {
- t.Errorf("GetValue calls = %d, want 3", proto.getCalls)
- }
- // A set that fails must not be reported as applied.
- if got := appliedFor(proto, via.ChannelRgblight); got != 160 {
- t.Errorf("unexpected applied value %d", got)
- }
- want := map[string]uint8{
- "logo": 160,
- "backlight": 255,
- "side": 160,
- }
- for _, r := range results {
- if r.Applied != want[r.Name] {
- t.Errorf("%s applied = %d, want %d", r.Name, r.Applied, want[r.Name])
- }
- if !r.Mismatch() {
- t.Errorf("%s: Mismatch() = false, want true (requested 200)", r.Name)
- }
- }
- }
- // A failed read-back must not be silently reported as success.
- func TestSetBrightnessVerifiedPropagatesReadError(t *testing.T) {
- proto := &verifyingProtocol{getErr: errors.New("read timeout")}
- if _, err := setBrightnessVerified(proto, []via.Channel{via.ChannelRgblight}, impact80Display(), 100); err == nil {
- t.Fatal("setBrightnessVerified() expected read error, got nil")
- }
- }
- func TestBrightnessCommandStaysQuietWhenApplied(t *testing.T) {
- proto := &verifyingProtocol{applied: map[via.Channel]uint8{via.ChannelRgblight: 200}}
- t.Cleanup(impact80Target(t, proto))
- var out, errOut bytes.Buffer
- cmd := NewBrightnessCmd()
- cmd.SetOut(&out)
- cmd.SetErr(&errOut)
- cmd.SetArgs([]string{"200"})
- if err := cmd.Execute(); err != nil {
- t.Fatalf("brightness returned error: %v", err)
- }
- if errOut.Len() != 0 {
- t.Errorf("stderr = %q, want no warning when the keyboard applied the requested value", errOut.String())
- }
- if !strings.Contains(out.String(), "200") {
- t.Errorf("stdout = %q, want the applied value reported", out.String())
- }
- }
|