|
@@ -0,0 +1,168 @@
|
|
|
|
|
+package main
|
|
|
|
|
+
|
|
|
|
|
+import (
|
|
|
|
|
+ "bytes"
|
|
|
|
|
+ "errors"
|
|
|
|
|
+ "strings"
|
|
|
|
|
+ "testing"
|
|
|
|
|
+
|
|
|
|
|
+ intrgb "netdome.biz/paul/impact-80/internal/rgb"
|
|
|
|
|
+ "netdome.biz/paul/impact-80/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.LEDType]uint8
|
|
|
|
|
+ getErr error
|
|
|
|
|
+ getCalls int
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (f *verifyingProtocol) SetValue(channel via.LEDType, param, value uint8) error {
|
|
|
|
|
+ f.reports = append(f.reports, commandReport{channel: channel, param: param, value: value})
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (f *verifyingProtocol) SetColor(via.LEDType, uint8, uint8) error { return nil }
|
|
|
|
|
+
|
|
|
|
|
+func (f *verifyingProtocol) GetValue(channel via.LEDType, _ 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.LEDType) 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.LEDType]uint8{
|
|
|
|
|
+ via.RGBLight: tt.applied,
|
|
|
|
|
+ via.RGBMatrix: tt.applied,
|
|
|
|
|
+ via.SideLight: tt.applied,
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ zones := []intrgb.Zone{intrgb.ZoneLogo}
|
|
|
|
|
+ results, err := setBrightnessVerified(proto, zones, 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.Zone != intrgb.ZoneLogo {
|
|
|
|
|
+ t.Errorf("results[0].Zone = %q, want %q", got.Zone, intrgb.ZoneLogo)
|
|
|
|
|
+ }
|
|
|
|
|
+ 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.LEDType]uint8{
|
|
|
|
|
+ via.RGBLight: 160,
|
|
|
|
|
+ via.RGBMatrix: 255,
|
|
|
|
|
+ via.SideLight: 160,
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ results, err := setBrightnessVerified(proto, intrgb.AllZones(), 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.RGBLight); got != 160 {
|
|
|
|
|
+ t.Errorf("unexpected applied value %d", got)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ want := map[intrgb.Zone]uint8{
|
|
|
|
|
+ intrgb.ZoneLogo: 160,
|
|
|
|
|
+ intrgb.ZoneBacklight: 255,
|
|
|
|
|
+ intrgb.ZoneSide: 160,
|
|
|
|
|
+ }
|
|
|
|
|
+ for _, r := range results {
|
|
|
|
|
+ if r.Applied != want[r.Zone] {
|
|
|
|
|
+ t.Errorf("%s applied = %d, want %d", r.Zone, r.Applied, want[r.Zone])
|
|
|
|
|
+ }
|
|
|
|
|
+ if !r.Mismatch() {
|
|
|
|
|
+ t.Errorf("%s: Mismatch() = false, want true (requested 200)", r.Zone)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 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, []intrgb.Zone{intrgb.ZoneLogo}, 100); err == nil {
|
|
|
|
|
+ t.Fatal("setBrightnessVerified() expected read error, got nil")
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func TestBrightnessCommandStaysQuietWhenApplied(t *testing.T) {
|
|
|
|
|
+ proto := &verifyingProtocol{applied: map[via.LEDType]uint8{via.RGBLight: 200}}
|
|
|
|
|
+
|
|
|
|
|
+ originalOpen := openRGBProtocol
|
|
|
|
|
+ originalZone := targetZone
|
|
|
|
|
+ t.Cleanup(func() {
|
|
|
|
|
+ openRGBProtocol = originalOpen
|
|
|
|
|
+ targetZone = originalZone
|
|
|
|
|
+ })
|
|
|
|
|
+ openRGBProtocol = func() (rgbProtocol, error) { return proto, nil }
|
|
|
|
|
+ targetZone = "logo"
|
|
|
|
|
+
|
|
|
|
|
+ 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())
|
|
|
|
|
+ }
|
|
|
|
|
+}
|