| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- package main
- import (
- "errors"
- "reflect"
- "testing"
- "netdome.biz/paul/qmk-rgb/internal/via"
- )
- type commandReport struct {
- channel via.Channel
- param uint8
- value uint8
- hue uint8
- saturation uint8
- }
- type fakeZoneProtocol struct {
- reports []commandReport
- failAt int
- channels []via.Channel
- }
- // DetectChannels reports the board's three channels unless a test asks for a
- // different set.
- func (f *fakeZoneProtocol) DetectChannels() ([]via.Channel, error) {
- if f.channels == nil {
- return impact80Channels(), nil
- }
- return f.channels, nil
- }
- func (f *fakeZoneProtocol) SetValue(channel via.Channel, param, value uint8) error {
- if f.failAt >= 0 && f.failAt == len(f.reports) {
- return errors.New("write failed")
- }
- f.reports = append(f.reports, commandReport{
- channel: channel,
- param: param,
- value: value,
- })
- return nil
- }
- func (f *fakeZoneProtocol) SetColor(channel via.Channel, hue, saturation uint8) error {
- if f.failAt >= 0 && f.failAt == len(f.reports) {
- return errors.New("write failed")
- }
- f.reports = append(f.reports, commandReport{
- channel: channel,
- param: 4,
- hue: hue,
- saturation: saturation,
- })
- return nil
- }
- // GetValue reports the last value written to a channel, so a command that reads
- // back what it set sees a keyboard that accepted it. A channel that was never
- // written to still fails, so a read-back without a preceding set stays visible.
- func (f *fakeZoneProtocol) GetValue(channel via.Channel, param uint8) ([]byte, error) {
- for i := len(f.reports) - 1; i >= 0; i-- {
- if f.reports[i].channel == channel && f.reports[i].param == param {
- return []byte{f.reports[i].value}, nil
- }
- }
- return nil, errors.New("unexpected GetValue call")
- }
- func (f *fakeZoneProtocol) Close() error {
- return nil
- }
- func TestSelectedChannelOperations(t *testing.T) {
- defaultZones := []via.Channel{via.ChannelRgblight, via.ChannelRgbMatrix, via.ChannelAudio}
- sideZones := []via.Channel{via.ChannelAudio}
- operations := []struct {
- name string
- zones []via.Channel
- sideZones []via.Channel
- run func(zoneProtocol, []via.Channel) error
- want []commandReport
- wantSide []commandReport
- }{
- {
- name: "brightness",
- zones: defaultZones,
- sideZones: sideZones,
- run: func(protocol zoneProtocol, zones []via.Channel) error {
- return setBrightnessOnChannels(protocol, zones, 160)
- },
- want: []commandReport{
- {channel: 2, param: 1, value: 160},
- {channel: 3, param: 1, value: 160},
- {channel: 4, param: 1, value: 160},
- },
- wantSide: []commandReport{{channel: 4, param: 1, value: 160}},
- },
- {
- name: "speed",
- zones: defaultZones,
- sideZones: sideZones,
- run: func(protocol zoneProtocol, zones []via.Channel) error {
- return setSpeedChannels(protocol, zones, 2)
- },
- want: []commandReport{
- {channel: 2, param: 3, value: 2},
- {channel: 3, param: 3, value: 2},
- {channel: 4, param: 3, value: 2},
- },
- wantSide: []commandReport{{channel: 4, param: 3, value: 2}},
- },
- {
- name: "color",
- zones: defaultZones,
- sideZones: sideZones,
- run: func(protocol zoneProtocol, zones []via.Channel) error {
- return setColorOnChannels(protocol, zones, 85, 255)
- },
- want: []commandReport{
- {channel: 2, param: 4, hue: 85, saturation: 255},
- {channel: 3, param: 4, hue: 85, saturation: 255},
- {channel: 4, param: 4, hue: 85, saturation: 255},
- },
- wantSide: []commandReport{{channel: 4, param: 4, hue: 85, saturation: 255}},
- },
- {
- name: "disable",
- zones: defaultZones,
- sideZones: sideZones,
- run: disableLightingOnChannels,
- want: []commandReport{
- {channel: 2, param: 2, value: 0},
- {channel: 2, param: 1, value: 0},
- {channel: 3, param: 2, value: 0},
- {channel: 3, param: 1, value: 0},
- {channel: 4, param: 2, value: 0},
- {channel: 4, param: 1, value: 0},
- },
- wantSide: []commandReport{
- {channel: 4, param: 2, value: 0},
- {channel: 4, param: 1, value: 0},
- },
- },
- {
- name: "enable",
- zones: defaultZones,
- sideZones: sideZones,
- run: func(protocol zoneProtocol, channels []via.Channel) error {
- return enableLightingOnChannels(protocol, channels, impact80Catalog(t))
- },
- // enable writes the first effect each channel's own list names, which
- // is wave on logo and side and solid_color on the backlight.
- want: []commandReport{
- {channel: 2, param: 2, value: 1},
- {channel: 2, param: 1, value: 160},
- {channel: 3, param: 2, value: 1},
- {channel: 3, param: 1, value: 160},
- {channel: 4, param: 2, value: 1},
- {channel: 4, param: 1, value: 160},
- },
- wantSide: []commandReport{
- {channel: 4, param: 2, value: 1},
- {channel: 4, param: 1, value: 160},
- },
- },
- {
- name: "mode",
- zones: defaultZones,
- sideZones: sideZones,
- run: func(protocol zoneProtocol, zones []via.Channel) error {
- return setModeOnChannels(protocol, zones, 17)
- },
- want: []commandReport{
- {channel: 2, param: 2, value: 17},
- {channel: 3, param: 2, value: 17},
- {channel: 4, param: 2, value: 17},
- },
- wantSide: []commandReport{{channel: 4, param: 2, value: 17}},
- },
- }
- for _, tc := range operations {
- t.Run(tc.name+"/default", func(t *testing.T) {
- protocol := &fakeZoneProtocol{failAt: -1}
- if err := tc.run(protocol, tc.zones); err != nil {
- t.Fatalf("operation error = %v", err)
- }
- if !reflect.DeepEqual(protocol.reports, tc.want) {
- t.Errorf("reports = %v, want %v", protocol.reports, tc.want)
- }
- })
- t.Run(tc.name+"/side", func(t *testing.T) {
- protocol := &fakeZoneProtocol{failAt: -1}
- if err := tc.run(protocol, tc.sideZones); err != nil {
- t.Fatalf("operation error = %v", err)
- }
- if !reflect.DeepEqual(protocol.reports, tc.wantSide) {
- t.Errorf("reports = %v, want %v", protocol.reports, tc.wantSide)
- }
- })
- }
- }
- func TestSelectedChannelStopsOnFirstError(t *testing.T) {
- protocol := &fakeZoneProtocol{failAt: 1}
- err := setBrightnessOnChannels(protocol, impact80Channels(), 160)
- if err == nil {
- t.Fatal("setBrightnessOnChannels() expected error, got nil")
- }
- if len(protocol.reports) != 1 {
- t.Errorf("reports = %v, want one report before failure", protocol.reports)
- }
- }
- // README.md promises the commands that take no arguments reject a stray token.
- // keyboard info declared none, so cobra accepted any number of them.
- func TestKeyboardInfoRejectsAStrayToken(t *testing.T) {
- if keyboardInfoCmd.Args == nil {
- t.Fatal("keyboard info declares no Args, so a stray token is accepted")
- }
- if err := keyboardInfoCmd.Args(keyboardInfoCmd, []string{"bogus"}); err == nil {
- t.Error("keyboard info accepted a stray token, want it rejected")
- }
- if err := keyboardInfoCmd.Args(keyboardInfoCmd, nil); err != nil {
- t.Errorf("keyboard info rejected no token: %v", err)
- }
- }
|