brightness_verify_test.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package main
  2. import (
  3. "bytes"
  4. "errors"
  5. "strings"
  6. "testing"
  7. intrgb "netdome.biz/paul/qmk-rgb/internal/rgb"
  8. "netdome.biz/paul/qmk-rgb/internal/via"
  9. )
  10. // verifyingProtocol records writes and reports what the keyboard actually
  11. // applied, which on real hardware is not always the requested value.
  12. type verifyingProtocol struct {
  13. reports []commandReport
  14. applied map[via.LEDType]uint8
  15. getErr error
  16. getCalls int
  17. }
  18. func (f *verifyingProtocol) SetValue(channel via.LEDType, param, value uint8) error {
  19. f.reports = append(f.reports, commandReport{channel: channel, param: param, value: value})
  20. return nil
  21. }
  22. func (f *verifyingProtocol) SetColor(via.LEDType, uint8, uint8) error { return nil }
  23. func (f *verifyingProtocol) GetValue(channel via.LEDType, _ uint8) ([]byte, error) {
  24. f.getCalls++
  25. if f.getErr != nil {
  26. return nil, f.getErr
  27. }
  28. return []byte{f.applied[channel]}, nil
  29. }
  30. func (f *verifyingProtocol) Close() error { return nil }
  31. func appliedFor(p *verifyingProtocol, channel via.LEDType) uint8 { return p.applied[channel] }
  32. func TestSetBrightnessVerifiedReportsAppliedValue(t *testing.T) {
  33. tests := []struct {
  34. name string
  35. requested uint8
  36. applied uint8
  37. wantWarning bool
  38. }{
  39. {"keyboard honours the value", 100, 100, false},
  40. {"keyboard clamps to 160", 200, 160, true},
  41. {"keyboard scales up", 100, 159, true},
  42. {"both zones clamp", 255, 160, true},
  43. }
  44. for _, tt := range tests {
  45. t.Run(tt.name, func(t *testing.T) {
  46. proto := &verifyingProtocol{
  47. applied: map[via.LEDType]uint8{
  48. via.RGBLight: tt.applied,
  49. via.RGBMatrix: tt.applied,
  50. via.SideLight: tt.applied,
  51. },
  52. }
  53. zones := []intrgb.Zone{intrgb.ZoneLogo}
  54. results, err := setBrightnessVerified(proto, zones, tt.requested)
  55. if err != nil {
  56. t.Fatalf("setBrightnessVerified() error = %v", err)
  57. }
  58. if len(results) != 1 {
  59. t.Fatalf("results = %d entries, want 1", len(results))
  60. }
  61. got := results[0]
  62. if got.Zone != intrgb.ZoneLogo {
  63. t.Errorf("results[0].Zone = %q, want %q", got.Zone, intrgb.ZoneLogo)
  64. }
  65. if got.Requested != tt.requested {
  66. t.Errorf("results[0].Requested = %d, want %d", got.Requested, tt.requested)
  67. }
  68. if got.Applied != tt.applied {
  69. t.Errorf("results[0].Applied = %d, want %d", got.Applied, tt.applied)
  70. }
  71. if got.Mismatch() != tt.wantWarning {
  72. t.Errorf("results[0].Mismatch() = %t, want %t", got.Mismatch(), tt.wantWarning)
  73. }
  74. })
  75. }
  76. }
  77. // The read-back must happen once per written zone, on the right channel.
  78. func TestSetBrightnessVerifiedReadsBackEveryZone(t *testing.T) {
  79. proto := &verifyingProtocol{
  80. applied: map[via.LEDType]uint8{
  81. via.RGBLight: 160,
  82. via.RGBMatrix: 255,
  83. via.SideLight: 160,
  84. },
  85. }
  86. results, err := setBrightnessVerified(proto, intrgb.AllZones(), 200)
  87. if err != nil {
  88. t.Fatalf("setBrightnessVerified() error = %v", err)
  89. }
  90. if len(results) != 3 {
  91. t.Fatalf("results = %d entries, want 3", len(results))
  92. }
  93. if proto.getCalls != 3 {
  94. t.Errorf("GetValue calls = %d, want 3", proto.getCalls)
  95. }
  96. // A set that fails must not be reported as applied.
  97. if got := appliedFor(proto, via.RGBLight); got != 160 {
  98. t.Errorf("unexpected applied value %d", got)
  99. }
  100. want := map[intrgb.Zone]uint8{
  101. intrgb.ZoneLogo: 160,
  102. intrgb.ZoneBacklight: 255,
  103. intrgb.ZoneSide: 160,
  104. }
  105. for _, r := range results {
  106. if r.Applied != want[r.Zone] {
  107. t.Errorf("%s applied = %d, want %d", r.Zone, r.Applied, want[r.Zone])
  108. }
  109. if !r.Mismatch() {
  110. t.Errorf("%s: Mismatch() = false, want true (requested 200)", r.Zone)
  111. }
  112. }
  113. }
  114. // A failed read-back must not be silently reported as success.
  115. func TestSetBrightnessVerifiedPropagatesReadError(t *testing.T) {
  116. proto := &verifyingProtocol{getErr: errors.New("read timeout")}
  117. if _, err := setBrightnessVerified(proto, []intrgb.Zone{intrgb.ZoneLogo}, 100); err == nil {
  118. t.Fatal("setBrightnessVerified() expected read error, got nil")
  119. }
  120. }
  121. func TestBrightnessCommandStaysQuietWhenApplied(t *testing.T) {
  122. proto := &verifyingProtocol{applied: map[via.LEDType]uint8{via.RGBLight: 200}}
  123. originalOpen := openRGBProtocol
  124. originalZone := targetZone
  125. t.Cleanup(func() {
  126. openRGBProtocol = originalOpen
  127. targetZone = originalZone
  128. })
  129. openRGBProtocol = func() (rgbProtocol, error) { return proto, nil }
  130. targetZone = "logo"
  131. var out, errOut bytes.Buffer
  132. cmd := NewBrightnessCmd()
  133. cmd.SetOut(&out)
  134. cmd.SetErr(&errOut)
  135. cmd.SetArgs([]string{"200"})
  136. if err := cmd.Execute(); err != nil {
  137. t.Fatalf("brightness returned error: %v", err)
  138. }
  139. if errOut.Len() != 0 {
  140. t.Errorf("stderr = %q, want no warning when the keyboard applied the requested value", errOut.String())
  141. }
  142. if !strings.Contains(out.String(), "200") {
  143. t.Errorf("stdout = %q, want the applied value reported", out.String())
  144. }
  145. }