package main import ( "errors" "strings" "testing" intrgb "netdome.biz/paul/qmk-rgb/internal/rgb" "netdome.biz/paul/qmk-rgb/internal/via" ) // A raw index above what the board implements is not refused: the Impact 80 // clamps it to the highest ID it holds, so the command would report an index the // keyboard never took. mode is the escape hatch for a board without a catalog, // which is exactly where an unverified success would hurt most. func TestModeCommandReportsClampedIndex(t *testing.T) { proto := &verifyingProtocol{applied: map[via.Channel]uint8{via.ChannelRgbMatrix: 46}} t.Cleanup(impact80Target(t, proto)) var out, errOut strings.Builder cmd := NewModeCmd() cmd.SetOut(&out) cmd.SetErr(&errOut) cmd.SetArgs([]string{"99"}) if err := cmd.Execute(); err != nil { t.Fatalf("mode returned error: %v", err) } stdout := out.String() if strings.Contains(stdout, "Mode set to index 99") { t.Errorf("stdout = %q, want no success claim for an index the keyboard clamped", stdout) } for _, want := range []string{"backlight", "46", "99"} { if !strings.Contains(stdout, want) { t.Errorf("stdout = %q, want it to name %q", stdout, want) } } } // An index the board takes must stay a plain success line, so the summary is // reserved for a real divergence. func TestModeCommandStaysQuietWhenApplied(t *testing.T) { proto := &verifyingProtocol{ applied: map[via.Channel]uint8{ via.ChannelRgblight: 5, via.ChannelRgbMatrix: 20, via.ChannelAudio: 5, }, } t.Cleanup(impact80Target(t, proto)) var out, errOut strings.Builder cmd := NewModeCmd() cmd.SetOut(&out) cmd.SetErr(&errOut) cmd.SetArgs([]string{"5"}) if err := cmd.Execute(); err != nil { t.Fatalf("mode returned error: %v", err) } // Only the backlight stores 20, so two of three zones deviate and the // summary is expected; a silent run would mean the read-back is skipped. if out.Len() == 0 { t.Error("stdout = \"\", want a divergence summary") } } func TestSetModeVerifiedPropagatesReadError(t *testing.T) { proto := &verifyingProtocol{getErr: errors.New("read timeout")} _, err := setModeVerified(proto, []via.Channel{via.ChannelRgbMatrix}, impact80Display(), 46) if err == nil { t.Fatal("setModeVerified() expected read error, got nil") } } // The mode command writes the effect value ID, the same one effect writes. func TestSetModeVerifiedUsesTheEffectValueID(t *testing.T) { proto := &verifyingProtocol{applied: map[via.Channel]uint8{via.ChannelRgbMatrix: 46}} if _, err := setModeVerified(proto, []via.Channel{via.ChannelRgbMatrix}, impact80Display(), 46); err != nil { t.Fatalf("setModeVerified() error = %v", err) } if len(proto.reports) != 1 { t.Fatalf("reports = %d, want 1", len(proto.reports)) } if got := proto.reports[0].param; got != uint8(intrgb.EffectID) { t.Errorf("param = 0x%02x, want 0x%02x", got, uint8(intrgb.EffectID)) } }