package rgb import ( "errors" "reflect" "testing" intrgb "github.com/wobkey/rgb/internal/rgb" "github.com/wobkey/rgb/internal/via" ) type commandReport struct { channel via.LEDType param uint8 value uint8 hue uint8 saturation uint8 } type fakeZoneProtocol struct { reports []commandReport failAt int } func (f *fakeZoneProtocol) SetValue(channel via.LEDType, 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.LEDType, 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 } func TestSelectedChannelOperations(t *testing.T) { defaultZones := []intrgb.Zone{intrgb.ZoneLogo, intrgb.ZoneBacklight, intrgb.ZoneSide} sideZones := []intrgb.Zone{intrgb.ZoneSide} operations := []struct { name string zones []intrgb.Zone sideZones []intrgb.Zone run func(zoneProtocol, []intrgb.Zone) error want []commandReport wantSide []commandReport }{ { name: "brightness", zones: defaultZones, sideZones: sideZones, run: func(protocol zoneProtocol, zones []intrgb.Zone) error { return setBrightnessOnZones(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 []intrgb.Zone) error { return setSpeedOnZones(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 []intrgb.Zone) error { return setColorOnZones(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: disableLightingOnZones, 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: enableLightingOnZones, want: []commandReport{ {channel: 2, param: 2, value: 4}, {channel: 2, param: 1, value: 160}, {channel: 3, param: 2, value: 5}, {channel: 3, param: 1, value: 160}, {channel: 4, param: 2, value: 4}, {channel: 4, param: 1, value: 160}, }, wantSide: []commandReport{ {channel: 4, param: 2, value: 4}, {channel: 4, param: 1, value: 160}, }, }, { name: "mode", zones: defaultZones, sideZones: sideZones, run: func(protocol zoneProtocol, zones []intrgb.Zone) error { return setModeOnZones(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 := setBrightnessOnZones(protocol, intrgb.AllZones(), 160) if err == nil { t.Fatal("setBrightnessOnZones() expected error, got nil") } if len(protocol.reports) != 1 { t.Errorf("reports = %v, want one report before failure", protocol.reports) } }