Skip to content

Commit

Permalink
args: add new UnknownCommandError type
Browse files Browse the repository at this point in the history
This commit makes unknown commands a proper error type so that
the caller can check for this specific error type without having
to do string comparisons.

This is useful in the context of #823

Signed-off-by: Michael Vogt <[email protected]>
Signed-off-by: Michael Vogt <[email protected]>
  • Loading branch information
mvo5 committed Aug 19, 2024
1 parent 756ba6d commit a75c389
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 3 deletions.
15 changes: 13 additions & 2 deletions args.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ import (

type PositionalArgs func(cmd *Command, args []string) error

// UnknownCommandError is returned for unknown command
type UnknownCommandError struct {
unknownCmd string
cmdPath string
suggestions string
}

func (e UnknownCommandError) Error() string {
return fmt.Sprintf("unknown command %q for %q%s", e.unknownCmd, e.cmdPath, e.suggestions)
}

// legacyArgs validation has the following behaviour:
// - root commands with no subcommands can take arbitrary arguments
// - root commands with subcommands will do subcommand validity checking
Expand All @@ -33,15 +44,15 @@ func legacyArgs(cmd *Command, args []string) error {

// root command with subcommands, do subcommand checking.
if !cmd.HasParent() && len(args) > 0 {
return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0]))
return UnknownCommandError{args[0], cmd.CommandPath(), cmd.findSuggestions(args[0])}
}
return nil
}

// NoArgs returns an error if any args are included.
func NoArgs(cmd *Command, args []string) error {
if len(args) > 0 {
return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath())
return UnknownCommandError{args[0], cmd.CommandPath(), ""}
}
return nil
}
Expand Down
15 changes: 14 additions & 1 deletion command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,10 @@ func TestRootExecuteUnknownCommand(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})

output, _ := executeCommand(rootCmd, "unknown")
output, err := executeCommand(rootCmd, "unknown")
if _, ok := err.(UnknownCommandError); !ok {
t.Errorf("Expected:\n %T\nGot:\n %T\n", err, UnknownCommandError{})
}

expected := "Error: unknown command \"unknown\" for \"root\"\nRun 'root --help' for usage.\n"

Expand All @@ -156,6 +159,16 @@ func TestRootExecuteUnknownCommand(t *testing.T) {
}
}

func TestRootFindUnknownCommandErrorType(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})

_, _, err := rootCmd.Find([]string{"unknown"})
if _, ok := err.(UnknownCommandError); !ok {
t.Errorf("Expected:\n %T\nGot:\n %T\n", err, UnknownCommandError{})
}
}

func TestSubcommandExecuteC(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
childCmd := &Command{Use: "child", Run: emptyRun}
Expand Down

0 comments on commit a75c389

Please sign in to comment.