| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- package main
- import (
- "strings"
- "testing"
- "github.com/spf13/cobra"
- )
- // `list` takes nothing. Without a declared arity cobra applies arbitraryArgs, so
- // a stray token yielded exit 0 and the command looked like it had done its work —
- // a caller could believe a lighting change happened when the argument was silently
- // dropped.
- func TestZeroArgCommandsRejectStrayTokens(t *testing.T) {
- cmds := map[string]*cobra.Command{
- "list": NewProfileListCmd(),
- }
- for name, cmd := range cmds {
- t.Run(name, func(t *testing.T) {
- err := cmd.ValidateArgs([]string{"unexpected-arg"})
- if err == nil {
- t.Errorf("%s accepted an argument, want it rejected", name)
- return
- }
- if !strings.Contains(err.Error(), "unexpected-arg") {
- t.Errorf("%s error = %q, want it to name the offending argument", name, err)
- }
- })
- }
- }
- // Rejecting extras must not break the no-argument case.
- func TestZeroArgCommandsAcceptNoArgs(t *testing.T) {
- cmds := map[string]*cobra.Command{
- "list": NewProfileListCmd(),
- }
- for name, cmd := range cmds {
- t.Run(name, func(t *testing.T) {
- if err := cmd.ValidateArgs(nil); err != nil {
- t.Errorf("%s rejected the empty argument list: %v", name, err)
- }
- })
- }
- }
- // A command whose arguments are a zone and a value takes exactly those two, and
- // refuses a third: an extra token means the invocation is not the one the user
- // meant, and carrying on with the first two is a guess.
- func TestTwoArgCommandsKeepTheirArity(t *testing.T) {
- cmds := map[string]*cobra.Command{
- "brightness": NewBrightnessCmd(),
- "speed": NewSpeedCmd(),
- "color": NewColorCmd(),
- }
- for name, cmd := range cmds {
- t.Run(name, func(t *testing.T) {
- if err := cmd.ValidateArgs([]string{"logo", "160"}); err != nil {
- t.Errorf("%s rejected its arguments: %v", name, err)
- }
- if err := cmd.ValidateArgs([]string{"160"}); err == nil {
- t.Errorf("%s accepted one argument, want a zone and a value", name)
- }
- if err := cmd.ValidateArgs([]string{"logo", "160", "extra"}); err == nil {
- t.Errorf("%s accepted three arguments, want exactly two", name)
- }
- })
- }
- }
- // A zone is an argument and not a flag, so the count of a command that writes
- // lighting is the thing that keeps it from writing every channel by accident.
- func TestZoneCommandsRejectAMissingZone(t *testing.T) {
- cmds := map[string]*cobra.Command{
- "enable": NewEnableCmd(),
- "disable": NewDisableCmd(),
- }
- for name, cmd := range cmds {
- t.Run(name, func(t *testing.T) {
- if err := cmd.ValidateArgs([]string{"logo"}); err != nil {
- t.Errorf("%s rejected a zone: %v", name, err)
- }
- err := cmd.ValidateArgs(nil)
- if err == nil {
- t.Fatalf("%s accepted no arguments, want the zone to be required", name)
- }
- if !strings.Contains(err.Error(), "zone") {
- t.Errorf("%s error = %q, want it to name the missing zone", name, err)
- }
- })
- }
- }
- // `effect` reads with one argument and writes with two, so the count is what tells
- // the two apart, and either count alone has to be accepted.
- func TestEffectTakesAZoneAndOptionallyAName(t *testing.T) {
- cmd := NewEffectCmd()
- if err := cmd.ValidateArgs([]string{"logo"}); err != nil {
- t.Errorf("effect rejected a zone on its own: %v", err)
- }
- if err := cmd.ValidateArgs([]string{"logo", "wave"}); err != nil {
- t.Errorf("effect rejected a zone and a name: %v", err)
- }
- if err := cmd.ValidateArgs(nil); err == nil {
- t.Error("effect accepted no arguments, want a zone to be required")
- }
- if err := cmd.ValidateArgs([]string{"logo", "wave", "extra"}); err == nil {
- t.Error("effect accepted three arguments, want at most two")
- }
- }
- // `info` reads every channel when it is given nothing and one zone when it is
- // given one. Both are requests, so neither is a stray token.
- func TestInfoTakesAtMostAZone(t *testing.T) {
- cmd := NewInfoCmd()
- if err := cmd.ValidateArgs(nil); err != nil {
- t.Errorf("info rejected no arguments: %v", err)
- }
- if err := cmd.ValidateArgs([]string{"logo"}); err != nil {
- t.Errorf("info rejected a zone: %v", err)
- }
- if err := cmd.ValidateArgs([]string{"logo", "side"}); err == nil {
- t.Error("info accepted two arguments, want one zone or none")
- }
- }
- // A list of zones is one argument, so `info logo,side` is one zone naming two
- // channels and not two arguments.
- func TestInfoTakesAZoneListAsOneArgument(t *testing.T) {
- cmd := NewInfoCmd()
- if err := cmd.ValidateArgs([]string{"logo,side"}); err != nil {
- t.Errorf("info rejected a comma separated zone list: %v", err)
- }
- }
|