2023-03-06 02:28:31 +00:00
// Copyright 2013-2023 The Cobra Authors
2022-09-16 11:55:56 +00:00
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2015-03-11 18:52:35 +00:00
package cobra
import (
2016-05-25 21:27:02 +00:00
"bytes"
2020-02-20 06:29:50 +00:00
"context"
2016-05-25 21:27:02 +00:00
"fmt"
2024-03-12 10:42:46 +00:00
"io"
2016-06-04 00:25:52 +00:00
"os"
2015-03-11 18:52:35 +00:00
"reflect"
2017-04-23 07:50:55 +00:00
"strings"
2015-03-11 18:52:35 +00:00
"testing"
2017-04-19 11:59:20 +00:00
"github.com/spf13/pflag"
2015-03-11 18:52:35 +00:00
)
2017-10-31 18:58:37 +00:00
func emptyRun ( * Command , [ ] string ) { }
func executeCommand ( root * Command , args ... string ) ( output string , err error ) {
_ , output , err = executeCommandC ( root , args ... )
return output , err
}
2020-02-20 06:29:50 +00:00
func executeCommandWithContext ( ctx context . Context , root * Command , args ... string ) ( output string , err error ) {
buf := new ( bytes . Buffer )
2020-04-01 16:25:22 +00:00
root . SetOut ( buf )
root . SetErr ( buf )
2020-02-20 06:29:50 +00:00
root . SetArgs ( args )
err = root . ExecuteContext ( ctx )
return buf . String ( ) , err
}
2017-10-31 18:58:37 +00:00
func executeCommandC ( root * Command , args ... string ) ( c * Command , output string , err error ) {
buf := new ( bytes . Buffer )
2020-04-01 16:25:22 +00:00
root . SetOut ( buf )
root . SetErr ( buf )
2017-10-31 18:58:37 +00:00
root . SetArgs ( args )
c , err = root . ExecuteC ( )
return c , buf . String ( ) , err
}
2021-05-03 16:33:57 +00:00
func executeCommandWithContextC ( ctx context . Context , root * Command , args ... string ) ( c * Command , output string , err error ) {
buf := new ( bytes . Buffer )
root . SetOut ( buf )
root . SetErr ( buf )
root . SetArgs ( args )
c , err = root . ExecuteContextC ( ctx )
return c , buf . String ( ) , err
}
2017-10-31 18:58:37 +00:00
func resetCommandLineFlagSet ( ) {
pflag . CommandLine = pflag . NewFlagSet ( os . Args [ 0 ] , pflag . ExitOnError )
}
2017-11-02 13:27:24 +00:00
func checkStringContains ( t * testing . T , got , expected string ) {
if ! strings . Contains ( got , expected ) {
t . Errorf ( "Expected to contain: \n %v\nGot:\n %v\n" , expected , got )
}
}
func checkStringOmits ( t * testing . T , got , expected string ) {
if strings . Contains ( got , expected ) {
t . Errorf ( "Expected to not contain: \n %v\nGot: %v" , expected , got )
}
}
2021-02-08 00:08:50 +00:00
const onetwo = "one two"
2017-10-31 18:58:37 +00:00
func TestSingleCommand ( t * testing . T ) {
var rootCmdArgs [ ] string
rootCmd := & Command {
Use : "root" ,
Args : ExactArgs ( 2 ) ,
Run : func ( _ * Command , args [ ] string ) { rootCmdArgs = args } ,
}
aCmd := & Command { Use : "a" , Args : NoArgs , Run : emptyRun }
bCmd := & Command { Use : "b" , Args : NoArgs , Run : emptyRun }
rootCmd . AddCommand ( aCmd , bCmd )
output , err := executeCommand ( rootCmd , "one" , "two" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
got := strings . Join ( rootCmdArgs , " " )
2021-02-08 00:08:50 +00:00
if got != onetwo {
t . Errorf ( "rootCmdArgs expected: %q, got: %q" , onetwo , got )
2017-10-31 18:58:37 +00:00
}
}
func TestChildCommand ( t * testing . T ) {
var child1CmdArgs [ ] string
rootCmd := & Command { Use : "root" , Args : NoArgs , Run : emptyRun }
child1Cmd := & Command {
Use : "child1" ,
Args : ExactArgs ( 2 ) ,
Run : func ( _ * Command , args [ ] string ) { child1CmdArgs = args } ,
}
child2Cmd := & Command { Use : "child2" , Args : NoArgs , Run : emptyRun }
rootCmd . AddCommand ( child1Cmd , child2Cmd )
output , err := executeCommand ( rootCmd , "child1" , "one" , "two" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
got := strings . Join ( child1CmdArgs , " " )
2021-02-08 00:08:50 +00:00
if got != onetwo {
t . Errorf ( "child1CmdArgs expected: %q, got: %q" , onetwo , got )
2017-10-31 18:58:37 +00:00
}
}
func TestCallCommandWithoutSubcommands ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Args : NoArgs , Run : emptyRun }
_ , err := executeCommand ( rootCmd )
if err != nil {
t . Errorf ( "Calling command without subcommands should not have error: %v" , err )
}
}
func TestRootExecuteUnknownCommand ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
rootCmd . AddCommand ( & Command { Use : "child" , Run : emptyRun } )
output , _ := executeCommand ( rootCmd , "unknown" )
expected := "Error: unknown command \"unknown\" for \"root\"\nRun 'root --help' for usage.\n"
if output != expected {
t . Errorf ( "Expected:\n %q\nGot:\n %q\n" , expected , output )
}
}
func TestSubcommandExecuteC ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
childCmd := & Command { Use : "child" , Run : emptyRun }
rootCmd . AddCommand ( childCmd )
c , output , err := executeCommandC ( rootCmd , "child" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if c . Name ( ) != "child" {
2021-02-08 00:08:50 +00:00
t . Errorf ( ` invalid command returned from ExecuteC: expected "child"', got: %q ` , c . Name ( ) )
2017-10-31 18:58:37 +00:00
}
}
2020-02-20 06:29:50 +00:00
func TestExecuteContext ( t * testing . T ) {
ctx := context . TODO ( )
ctxRun := func ( cmd * Command , args [ ] string ) {
if cmd . Context ( ) != ctx {
t . Errorf ( "Command %q must have context when called with ExecuteContext" , cmd . Use )
}
}
rootCmd := & Command { Use : "root" , Run : ctxRun , PreRun : ctxRun }
childCmd := & Command { Use : "child" , Run : ctxRun , PreRun : ctxRun }
granchildCmd := & Command { Use : "grandchild" , Run : ctxRun , PreRun : ctxRun }
childCmd . AddCommand ( granchildCmd )
rootCmd . AddCommand ( childCmd )
if _ , err := executeCommandWithContext ( ctx , rootCmd , "" ) ; err != nil {
t . Errorf ( "Root command must not fail: %+v" , err )
}
if _ , err := executeCommandWithContext ( ctx , rootCmd , "child" ) ; err != nil {
t . Errorf ( "Subcommand must not fail: %+v" , err )
}
if _ , err := executeCommandWithContext ( ctx , rootCmd , "child" , "grandchild" ) ; err != nil {
t . Errorf ( "Command child must not fail: %+v" , err )
}
}
2021-05-03 16:33:57 +00:00
func TestExecuteContextC ( t * testing . T ) {
ctx := context . TODO ( )
ctxRun := func ( cmd * Command , args [ ] string ) {
if cmd . Context ( ) != ctx {
t . Errorf ( "Command %q must have context when called with ExecuteContext" , cmd . Use )
}
}
rootCmd := & Command { Use : "root" , Run : ctxRun , PreRun : ctxRun }
childCmd := & Command { Use : "child" , Run : ctxRun , PreRun : ctxRun }
granchildCmd := & Command { Use : "grandchild" , Run : ctxRun , PreRun : ctxRun }
childCmd . AddCommand ( granchildCmd )
rootCmd . AddCommand ( childCmd )
if _ , _ , err := executeCommandWithContextC ( ctx , rootCmd , "" ) ; err != nil {
t . Errorf ( "Root command must not fail: %+v" , err )
}
if _ , _ , err := executeCommandWithContextC ( ctx , rootCmd , "child" ) ; err != nil {
t . Errorf ( "Subcommand must not fail: %+v" , err )
}
if _ , _ , err := executeCommandWithContextC ( ctx , rootCmd , "child" , "grandchild" ) ; err != nil {
t . Errorf ( "Command child must not fail: %+v" , err )
}
}
2020-02-20 06:29:50 +00:00
func TestExecute_NoContext ( t * testing . T ) {
run := func ( cmd * Command , args [ ] string ) {
if cmd . Context ( ) != context . Background ( ) {
t . Errorf ( "Command %s must have background context" , cmd . Use )
}
}
rootCmd := & Command { Use : "root" , Run : run , PreRun : run }
childCmd := & Command { Use : "child" , Run : run , PreRun : run }
granchildCmd := & Command { Use : "grandchild" , Run : run , PreRun : run }
childCmd . AddCommand ( granchildCmd )
rootCmd . AddCommand ( childCmd )
if _ , err := executeCommand ( rootCmd , "" ) ; err != nil {
t . Errorf ( "Root command must not fail: %+v" , err )
}
if _ , err := executeCommand ( rootCmd , "child" ) ; err != nil {
t . Errorf ( "Subcommand must not fail: %+v" , err )
}
if _ , err := executeCommand ( rootCmd , "child" , "grandchild" ) ; err != nil {
t . Errorf ( "Command child must not fail: %+v" , err )
}
}
2017-10-31 18:58:37 +00:00
func TestRootUnknownCommandSilenced ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
rootCmd . SilenceErrors = true
rootCmd . SilenceUsage = true
rootCmd . AddCommand ( & Command { Use : "child" , Run : emptyRun } )
output , _ := executeCommand ( rootCmd , "unknown" )
if output != "" {
t . Errorf ( "Expected blank output, because of silenced usage.\nGot:\n %q\n" , output )
}
}
func TestCommandAlias ( t * testing . T ) {
var timesCmdArgs [ ] string
rootCmd := & Command { Use : "root" , Args : NoArgs , Run : emptyRun }
echoCmd := & Command {
Use : "echo" ,
Aliases : [ ] string { "say" , "tell" } ,
Args : NoArgs ,
Run : emptyRun ,
}
timesCmd := & Command {
Use : "times" ,
Args : ExactArgs ( 2 ) ,
Run : func ( _ * Command , args [ ] string ) { timesCmdArgs = args } ,
}
echoCmd . AddCommand ( timesCmd )
rootCmd . AddCommand ( echoCmd )
output , err := executeCommand ( rootCmd , "tell" , "times" , "one" , "two" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
got := strings . Join ( timesCmdArgs , " " )
2021-02-08 00:08:50 +00:00
if got != onetwo {
t . Errorf ( "timesCmdArgs expected: %v, got: %v" , onetwo , got )
2017-10-31 18:58:37 +00:00
}
}
func TestEnablePrefixMatching ( t * testing . T ) {
EnablePrefixMatching = true
var aCmdArgs [ ] string
rootCmd := & Command { Use : "root" , Args : NoArgs , Run : emptyRun }
aCmd := & Command {
Use : "aCmd" ,
Args : ExactArgs ( 2 ) ,
Run : func ( _ * Command , args [ ] string ) { aCmdArgs = args } ,
}
bCmd := & Command { Use : "bCmd" , Args : NoArgs , Run : emptyRun }
rootCmd . AddCommand ( aCmd , bCmd )
output , err := executeCommand ( rootCmd , "a" , "one" , "two" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
got := strings . Join ( aCmdArgs , " " )
2021-02-08 00:08:50 +00:00
if got != onetwo {
t . Errorf ( "aCmdArgs expected: %q, got: %q" , onetwo , got )
2017-10-31 18:58:37 +00:00
}
2022-09-11 12:25:22 +00:00
EnablePrefixMatching = defaultPrefixMatching
2017-10-31 18:58:37 +00:00
}
func TestAliasPrefixMatching ( t * testing . T ) {
EnablePrefixMatching = true
var timesCmdArgs [ ] string
rootCmd := & Command { Use : "root" , Args : NoArgs , Run : emptyRun }
echoCmd := & Command {
Use : "echo" ,
Aliases : [ ] string { "say" , "tell" } ,
Args : NoArgs ,
Run : emptyRun ,
}
timesCmd := & Command {
Use : "times" ,
Args : ExactArgs ( 2 ) ,
Run : func ( _ * Command , args [ ] string ) { timesCmdArgs = args } ,
}
echoCmd . AddCommand ( timesCmd )
rootCmd . AddCommand ( echoCmd )
output , err := executeCommand ( rootCmd , "sa" , "times" , "one" , "two" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
got := strings . Join ( timesCmdArgs , " " )
2021-02-08 00:08:50 +00:00
if got != onetwo {
t . Errorf ( "timesCmdArgs expected: %v, got: %v" , onetwo , got )
2017-10-31 18:58:37 +00:00
}
2022-09-11 12:25:22 +00:00
EnablePrefixMatching = defaultPrefixMatching
2017-10-31 18:58:37 +00:00
}
2023-11-02 12:15:26 +00:00
// TestPlugin checks usage as plugin for another command such as kubectl. The
// executable is `kubectl-plugin`, but we run it as `kubectl plugin`. The help
// text should reflect the way we run the command.
func TestPlugin ( t * testing . T ) {
2023-11-12 18:07:59 +00:00
cmd := & Command {
Use : "kubectl-plugin" ,
Args : NoArgs ,
Annotations : map [ string ] string {
CommandDisplayNameAnnotation : "kubectl plugin" ,
} ,
Run : emptyRun ,
}
cmdHelp , err := executeCommand ( cmd , "-h" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , cmdHelp , "kubectl plugin [flags]" )
checkStringContains ( t , cmdHelp , "help for kubectl plugin" )
}
// TestPlugin checks usage as plugin with sub commands.
func TestPluginWithSubCommands ( t * testing . T ) {
2023-11-02 12:15:26 +00:00
rootCmd := & Command {
2023-11-12 15:20:47 +00:00
Use : "kubectl-plugin" ,
2023-11-02 12:15:26 +00:00
Args : NoArgs ,
Annotations : map [ string ] string {
CommandDisplayNameAnnotation : "kubectl plugin" ,
} ,
}
subCmd := & Command { Use : "sub [flags]" , Args : NoArgs , Run : emptyRun }
rootCmd . AddCommand ( subCmd )
rootHelp , err := executeCommand ( rootCmd , "-h" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , rootHelp , "kubectl plugin [command]" )
2023-11-12 15:20:47 +00:00
checkStringContains ( t , rootHelp , "help for kubectl plugin" )
checkStringContains ( t , rootHelp , "kubectl plugin [command] --help" )
2023-11-02 12:15:26 +00:00
childHelp , err := executeCommand ( rootCmd , "sub" , "-h" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , childHelp , "kubectl plugin sub [flags]" )
2023-11-12 15:20:47 +00:00
checkStringContains ( t , childHelp , "help for sub" )
helpHelp , err := executeCommand ( rootCmd , "help" , "-h" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , helpHelp , "kubectl plugin help [path to command]" )
checkStringContains ( t , helpHelp , "kubectl plugin help [command]" )
2023-11-02 12:15:26 +00:00
}
2017-10-31 18:58:37 +00:00
// TestChildSameName checks the correct behaviour of cobra in cases,
// when an application with name "foo" and with subcommand "foo"
// is executed with args "foo foo".
func TestChildSameName ( t * testing . T ) {
var fooCmdArgs [ ] string
rootCmd := & Command { Use : "foo" , Args : NoArgs , Run : emptyRun }
fooCmd := & Command {
Use : "foo" ,
Args : ExactArgs ( 2 ) ,
Run : func ( _ * Command , args [ ] string ) { fooCmdArgs = args } ,
}
barCmd := & Command { Use : "bar" , Args : NoArgs , Run : emptyRun }
rootCmd . AddCommand ( fooCmd , barCmd )
output , err := executeCommand ( rootCmd , "foo" , "one" , "two" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
got := strings . Join ( fooCmdArgs , " " )
2021-02-08 00:08:50 +00:00
if got != onetwo {
t . Errorf ( "fooCmdArgs expected: %v, got: %v" , onetwo , got )
2017-10-31 18:58:37 +00:00
}
}
// TestGrandChildSameName checks the correct behaviour of cobra in cases,
// when user has a root command and a grand child
// with the same name.
func TestGrandChildSameName ( t * testing . T ) {
var fooCmdArgs [ ] string
rootCmd := & Command { Use : "foo" , Args : NoArgs , Run : emptyRun }
barCmd := & Command { Use : "bar" , Args : NoArgs , Run : emptyRun }
fooCmd := & Command {
Use : "foo" ,
Args : ExactArgs ( 2 ) ,
Run : func ( _ * Command , args [ ] string ) { fooCmdArgs = args } ,
}
barCmd . AddCommand ( fooCmd )
rootCmd . AddCommand ( barCmd )
output , err := executeCommand ( rootCmd , "bar" , "foo" , "one" , "two" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
got := strings . Join ( fooCmdArgs , " " )
2021-02-08 00:08:50 +00:00
if got != onetwo {
t . Errorf ( "fooCmdArgs expected: %v, got: %v" , onetwo , got )
2017-10-31 18:58:37 +00:00
}
}
func TestFlagLong ( t * testing . T ) {
var cArgs [ ] string
c := & Command {
Use : "c" ,
Args : ArbitraryArgs ,
Run : func ( _ * Command , args [ ] string ) { cArgs = args } ,
}
var intFlagValue int
var stringFlagValue string
c . Flags ( ) . IntVar ( & intFlagValue , "intf" , - 1 , "" )
c . Flags ( ) . StringVar ( & stringFlagValue , "sf" , "" , "" )
output , err := executeCommand ( c , "--intf=7" , "--sf=abc" , "one" , "--" , "two" )
if output != "" {
2023-07-23 11:31:55 +00:00
t . Errorf ( "Unexpected output: %v" , output )
2017-10-31 18:58:37 +00:00
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if c . ArgsLenAtDash ( ) != 1 {
t . Errorf ( "Expected ArgsLenAtDash: %v but got %v" , 1 , c . ArgsLenAtDash ( ) )
}
if intFlagValue != 7 {
t . Errorf ( "Expected intFlagValue: %v, got %v" , 7 , intFlagValue )
}
if stringFlagValue != "abc" {
t . Errorf ( "Expected stringFlagValue: %q, got %q" , "abc" , stringFlagValue )
}
got := strings . Join ( cArgs , " " )
2021-02-08 00:08:50 +00:00
if got != onetwo {
t . Errorf ( "rootCmdArgs expected: %q, got: %q" , onetwo , got )
2017-10-31 18:58:37 +00:00
}
}
func TestFlagShort ( t * testing . T ) {
var cArgs [ ] string
c := & Command {
Use : "c" ,
Args : ArbitraryArgs ,
Run : func ( _ * Command , args [ ] string ) { cArgs = args } ,
}
var intFlagValue int
var stringFlagValue string
c . Flags ( ) . IntVarP ( & intFlagValue , "intf" , "i" , - 1 , "" )
c . Flags ( ) . StringVarP ( & stringFlagValue , "sf" , "s" , "" , "" )
output , err := executeCommand ( c , "-i" , "7" , "-sabc" , "one" , "two" )
if output != "" {
2023-07-23 11:31:55 +00:00
t . Errorf ( "Unexpected output: %v" , output )
2017-10-31 18:58:37 +00:00
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if intFlagValue != 7 {
t . Errorf ( "Expected flag value: %v, got %v" , 7 , intFlagValue )
}
if stringFlagValue != "abc" {
t . Errorf ( "Expected stringFlagValue: %q, got %q" , "abc" , stringFlagValue )
}
got := strings . Join ( cArgs , " " )
2021-02-08 00:08:50 +00:00
if got != onetwo {
t . Errorf ( "rootCmdArgs expected: %q, got: %q" , onetwo , got )
2017-10-31 18:58:37 +00:00
}
}
func TestChildFlag ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
childCmd := & Command { Use : "child" , Run : emptyRun }
rootCmd . AddCommand ( childCmd )
var intFlagValue int
childCmd . Flags ( ) . IntVarP ( & intFlagValue , "intf" , "i" , - 1 , "" )
output , err := executeCommand ( rootCmd , "child" , "-i7" )
if output != "" {
2023-07-23 11:31:55 +00:00
t . Errorf ( "Unexpected output: %v" , output )
2017-10-31 18:58:37 +00:00
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if intFlagValue != 7 {
t . Errorf ( "Expected flag value: %v, got %v" , 7 , intFlagValue )
}
}
func TestChildFlagWithParentLocalFlag ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
childCmd := & Command { Use : "child" , Run : emptyRun }
rootCmd . AddCommand ( childCmd )
var intFlagValue int
rootCmd . Flags ( ) . StringP ( "sf" , "s" , "" , "" )
childCmd . Flags ( ) . IntVarP ( & intFlagValue , "intf" , "i" , - 1 , "" )
_ , err := executeCommand ( rootCmd , "child" , "-i7" , "-sabc" )
if err == nil {
t . Errorf ( "Invalid flag should generate error" )
}
2017-11-02 13:27:24 +00:00
checkStringContains ( t , err . Error ( ) , "unknown shorthand" )
2017-10-31 18:58:37 +00:00
if intFlagValue != 7 {
t . Errorf ( "Expected flag value: %v, got %v" , 7 , intFlagValue )
}
}
func TestFlagInvalidInput ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
rootCmd . Flags ( ) . IntP ( "intf" , "i" , - 1 , "" )
_ , err := executeCommand ( rootCmd , "-iabc" )
if err == nil {
t . Errorf ( "Invalid flag value should generate error" )
}
2017-11-02 13:27:24 +00:00
checkStringContains ( t , err . Error ( ) , "invalid syntax" )
2017-10-31 18:58:37 +00:00
}
func TestFlagBeforeCommand ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
childCmd := & Command { Use : "child" , Run : emptyRun }
rootCmd . AddCommand ( childCmd )
var flagValue int
childCmd . Flags ( ) . IntVarP ( & flagValue , "intf" , "i" , - 1 , "" )
// With short flag.
_ , err := executeCommand ( rootCmd , "-i7" , "child" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if flagValue != 7 {
t . Errorf ( "Expected flag value: %v, got %v" , 7 , flagValue )
}
// With long flag.
_ , err = executeCommand ( rootCmd , "--intf=8" , "child" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if flagValue != 8 {
t . Errorf ( "Expected flag value: %v, got %v" , 9 , flagValue )
}
}
func TestStripFlags ( t * testing . T ) {
tests := [ ] struct {
input [ ] string
output [ ] string
} {
{
[ ] string { "foo" , "bar" } ,
[ ] string { "foo" , "bar" } ,
} ,
{
[ ] string { "foo" , "--str" , "-s" } ,
[ ] string { "foo" } ,
} ,
{
[ ] string { "-s" , "foo" , "--str" , "bar" } ,
[ ] string { } ,
} ,
{
[ ] string { "-i10" , "echo" } ,
[ ] string { "echo" } ,
} ,
{
[ ] string { "-i=10" , "echo" } ,
[ ] string { "echo" } ,
} ,
{
[ ] string { "--int=100" , "echo" } ,
[ ] string { "echo" } ,
} ,
{
[ ] string { "-ib" , "echo" , "-sfoo" , "baz" } ,
[ ] string { "echo" , "baz" } ,
} ,
{
[ ] string { "-i=baz" , "bar" , "-i" , "foo" , "blah" } ,
[ ] string { "bar" , "blah" } ,
} ,
{
[ ] string { "--int=baz" , "-sbar" , "-i" , "foo" , "blah" } ,
[ ] string { "blah" } ,
} ,
{
[ ] string { "--bool" , "bar" , "-i" , "foo" , "blah" } ,
[ ] string { "bar" , "blah" } ,
} ,
{
[ ] string { "-b" , "bar" , "-i" , "foo" , "blah" } ,
[ ] string { "bar" , "blah" } ,
} ,
{
[ ] string { "--persist" , "bar" } ,
[ ] string { "bar" } ,
} ,
{
[ ] string { "-p" , "bar" } ,
[ ] string { "bar" } ,
} ,
2024-09-14 14:08:27 +00:00
{
[ ] string { "-s" , "value" , "bar" } ,
[ ] string { "bar" } ,
} ,
{
[ ] string { "-s=value" , "bar" } ,
[ ] string { "bar" } ,
} ,
{
[ ] string { "-svalue" , "bar" } ,
[ ] string { "bar" } ,
} ,
{
[ ] string { "-ps" , "value" , "bar" } ,
[ ] string { "bar" } ,
} ,
{
[ ] string { "-ps=value" , "bar" } ,
[ ] string { "bar" } ,
} ,
{
[ ] string { "-psvalue" , "bar" } ,
[ ] string { "bar" } ,
} ,
2017-10-31 18:58:37 +00:00
}
c := & Command { Use : "c" , Run : emptyRun }
c . PersistentFlags ( ) . BoolP ( "persist" , "p" , false , "" )
c . Flags ( ) . IntP ( "int" , "i" , - 1 , "" )
c . Flags ( ) . StringP ( "str" , "s" , "" , "" )
c . Flags ( ) . BoolP ( "bool" , "b" , false , "" )
for i , test := range tests {
2024-09-14 14:08:27 +00:00
got , _ := stripFlags ( test . input , c )
2017-10-31 18:58:37 +00:00
if ! reflect . DeepEqual ( test . output , got ) {
t . Errorf ( "(%v) Expected: %v, got: %v" , i , test . output , got )
}
}
}
func TestDisableFlagParsing ( t * testing . T ) {
var cArgs [ ] string
c := & Command {
Use : "c" ,
DisableFlagParsing : true ,
Run : func ( _ * Command , args [ ] string ) {
cArgs = args
} ,
}
args := [ ] string { "cmd" , "-v" , "-race" , "-file" , "foo.go" }
output , err := executeCommand ( c , args ... )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if ! reflect . DeepEqual ( args , cArgs ) {
t . Errorf ( "Expected: %v, got: %v" , args , cArgs )
}
}
func TestPersistentFlagsOnSameCommand ( t * testing . T ) {
var rootCmdArgs [ ] string
rootCmd := & Command {
Use : "root" ,
Args : ArbitraryArgs ,
Run : func ( _ * Command , args [ ] string ) { rootCmdArgs = args } ,
}
var flagValue int
rootCmd . PersistentFlags ( ) . IntVarP ( & flagValue , "intf" , "i" , - 1 , "" )
output , err := executeCommand ( rootCmd , "-i7" , "one" , "two" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
got := strings . Join ( rootCmdArgs , " " )
2021-02-08 00:08:50 +00:00
if got != onetwo {
t . Errorf ( "rootCmdArgs expected: %q, got %q" , onetwo , got )
2017-10-31 18:58:37 +00:00
}
if flagValue != 7 {
t . Errorf ( "flagValue expected: %v, got %v" , 7 , flagValue )
}
}
// TestEmptyInputs checks,
// if flags correctly parsed with blank strings in args.
func TestEmptyInputs ( t * testing . T ) {
c := & Command { Use : "c" , Run : emptyRun }
var flagValue int
c . Flags ( ) . IntVarP ( & flagValue , "intf" , "i" , - 1 , "" )
output , err := executeCommand ( c , "" , "-i7" , "" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if flagValue != 7 {
t . Errorf ( "flagValue expected: %v, got %v" , 7 , flagValue )
}
}
2022-08-28 16:46:39 +00:00
func TestChildFlagShadowsParentPersistentFlag ( t * testing . T ) {
2017-10-31 18:58:37 +00:00
parent := & Command { Use : "parent" , Run : emptyRun }
child := & Command { Use : "child" , Run : emptyRun }
parent . PersistentFlags ( ) . Bool ( "boolf" , false , "" )
parent . PersistentFlags ( ) . Int ( "intf" , - 1 , "" )
child . Flags ( ) . String ( "strf" , "" , "" )
child . Flags ( ) . Int ( "intf" , - 1 , "" )
parent . AddCommand ( child )
childInherited := child . InheritedFlags ( )
childLocal := child . LocalFlags ( )
if childLocal . Lookup ( "strf" ) == nil {
t . Error ( ` LocalFlags expected to contain "strf", got "nil" ` )
}
if childInherited . Lookup ( "boolf" ) == nil {
t . Error ( ` InheritedFlags expected to contain "boolf", got "nil" ` )
}
if childInherited . Lookup ( "intf" ) != nil {
2022-08-28 16:46:39 +00:00
t . Errorf ( ` InheritedFlags should not contain shadowed flag "intf" ` )
2017-10-31 18:58:37 +00:00
}
if childLocal . Lookup ( "intf" ) == nil {
t . Error ( ` LocalFlags expected to contain "intf", got "nil" ` )
}
}
func TestPersistentFlagsOnChild ( t * testing . T ) {
var childCmdArgs [ ] string
rootCmd := & Command { Use : "root" , Run : emptyRun }
childCmd := & Command {
Use : "child" ,
Args : ArbitraryArgs ,
Run : func ( _ * Command , args [ ] string ) { childCmdArgs = args } ,
}
rootCmd . AddCommand ( childCmd )
var parentFlagValue int
var childFlagValue int
rootCmd . PersistentFlags ( ) . IntVarP ( & parentFlagValue , "parentf" , "p" , - 1 , "" )
childCmd . Flags ( ) . IntVarP ( & childFlagValue , "childf" , "c" , - 1 , "" )
output , err := executeCommand ( rootCmd , "child" , "-c7" , "-p8" , "one" , "two" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
got := strings . Join ( childCmdArgs , " " )
2021-02-08 00:08:50 +00:00
if got != onetwo {
t . Errorf ( "rootCmdArgs expected: %q, got: %q" , onetwo , got )
2017-10-31 18:58:37 +00:00
}
if parentFlagValue != 8 {
t . Errorf ( "parentFlagValue expected: %v, got %v" , 8 , parentFlagValue )
}
if childFlagValue != 7 {
t . Errorf ( "childFlagValue expected: %v, got %v" , 7 , childFlagValue )
}
}
func TestRequiredFlags ( t * testing . T ) {
c := & Command { Use : "c" , Run : emptyRun }
c . Flags ( ) . String ( "foo1" , "" , "" )
2021-02-08 00:08:50 +00:00
assertNoErr ( t , c . MarkFlagRequired ( "foo1" ) )
2017-10-31 18:58:37 +00:00
c . Flags ( ) . String ( "foo2" , "" , "" )
2021-02-08 00:08:50 +00:00
assertNoErr ( t , c . MarkFlagRequired ( "foo2" ) )
2017-10-31 18:58:37 +00:00
c . Flags ( ) . String ( "bar" , "" , "" )
2017-11-19 09:22:51 +00:00
expected := fmt . Sprintf ( "required flag(s) %q, %q not set" , "foo1" , "foo2" )
2017-10-31 18:58:37 +00:00
_ , err := executeCommand ( c )
got := err . Error ( )
if got != expected {
t . Errorf ( "Expected error: %q, got: %q" , expected , got )
}
}
func TestPersistentRequiredFlags ( t * testing . T ) {
parent := & Command { Use : "parent" , Run : emptyRun }
parent . PersistentFlags ( ) . String ( "foo1" , "" , "" )
2021-02-08 00:08:50 +00:00
assertNoErr ( t , parent . MarkPersistentFlagRequired ( "foo1" ) )
2017-10-31 18:58:37 +00:00
parent . PersistentFlags ( ) . String ( "foo2" , "" , "" )
2021-02-08 00:08:50 +00:00
assertNoErr ( t , parent . MarkPersistentFlagRequired ( "foo2" ) )
2017-10-31 18:58:37 +00:00
parent . Flags ( ) . String ( "foo3" , "" , "" )
child := & Command { Use : "child" , Run : emptyRun }
child . Flags ( ) . String ( "bar1" , "" , "" )
2021-02-08 00:08:50 +00:00
assertNoErr ( t , child . MarkFlagRequired ( "bar1" ) )
2017-10-31 18:58:37 +00:00
child . Flags ( ) . String ( "bar2" , "" , "" )
2021-02-08 00:08:50 +00:00
assertNoErr ( t , child . MarkFlagRequired ( "bar2" ) )
2017-10-31 18:58:37 +00:00
child . Flags ( ) . String ( "bar3" , "" , "" )
parent . AddCommand ( child )
2017-11-19 09:22:51 +00:00
expected := fmt . Sprintf ( "required flag(s) %q, %q, %q, %q not set" , "bar1" , "bar2" , "foo1" , "foo2" )
2017-10-31 18:58:37 +00:00
_ , err := executeCommand ( parent , "child" )
if err . Error ( ) != expected {
t . Errorf ( "Expected %q, got %q" , expected , err . Error ( ) )
}
}
2020-05-08 01:18:16 +00:00
func TestPersistentRequiredFlagsWithDisableFlagParsing ( t * testing . T ) {
// Make sure a required persistent flag does not break
// commands that disable flag parsing
parent := & Command { Use : "parent" , Run : emptyRun }
parent . PersistentFlags ( ) . Bool ( "foo" , false , "" )
flag := parent . PersistentFlags ( ) . Lookup ( "foo" )
2021-02-08 00:08:50 +00:00
assertNoErr ( t , parent . MarkPersistentFlagRequired ( "foo" ) )
2020-05-08 01:18:16 +00:00
child := & Command { Use : "child" , Run : emptyRun }
child . DisableFlagParsing = true
parent . AddCommand ( child )
if _ , err := executeCommand ( parent , "--foo" , "child" ) ; err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
// Reset the flag or else it will remember the state from the previous command
flag . Changed = false
if _ , err := executeCommand ( parent , "child" , "--foo" ) ; err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
// Reset the flag or else it will remember the state from the previous command
flag . Changed = false
if _ , err := executeCommand ( parent , "child" ) ; err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
}
2017-10-31 18:58:37 +00:00
func TestInitHelpFlagMergesFlags ( t * testing . T ) {
usage := "custom flag"
rootCmd := & Command { Use : "root" }
rootCmd . PersistentFlags ( ) . Bool ( "help" , false , "custom flag" )
childCmd := & Command { Use : "child" }
rootCmd . AddCommand ( childCmd )
childCmd . InitDefaultHelpFlag ( )
got := childCmd . Flags ( ) . Lookup ( "help" ) . Usage
if got != usage {
t . Errorf ( "Expected the help flag from the root command with usage: %v\nGot the default with usage: %v" , usage , got )
}
}
func TestHelpCommandExecuted ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Long : "Long description" , Run : emptyRun }
rootCmd . AddCommand ( & Command { Use : "child" , Run : emptyRun } )
output , err := executeCommand ( rootCmd , "help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
2017-11-02 13:27:24 +00:00
checkStringContains ( t , output , rootCmd . Long )
2017-10-31 18:58:37 +00:00
}
func TestHelpCommandExecutedOnChild ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
childCmd := & Command { Use : "child" , Long : "Long description" , Run : emptyRun }
rootCmd . AddCommand ( childCmd )
output , err := executeCommand ( rootCmd , "help" , "child" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
2017-11-02 13:27:24 +00:00
checkStringContains ( t , output , childCmd . Long )
2017-10-31 18:58:37 +00:00
}
2022-08-28 16:46:39 +00:00
func TestHelpCommandExecutedOnChildWithFlagThatShadowsParentFlag ( t * testing . T ) {
parent := & Command { Use : "parent" , Run : emptyRun }
child := & Command { Use : "child" , Run : emptyRun }
parent . AddCommand ( child )
parent . PersistentFlags ( ) . Bool ( "foo" , false , "parent foo usage" )
parent . PersistentFlags ( ) . Bool ( "bar" , false , "parent bar usage" )
child . Flags ( ) . Bool ( "foo" , false , "child foo usage" ) // This shadows parent's foo flag
child . Flags ( ) . Bool ( "baz" , false , "child baz usage" )
got , err := executeCommand ( parent , "help" , "child" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
expected := ` Usage :
parent child [ flags ]
Flags :
-- baz child baz usage
-- foo child foo usage
- h , -- help help for child
Global Flags :
-- bar parent bar usage
`
if got != expected {
t . Errorf ( "Help text mismatch.\nExpected:\n%s\n\nGot:\n%s\n" , expected , got )
}
}
2017-10-31 18:58:37 +00:00
func TestSetHelpCommand ( t * testing . T ) {
c := & Command { Use : "c" , Run : emptyRun }
c . AddCommand ( & Command { Use : "empty" , Run : emptyRun } )
expected := "WORKS"
c . SetHelpCommand ( & Command {
Use : "help [command]" ,
Short : "Help about any command" ,
Long : ` Help provides help for any command in the application .
Simply type ` + c.Name() + ` help [ path to command ] for full details . ` ,
Run : func ( c * Command , _ [ ] string ) { c . Print ( expected ) } ,
} )
got , err := executeCommand ( c , "help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if got != expected {
t . Errorf ( "Expected to contain %q, got %q" , expected , got )
}
}
func TestHelpFlagExecuted ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Long : "Long description" , Run : emptyRun }
output , err := executeCommand ( rootCmd , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
2017-11-02 13:27:24 +00:00
checkStringContains ( t , output , rootCmd . Long )
2017-10-31 18:58:37 +00:00
}
func TestHelpFlagExecutedOnChild ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
childCmd := & Command { Use : "child" , Long : "Long description" , Run : emptyRun }
rootCmd . AddCommand ( childCmd )
output , err := executeCommand ( rootCmd , "child" , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
2017-11-02 13:27:24 +00:00
checkStringContains ( t , output , childCmd . Long )
2017-10-31 18:58:37 +00:00
}
// TestHelpFlagInHelp checks,
// if '--help' flag is shown in help for child (executing `parent help child`),
// that has no other flags.
// Related to https://github.com/spf13/cobra/issues/302.
func TestHelpFlagInHelp ( t * testing . T ) {
2017-11-02 13:27:24 +00:00
parentCmd := & Command { Use : "parent" , Run : func ( * Command , [ ] string ) { } }
2017-10-31 18:58:37 +00:00
2017-11-02 13:27:24 +00:00
childCmd := & Command { Use : "child" , Run : func ( * Command , [ ] string ) { } }
parentCmd . AddCommand ( childCmd )
2017-10-31 18:58:37 +00:00
2017-11-02 13:27:24 +00:00
output , err := executeCommand ( parentCmd , "help" , "child" )
2017-10-31 18:58:37 +00:00
if err != nil {
2017-11-02 13:27:24 +00:00
t . Errorf ( "Unexpected error: %v" , err )
2017-10-31 18:58:37 +00:00
}
2017-11-02 13:27:24 +00:00
checkStringContains ( t , output , "[flags]" )
2017-10-31 18:58:37 +00:00
}
func TestFlagsInUsage ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Args : NoArgs , Run : func ( * Command , [ ] string ) { } }
output , err := executeCommand ( rootCmd , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
2017-11-02 13:27:24 +00:00
checkStringContains ( t , output , "[flags]" )
2017-10-31 18:58:37 +00:00
}
func TestHelpExecutedOnNonRunnableChild ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
childCmd := & Command { Use : "child" , Long : "Long description" }
rootCmd . AddCommand ( childCmd )
output , err := executeCommand ( rootCmd , "child" )
2020-03-27 20:38:32 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
2017-10-31 18:58:37 +00:00
}
2015-09-04 20:34:51 +00:00
2017-11-02 13:27:24 +00:00
checkStringContains ( t , output , childCmd . Long )
2017-10-31 18:58:37 +00:00
}
2015-09-04 20:34:51 +00:00
2017-12-01 21:37:16 +00:00
func TestVersionFlagExecuted ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Version : "1.0.0" , Run : emptyRun }
output , err := executeCommand ( rootCmd , "--version" , "arg1" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , "root version 1.0.0" )
}
2020-02-28 18:13:40 +00:00
func TestVersionFlagExecutedWithNoName ( t * testing . T ) {
rootCmd := & Command { Version : "1.0.0" , Run : emptyRun }
output , err := executeCommand ( rootCmd , "--version" , "arg1" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , "version 1.0.0" )
}
func TestShortAndLongVersionFlagInHelp ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Version : "1.0.0" , Run : emptyRun }
output , err := executeCommand ( rootCmd , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , "-v, --version" )
}
func TestLongVersionFlagOnlyInHelpWhenShortPredefined ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Version : "1.0.0" , Run : emptyRun }
rootCmd . Flags ( ) . StringP ( "foo" , "v" , "" , "not a version flag" )
output , err := executeCommand ( rootCmd , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringOmits ( t , output , "-v, --version" )
checkStringContains ( t , output , "--version" )
}
func TestShorthandVersionFlagExecuted ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Version : "1.0.0" , Run : emptyRun }
output , err := executeCommand ( rootCmd , "-v" , "arg1" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , "root version 1.0.0" )
}
2017-12-01 21:37:16 +00:00
func TestVersionTemplate ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Version : "1.0.0" , Run : emptyRun }
rootCmd . SetVersionTemplate ( ` customized version: {{ .Version }} ` )
output , err := executeCommand ( rootCmd , "--version" , "arg1" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , "customized version: 1.0.0" )
}
2020-02-28 18:13:40 +00:00
func TestShorthandVersionTemplate ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Version : "1.0.0" , Run : emptyRun }
rootCmd . SetVersionTemplate ( ` customized version: {{ .Version }} ` )
output , err := executeCommand ( rootCmd , "-v" , "arg1" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , "customized version: 1.0.0" )
}
2023-09-08 17:29:06 +00:00
func TestRootErrPrefixExecutedOnSubcommand ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
rootCmd . SetErrPrefix ( "root error prefix:" )
rootCmd . AddCommand ( & Command { Use : "sub" , Run : emptyRun } )
output , err := executeCommand ( rootCmd , "sub" , "--unknown-flag" )
if err == nil {
t . Errorf ( "Expected error" )
}
checkStringContains ( t , output , "root error prefix: unknown flag: --unknown-flag" )
}
func TestRootAndSubErrPrefix ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
subCmd := & Command { Use : "sub" , Run : emptyRun }
rootCmd . AddCommand ( subCmd )
rootCmd . SetErrPrefix ( "root error prefix:" )
subCmd . SetErrPrefix ( "sub error prefix:" )
if output , err := executeCommand ( rootCmd , "--unknown-root-flag" ) ; err == nil {
t . Errorf ( "Expected error" )
} else {
checkStringContains ( t , output , "root error prefix: unknown flag: --unknown-root-flag" )
}
if output , err := executeCommand ( rootCmd , "sub" , "--unknown-sub-flag" ) ; err == nil {
t . Errorf ( "Expected error" )
} else {
checkStringContains ( t , output , "sub error prefix: unknown flag: --unknown-sub-flag" )
}
}
2017-12-01 21:37:16 +00:00
func TestVersionFlagExecutedOnSubcommand ( t * testing . T ) {
2017-12-07 07:49:35 +00:00
rootCmd := & Command { Use : "root" , Version : "1.0.0" }
2017-12-01 21:37:16 +00:00
rootCmd . AddCommand ( & Command { Use : "sub" , Run : emptyRun } )
output , err := executeCommand ( rootCmd , "--version" , "sub" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , "root version 1.0.0" )
}
2020-02-28 18:13:40 +00:00
func TestShorthandVersionFlagExecutedOnSubcommand ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Version : "1.0.0" }
rootCmd . AddCommand ( & Command { Use : "sub" , Run : emptyRun } )
output , err := executeCommand ( rootCmd , "-v" , "sub" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , "root version 1.0.0" )
}
2017-12-01 21:37:16 +00:00
func TestVersionFlagOnlyAddedToRoot ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Version : "1.0.0" , Run : emptyRun }
rootCmd . AddCommand ( & Command { Use : "sub" , Run : emptyRun } )
_ , err := executeCommand ( rootCmd , "sub" , "--version" )
if err == nil {
t . Errorf ( "Expected error" )
}
checkStringContains ( t , err . Error ( ) , "unknown flag: --version" )
}
2020-02-28 18:13:40 +00:00
func TestShortVersionFlagOnlyAddedToRoot ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Version : "1.0.0" , Run : emptyRun }
rootCmd . AddCommand ( & Command { Use : "sub" , Run : emptyRun } )
_ , err := executeCommand ( rootCmd , "sub" , "-v" )
if err == nil {
t . Errorf ( "Expected error" )
}
checkStringContains ( t , err . Error ( ) , "unknown shorthand flag: 'v' in -v" )
}
2017-12-01 21:37:16 +00:00
func TestVersionFlagOnlyExistsIfVersionNonEmpty ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
_ , err := executeCommand ( rootCmd , "--version" )
if err == nil {
t . Errorf ( "Expected error" )
}
checkStringContains ( t , err . Error ( ) , "unknown flag: --version" )
}
2020-02-28 18:13:40 +00:00
func TestShorthandVersionFlagOnlyExistsIfVersionNonEmpty ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
_ , err := executeCommand ( rootCmd , "-v" )
if err == nil {
t . Errorf ( "Expected error" )
}
checkStringContains ( t , err . Error ( ) , "unknown shorthand flag: 'v' in -v" )
}
func TestShorthandVersionFlagOnlyAddedIfShorthandNotDefined ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun , Version : "1.2.3" }
rootCmd . Flags ( ) . StringP ( "notversion" , "v" , "" , "not a version flag" )
_ , err := executeCommand ( rootCmd , "-v" )
if err == nil {
t . Errorf ( "Expected error" )
}
check ( t , rootCmd . Flags ( ) . ShorthandLookup ( "v" ) . Name , "notversion" )
checkStringContains ( t , err . Error ( ) , "flag needs an argument: 'v' in -v" )
}
func TestShorthandVersionFlagOnlyAddedIfVersionNotDefined ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun , Version : "1.2.3" }
rootCmd . Flags ( ) . Bool ( "version" , false , "a different kind of version flag" )
_ , err := executeCommand ( rootCmd , "-v" )
if err == nil {
t . Errorf ( "Expected error" )
}
checkStringContains ( t , err . Error ( ) , "unknown shorthand flag: 'v' in -v" )
}
2017-10-31 18:58:37 +00:00
func TestUsageIsNotPrintedTwice ( t * testing . T ) {
var cmd = & Command { Use : "root" }
var sub = & Command { Use : "sub" }
cmd . AddCommand ( sub )
2015-09-04 20:34:51 +00:00
2017-10-31 18:58:37 +00:00
output , _ := executeCommand ( cmd , "" )
if strings . Count ( output , "Usage:" ) != 1 {
t . Error ( "Usage output is not printed exactly once" )
2015-09-04 20:34:51 +00:00
}
}
2017-10-31 18:58:37 +00:00
func TestVisitParents ( t * testing . T ) {
c := & Command { Use : "app" }
sub := & Command { Use : "sub" }
dsub := & Command { Use : "dsub" }
sub . AddCommand ( dsub )
c . AddCommand ( sub )
total := 0
add := func ( x * Command ) {
total ++
}
sub . VisitParents ( add )
if total != 1 {
t . Errorf ( "Should have visited 1 parent but visited %d" , total )
}
total = 0
dsub . VisitParents ( add )
if total != 2 {
t . Errorf ( "Should have visited 2 parents but visited %d" , total )
}
total = 0
c . VisitParents ( add )
if total != 0 {
t . Errorf ( "Should have visited no parents but visited %d" , total )
2015-09-04 20:34:51 +00:00
}
}
2017-10-31 18:58:37 +00:00
func TestSuggestions ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
timesCmd := & Command {
Use : "times" ,
SuggestFor : [ ] string { "counts" } ,
Run : emptyRun ,
}
rootCmd . AddCommand ( timesCmd )
templateWithSuggestions := "Error: unknown command \"%s\" for \"root\"\n\nDid you mean this?\n\t%s\n\nRun 'root --help' for usage.\n"
templateWithoutSuggestions := "Error: unknown command \"%s\" for \"root\"\nRun 'root --help' for usage.\n"
tests := map [ string ] string {
"time" : "times" ,
"tiems" : "times" ,
"tims" : "times" ,
"timeS" : "times" ,
"rimes" : "times" ,
"ti" : "times" ,
"t" : "times" ,
"timely" : "times" ,
"ri" : "" ,
"timezone" : "" ,
"foo" : "" ,
"counts" : "times" ,
}
for typo , suggestion := range tests {
for _ , suggestionsDisabled := range [ ] bool { true , false } {
rootCmd . DisableSuggestions = suggestionsDisabled
var expected string
output , _ := executeCommand ( rootCmd , typo )
if suggestion == "" || suggestionsDisabled {
expected = fmt . Sprintf ( templateWithoutSuggestions , typo )
} else {
expected = fmt . Sprintf ( templateWithSuggestions , typo , suggestion )
}
if output != expected {
t . Errorf ( "Unexpected response.\nExpected:\n %q\nGot:\n %q\n" , expected , output )
}
}
}
}
2022-09-11 12:25:22 +00:00
func TestCaseInsensitive ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
childCmd := & Command { Use : "child" , Run : emptyRun , Aliases : [ ] string { "alternative" } }
granchildCmd := & Command { Use : "GRANDCHILD" , Run : emptyRun , Aliases : [ ] string { "ALIAS" } }
childCmd . AddCommand ( granchildCmd )
rootCmd . AddCommand ( childCmd )
tests := [ ] struct {
args [ ] string
failWithoutEnabling bool
} {
{
args : [ ] string { "child" } ,
failWithoutEnabling : false ,
} ,
{
args : [ ] string { "CHILD" } ,
failWithoutEnabling : true ,
} ,
{
args : [ ] string { "chILD" } ,
failWithoutEnabling : true ,
} ,
{
args : [ ] string { "CHIld" } ,
failWithoutEnabling : true ,
} ,
{
args : [ ] string { "alternative" } ,
failWithoutEnabling : false ,
} ,
{
args : [ ] string { "ALTERNATIVE" } ,
failWithoutEnabling : true ,
} ,
{
args : [ ] string { "ALTernatIVE" } ,
failWithoutEnabling : true ,
} ,
{
args : [ ] string { "alternatiVE" } ,
failWithoutEnabling : true ,
} ,
{
args : [ ] string { "child" , "GRANDCHILD" } ,
failWithoutEnabling : false ,
} ,
{
args : [ ] string { "child" , "grandchild" } ,
failWithoutEnabling : true ,
} ,
{
args : [ ] string { "CHIld" , "GRANdchild" } ,
failWithoutEnabling : true ,
} ,
{
args : [ ] string { "alternative" , "ALIAS" } ,
failWithoutEnabling : false ,
} ,
{
args : [ ] string { "alternative" , "alias" } ,
failWithoutEnabling : true ,
} ,
{
args : [ ] string { "CHILD" , "alias" } ,
failWithoutEnabling : true ,
} ,
{
args : [ ] string { "CHIld" , "aliAS" } ,
failWithoutEnabling : true ,
} ,
}
for _ , test := range tests {
for _ , enableCaseInsensitivity := range [ ] bool { true , false } {
EnableCaseInsensitive = enableCaseInsensitivity
output , err := executeCommand ( rootCmd , test . args ... )
expectedFailure := test . failWithoutEnabling && ! enableCaseInsensitivity
if ! expectedFailure && output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if ! expectedFailure && err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
}
}
EnableCaseInsensitive = defaultCaseInsensitive
}
// This test make sure we keep backwards-compatibility with respect
// to command names case sensitivity behavior.
func TestCaseSensitivityBackwardCompatibility ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
childCmd := & Command { Use : "child" , Run : emptyRun }
rootCmd . AddCommand ( childCmd )
_ , err := executeCommand ( rootCmd , strings . ToUpper ( childCmd . Use ) )
if err == nil {
t . Error ( "Expected error on calling a command in upper case while command names are case sensitive. Got nil." )
}
}
2017-10-31 18:58:37 +00:00
func TestRemoveCommand ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Args : NoArgs , Run : emptyRun }
childCmd := & Command { Use : "child" , Run : emptyRun }
rootCmd . AddCommand ( childCmd )
rootCmd . RemoveCommand ( childCmd )
_ , err := executeCommand ( rootCmd , "child" )
if err == nil {
t . Error ( "Expected error on calling removed command. Got nil." )
}
}
func TestReplaceCommandWithRemove ( t * testing . T ) {
childUsed := 0
rootCmd := & Command { Use : "root" , Run : emptyRun }
child1Cmd := & Command {
Use : "child" ,
Run : func ( * Command , [ ] string ) { childUsed = 1 } ,
}
child2Cmd := & Command {
Use : "child" ,
Run : func ( * Command , [ ] string ) { childUsed = 2 } ,
}
rootCmd . AddCommand ( child1Cmd )
rootCmd . RemoveCommand ( child1Cmd )
rootCmd . AddCommand ( child2Cmd )
output , err := executeCommand ( rootCmd , "child" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if childUsed == 1 {
t . Error ( "Removed command shouldn't be called" )
}
if childUsed != 2 {
t . Error ( "Replacing command should have been called but didn't" )
}
}
func TestDeprecatedCommand ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Run : emptyRun }
deprecatedCmd := & Command {
Use : "deprecated" ,
Deprecated : "This command is deprecated" ,
Run : emptyRun ,
}
rootCmd . AddCommand ( deprecatedCmd )
output , err := executeCommand ( rootCmd , "deprecated" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
2017-11-02 13:27:24 +00:00
checkStringContains ( t , output , deprecatedCmd . Deprecated )
2017-10-31 18:58:37 +00:00
}
func TestHooks ( t * testing . T ) {
var (
persPreArgs string
preArgs string
runArgs string
postArgs string
persPostArgs string
)
c := & Command {
Use : "c" ,
PersistentPreRun : func ( _ * Command , args [ ] string ) {
persPreArgs = strings . Join ( args , " " )
2015-03-11 18:52:35 +00:00
} ,
2017-10-31 18:58:37 +00:00
PreRun : func ( _ * Command , args [ ] string ) {
preArgs = strings . Join ( args , " " )
2015-03-11 18:52:35 +00:00
} ,
2017-10-31 18:58:37 +00:00
Run : func ( _ * Command , args [ ] string ) {
runArgs = strings . Join ( args , " " )
2015-03-11 18:52:35 +00:00
} ,
2017-10-31 18:58:37 +00:00
PostRun : func ( _ * Command , args [ ] string ) {
postArgs = strings . Join ( args , " " )
2015-03-11 18:52:35 +00:00
} ,
2017-10-31 18:58:37 +00:00
PersistentPostRun : func ( _ * Command , args [ ] string ) {
persPostArgs = strings . Join ( args , " " )
2015-03-11 18:52:35 +00:00
} ,
2017-10-31 18:58:37 +00:00
}
output , err := executeCommand ( c , "one" , "two" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
2021-02-08 00:08:50 +00:00
for _ , v := range [ ] struct {
name string
got string
} {
{ "persPreArgs" , persPreArgs } ,
{ "preArgs" , preArgs } ,
{ "runArgs" , runArgs } ,
{ "postArgs" , postArgs } ,
{ "persPostArgs" , persPostArgs } ,
} {
if v . got != onetwo {
t . Errorf ( "Expected %s %q, got %q" , v . name , onetwo , v . got )
}
2017-10-31 18:58:37 +00:00
}
}
func TestPersistentHooks ( t * testing . T ) {
2023-10-22 00:36:12 +00:00
EnableTraverseRunHooks = true
testPersistentHooks ( t , [ ] string {
"parent PersistentPreRun" ,
"child PersistentPreRun" ,
"child PreRun" ,
"child Run" ,
"child PostRun" ,
"child PersistentPostRun" ,
"parent PersistentPostRun" ,
} )
2017-10-31 18:58:37 +00:00
2023-10-22 00:36:12 +00:00
EnableTraverseRunHooks = false
testPersistentHooks ( t , [ ] string {
"child PersistentPreRun" ,
"child PreRun" ,
"child Run" ,
"child PostRun" ,
"child PersistentPostRun" ,
} )
}
func testPersistentHooks ( t * testing . T , expectedHookRunOrder [ ] string ) {
var hookRunOrder [ ] string
validateHook := func ( args [ ] string , hookName string ) {
hookRunOrder = append ( hookRunOrder , hookName )
got := strings . Join ( args , " " )
if onetwo != got {
t . Errorf ( "Expected %s %q, got %q" , hookName , onetwo , got )
}
}
2017-10-31 18:58:37 +00:00
parentCmd := & Command {
Use : "parent" ,
PersistentPreRun : func ( _ * Command , args [ ] string ) {
2023-10-22 00:36:12 +00:00
validateHook ( args , "parent PersistentPreRun" )
2015-03-11 18:52:35 +00:00
} ,
2017-10-31 18:58:37 +00:00
PreRun : func ( _ * Command , args [ ] string ) {
2023-10-22 00:36:12 +00:00
validateHook ( args , "parent PreRun" )
2015-03-11 18:52:35 +00:00
} ,
2017-10-31 18:58:37 +00:00
Run : func ( _ * Command , args [ ] string ) {
2023-10-22 00:36:12 +00:00
validateHook ( args , "parent Run" )
2015-03-11 18:52:35 +00:00
} ,
2017-10-31 18:58:37 +00:00
PostRun : func ( _ * Command , args [ ] string ) {
2023-10-22 00:36:12 +00:00
validateHook ( args , "parent PostRun" )
2015-03-11 18:52:35 +00:00
} ,
2017-10-31 18:58:37 +00:00
PersistentPostRun : func ( _ * Command , args [ ] string ) {
2023-10-22 00:36:12 +00:00
validateHook ( args , "parent PersistentPostRun" )
2015-03-11 18:52:35 +00:00
} ,
2017-10-31 18:58:37 +00:00
}
childCmd := & Command {
Use : "child" ,
PersistentPreRun : func ( _ * Command , args [ ] string ) {
2023-10-22 00:36:12 +00:00
validateHook ( args , "child PersistentPreRun" )
2015-03-11 18:52:35 +00:00
} ,
2017-10-31 18:58:37 +00:00
PreRun : func ( _ * Command , args [ ] string ) {
2023-10-22 00:36:12 +00:00
validateHook ( args , "child PreRun" )
2015-03-16 19:47:32 +00:00
} ,
2017-10-31 18:58:37 +00:00
Run : func ( _ * Command , args [ ] string ) {
2023-10-22 00:36:12 +00:00
validateHook ( args , "child Run" )
2017-10-31 18:58:37 +00:00
} ,
PostRun : func ( _ * Command , args [ ] string ) {
2023-10-22 00:36:12 +00:00
validateHook ( args , "child PostRun" )
2017-10-31 18:58:37 +00:00
} ,
PersistentPostRun : func ( _ * Command , args [ ] string ) {
2023-10-22 00:36:12 +00:00
validateHook ( args , "child PersistentPostRun" )
2015-03-16 19:47:32 +00:00
} ,
2015-03-11 18:52:35 +00:00
}
2017-10-31 18:58:37 +00:00
parentCmd . AddCommand ( childCmd )
2015-03-11 18:52:35 +00:00
2017-10-31 18:58:37 +00:00
output , err := executeCommand ( parentCmd , "child" , "one" , "two" )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
2023-10-22 00:36:12 +00:00
for idx , exp := range expectedHookRunOrder {
if len ( hookRunOrder ) > idx {
if act := hookRunOrder [ idx ] ; act != exp {
t . Errorf ( "Expected %q at %d, got %q" , exp , idx , act )
}
} else {
t . Errorf ( "Expected %q at %d, got nothing" , exp , idx )
2021-02-08 00:08:50 +00:00
}
2017-10-31 18:58:37 +00:00
}
}
2015-03-11 18:52:35 +00:00
2017-10-31 18:58:37 +00:00
// Related to https://github.com/spf13/cobra/issues/521.
func TestGlobalNormFuncPropagation ( t * testing . T ) {
normFunc := func ( f * pflag . FlagSet , name string ) pflag . NormalizedName {
return pflag . NormalizedName ( name )
}
2015-03-11 18:52:35 +00:00
2017-10-31 18:58:37 +00:00
rootCmd := & Command { Use : "root" , Run : emptyRun }
childCmd := & Command { Use : "child" , Run : emptyRun }
rootCmd . AddCommand ( childCmd )
rootCmd . SetGlobalNormalizationFunc ( normFunc )
if reflect . ValueOf ( normFunc ) . Pointer ( ) != reflect . ValueOf ( rootCmd . GlobalNormalizationFunc ( ) ) . Pointer ( ) {
t . Error ( "rootCmd seems to have a wrong normalization function" )
}
if reflect . ValueOf ( normFunc ) . Pointer ( ) != reflect . ValueOf ( childCmd . GlobalNormalizationFunc ( ) ) . Pointer ( ) {
t . Error ( "childCmd should have had the normalization function of rootCmd" )
2015-03-11 18:52:35 +00:00
}
}
2016-06-04 00:25:52 +00:00
2017-10-31 18:58:37 +00:00
// Related to https://github.com/spf13/cobra/issues/521.
func TestNormPassedOnLocal ( t * testing . T ) {
toUpper := func ( f * pflag . FlagSet , name string ) pflag . NormalizedName {
return pflag . NormalizedName ( strings . ToUpper ( name ) )
2016-06-04 00:25:52 +00:00
}
2017-10-31 18:58:37 +00:00
c := & Command { }
c . Flags ( ) . Bool ( "flagname" , true , "this is a dummy flag" )
c . SetGlobalNormalizationFunc ( toUpper )
if c . LocalFlags ( ) . Lookup ( "flagname" ) != c . LocalFlags ( ) . Lookup ( "FLAGNAME" ) {
t . Error ( "Normalization function should be passed on to Local flag set" )
}
}
// Related to https://github.com/spf13/cobra/issues/521.
func TestNormPassedOnInherited ( t * testing . T ) {
toUpper := func ( f * pflag . FlagSet , name string ) pflag . NormalizedName {
return pflag . NormalizedName ( strings . ToUpper ( name ) )
2016-06-04 00:25:52 +00:00
}
2017-10-31 18:58:37 +00:00
c := & Command { }
c . SetGlobalNormalizationFunc ( toUpper )
child1 := & Command { }
c . AddCommand ( child1 )
c . PersistentFlags ( ) . Bool ( "flagname" , true , "" )
child2 := & Command { }
c . AddCommand ( child2 )
inherited := child1 . InheritedFlags ( )
if inherited . Lookup ( "flagname" ) == nil || inherited . Lookup ( "flagname" ) != inherited . Lookup ( "FLAGNAME" ) {
t . Error ( "Normalization function should be passed on to inherited flag set in command added before flag" )
}
inherited = child2 . InheritedFlags ( )
if inherited . Lookup ( "flagname" ) == nil || inherited . Lookup ( "flagname" ) != inherited . Lookup ( "FLAGNAME" ) {
t . Error ( "Normalization function should be passed on to inherited flag set in command added after flag" )
2016-06-04 00:25:52 +00:00
}
}
2016-06-14 14:04:53 +00:00
2017-10-31 18:58:37 +00:00
// Related to https://github.com/spf13/cobra/issues/521.
func TestConsistentNormalizedName ( t * testing . T ) {
toUpper := func ( f * pflag . FlagSet , name string ) pflag . NormalizedName {
return pflag . NormalizedName ( strings . ToUpper ( name ) )
}
n := func ( f * pflag . FlagSet , name string ) pflag . NormalizedName {
return pflag . NormalizedName ( name )
}
c := & Command { }
c . Flags ( ) . Bool ( "flagname" , true , "" )
c . SetGlobalNormalizationFunc ( toUpper )
c . SetGlobalNormalizationFunc ( n )
if c . LocalFlags ( ) . Lookup ( "flagname" ) == c . LocalFlags ( ) . Lookup ( "FLAGNAME" ) {
t . Error ( "Normalizing flag names should not result in duplicate flags" )
}
}
func TestFlagOnPflagCommandLine ( t * testing . T ) {
flagName := "flagOnCommandLine"
pflag . String ( flagName , "" , "about my flag" )
2016-05-31 22:38:12 +00:00
2017-10-31 18:58:37 +00:00
c := & Command { Use : "c" , Run : emptyRun }
c . AddCommand ( & Command { Use : "child" , Run : emptyRun } )
output , _ := executeCommand ( c , "--help" )
2017-11-02 13:27:24 +00:00
checkStringContains ( t , output , flagName )
2017-10-31 18:58:37 +00:00
resetCommandLineFlagSet ( )
}
// TestHiddenCommandExecutes checks,
// if hidden commands run as intended.
func TestHiddenCommandExecutes ( t * testing . T ) {
executed := false
c := & Command {
Use : "c" ,
Hidden : true ,
Run : func ( * Command , [ ] string ) { executed = true } ,
}
output , err := executeCommand ( c )
if output != "" {
t . Errorf ( "Unexpected output: %v" , output )
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if ! executed {
t . Error ( "Hidden command should have been executed" )
}
}
// test to ensure hidden commands do not show up in usage/help text
func TestHiddenCommandIsHidden ( t * testing . T ) {
c := & Command { Use : "c" , Hidden : true , Run : emptyRun }
if c . IsAvailableCommand ( ) {
t . Errorf ( "Hidden command should be unavailable" )
2016-05-31 22:38:12 +00:00
}
}
2016-06-14 14:04:53 +00:00
func TestCommandsAreSorted ( t * testing . T ) {
EnableCommandSorting = true
originalNames := [ ] string { "middle" , "zlast" , "afirst" }
expectedNames := [ ] string { "afirst" , "middle" , "zlast" }
2017-10-31 18:58:37 +00:00
var rootCmd = & Command { Use : "root" }
2016-06-14 14:04:53 +00:00
2016-08-20 07:09:46 +00:00
for _ , name := range originalNames {
2017-10-31 18:58:37 +00:00
rootCmd . AddCommand ( & Command { Use : name } )
2016-06-14 14:04:53 +00:00
}
2017-10-31 18:58:37 +00:00
for i , c := range rootCmd . Commands ( ) {
got := c . Name ( )
if expectedNames [ i ] != got {
t . Errorf ( "Expected: %s, got: %s" , expectedNames [ i ] , got )
2016-06-14 14:04:53 +00:00
}
}
2022-09-11 12:25:22 +00:00
EnableCommandSorting = defaultCommandSorting
2016-06-14 14:04:53 +00:00
}
func TestEnableCommandSortingIsDisabled ( t * testing . T ) {
EnableCommandSorting = false
originalNames := [ ] string { "middle" , "zlast" , "afirst" }
2017-10-31 18:58:37 +00:00
var rootCmd = & Command { Use : "root" }
2016-06-14 14:04:53 +00:00
2016-08-20 07:09:46 +00:00
for _ , name := range originalNames {
2017-10-31 18:58:37 +00:00
rootCmd . AddCommand ( & Command { Use : name } )
2016-06-14 14:04:53 +00:00
}
2017-10-31 18:58:37 +00:00
for i , c := range rootCmd . Commands ( ) {
got := c . Name ( )
if originalNames [ i ] != got {
t . Errorf ( "expected: %s, got: %s" , originalNames [ i ] , got )
2016-06-14 14:04:53 +00:00
}
}
2022-09-11 12:25:22 +00:00
EnableCommandSorting = defaultCommandSorting
2016-06-14 14:04:53 +00:00
}
2016-05-25 21:27:02 +00:00
2022-10-10 20:59:11 +00:00
func TestUsageWithGroup ( t * testing . T ) {
var rootCmd = & Command { Use : "root" , Short : "test" , Run : emptyRun }
rootCmd . CompletionOptions . DisableDefaultCmd = true
rootCmd . AddGroup ( & Group { ID : "group1" , Title : "group1" } )
rootCmd . AddGroup ( & Group { ID : "group2" , Title : "group2" } )
rootCmd . AddCommand ( & Command { Use : "cmd1" , GroupID : "group1" , Run : emptyRun } )
rootCmd . AddCommand ( & Command { Use : "cmd2" , GroupID : "group2" , Run : emptyRun } )
output , err := executeCommand ( rootCmd , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
// help should be ungrouped here
checkStringContains ( t , output , "\nAdditional Commands:\n help" )
checkStringContains ( t , output , "\ngroup1\n cmd1" )
checkStringContains ( t , output , "\ngroup2\n cmd2" )
}
func TestUsageHelpGroup ( t * testing . T ) {
var rootCmd = & Command { Use : "root" , Short : "test" , Run : emptyRun }
rootCmd . CompletionOptions . DisableDefaultCmd = true
rootCmd . AddGroup ( & Group { ID : "group" , Title : "group" } )
rootCmd . AddCommand ( & Command { Use : "xxx" , GroupID : "group" , Run : emptyRun } )
rootCmd . SetHelpCommandGroupID ( "group" )
output , err := executeCommand ( rootCmd , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
// now help should be grouped under "group"
checkStringOmits ( t , output , "\nAdditional Commands:\n help" )
checkStringContains ( t , output , "\ngroup\n help" )
}
func TestUsageCompletionGroup ( t * testing . T ) {
var rootCmd = & Command { Use : "root" , Short : "test" , Run : emptyRun }
rootCmd . AddGroup ( & Group { ID : "group" , Title : "group" } )
rootCmd . AddGroup ( & Group { ID : "help" , Title : "help" } )
rootCmd . AddCommand ( & Command { Use : "xxx" , GroupID : "group" , Run : emptyRun } )
rootCmd . SetHelpCommandGroupID ( "help" )
rootCmd . SetCompletionCommandGroupID ( "group" )
output , err := executeCommand ( rootCmd , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
// now completion should be grouped under "group"
checkStringOmits ( t , output , "\nAdditional Commands:\n completion" )
checkStringContains ( t , output , "\ngroup\n completion" )
}
func TestUngroupedCommand ( t * testing . T ) {
var rootCmd = & Command { Use : "root" , Short : "test" , Run : emptyRun }
rootCmd . AddGroup ( & Group { ID : "group" , Title : "group" } )
rootCmd . AddGroup ( & Group { ID : "help" , Title : "help" } )
rootCmd . AddCommand ( & Command { Use : "xxx" , GroupID : "group" , Run : emptyRun } )
rootCmd . SetHelpCommandGroupID ( "help" )
rootCmd . SetCompletionCommandGroupID ( "group" )
// Add a command without a group
rootCmd . AddCommand ( & Command { Use : "yyy" , Run : emptyRun } )
output , err := executeCommand ( rootCmd , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
// The yyy command should be in the additional command "group"
checkStringContains ( t , output , "\nAdditional Commands:\n yyy" )
}
func TestAddGroup ( t * testing . T ) {
var rootCmd = & Command { Use : "root" , Short : "test" , Run : emptyRun }
rootCmd . AddGroup ( & Group { ID : "group" , Title : "Test group" } )
rootCmd . AddCommand ( & Command { Use : "cmd" , GroupID : "group" , Run : emptyRun } )
output , err := executeCommand ( rootCmd , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , "\nTest group\n cmd" )
}
2022-10-24 15:11:57 +00:00
func TestWrongGroupFirstLevel ( t * testing . T ) {
var rootCmd = & Command { Use : "root" , Short : "test" , Run : emptyRun }
rootCmd . AddGroup ( & Group { ID : "group" , Title : "Test group" } )
// Use the wrong group ID
rootCmd . AddCommand ( & Command { Use : "cmd" , GroupID : "wrong" , Run : emptyRun } )
defer func ( ) {
if recover ( ) == nil {
t . Errorf ( "The code should have panicked due to a missing group" )
}
} ( )
_ , err := executeCommand ( rootCmd , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
}
func TestWrongGroupNestedLevel ( t * testing . T ) {
var rootCmd = & Command { Use : "root" , Short : "test" , Run : emptyRun }
var childCmd = & Command { Use : "child" , Run : emptyRun }
rootCmd . AddCommand ( childCmd )
childCmd . AddGroup ( & Group { ID : "group" , Title : "Test group" } )
// Use the wrong group ID
childCmd . AddCommand ( & Command { Use : "cmd" , GroupID : "wrong" , Run : emptyRun } )
defer func ( ) {
if recover ( ) == nil {
t . Errorf ( "The code should have panicked due to a missing group" )
}
} ( )
_ , err := executeCommand ( rootCmd , "child" , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
}
func TestWrongGroupForHelp ( t * testing . T ) {
var rootCmd = & Command { Use : "root" , Short : "test" , Run : emptyRun }
var childCmd = & Command { Use : "child" , Run : emptyRun }
rootCmd . AddCommand ( childCmd )
rootCmd . AddGroup ( & Group { ID : "group" , Title : "Test group" } )
// Use the wrong group ID
rootCmd . SetHelpCommandGroupID ( "wrong" )
defer func ( ) {
if recover ( ) == nil {
t . Errorf ( "The code should have panicked due to a missing group" )
}
} ( )
_ , err := executeCommand ( rootCmd , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
}
func TestWrongGroupForCompletion ( t * testing . T ) {
var rootCmd = & Command { Use : "root" , Short : "test" , Run : emptyRun }
var childCmd = & Command { Use : "child" , Run : emptyRun }
rootCmd . AddCommand ( childCmd )
rootCmd . AddGroup ( & Group { ID : "group" , Title : "Test group" } )
// Use the wrong group ID
rootCmd . SetCompletionCommandGroupID ( "wrong" )
defer func ( ) {
if recover ( ) == nil {
t . Errorf ( "The code should have panicked due to a missing group" )
}
} ( )
_ , err := executeCommand ( rootCmd , "--help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
}
2017-04-02 14:14:34 +00:00
func TestSetOutput ( t * testing . T ) {
2017-10-31 18:58:37 +00:00
c := & Command { }
c . SetOutput ( nil )
if out := c . OutOrStdout ( ) ; out != os . Stdout {
t . Errorf ( "Expected setting output to nil to revert back to stdout" )
2017-04-02 14:14:34 +00:00
}
}
2019-04-30 17:41:56 +00:00
func TestSetOut ( t * testing . T ) {
c := & Command { }
c . SetOut ( nil )
if out := c . OutOrStdout ( ) ; out != os . Stdout {
t . Errorf ( "Expected setting output to nil to revert back to stdout" )
}
}
func TestSetErr ( t * testing . T ) {
c := & Command { }
c . SetErr ( nil )
if out := c . ErrOrStderr ( ) ; out != os . Stderr {
t . Errorf ( "Expected setting error to nil to revert back to stderr" )
}
}
func TestSetIn ( t * testing . T ) {
c := & Command { }
c . SetIn ( nil )
if out := c . InOrStdin ( ) ; out != os . Stdin {
t . Errorf ( "Expected setting input to nil to revert back to stdin" )
}
}
2019-05-15 16:49:16 +00:00
func TestUsageStringRedirected ( t * testing . T ) {
c := & Command { }
c . usageFunc = func ( cmd * Command ) error {
cmd . Print ( "[stdout1]" )
cmd . PrintErr ( "[stderr2]" )
cmd . Print ( "[stdout3]" )
2019-05-15 16:53:39 +00:00
return nil
2019-05-15 16:49:16 +00:00
}
expected := "[stdout1][stderr2][stdout3]"
2019-05-15 16:53:39 +00:00
if got := c . UsageString ( ) ; got != expected {
2019-05-15 16:49:16 +00:00
t . Errorf ( "Expected usage string to consider both stdout and stderr" )
}
}
2020-10-01 15:28:00 +00:00
func TestCommandPrintRedirection ( t * testing . T ) {
errBuff , outBuff := bytes . NewBuffer ( nil ) , bytes . NewBuffer ( nil )
root := & Command {
Run : func ( cmd * Command , args [ ] string ) {
cmd . PrintErr ( "PrintErr" )
cmd . PrintErrln ( "PrintErr" , "line" )
cmd . PrintErrf ( "PrintEr%s" , "r" )
cmd . Print ( "Print" )
cmd . Println ( "Print" , "line" )
cmd . Printf ( "Prin%s" , "t" )
} ,
}
root . SetErr ( errBuff )
root . SetOut ( outBuff )
if err := root . Execute ( ) ; err != nil {
t . Error ( err )
}
2024-03-12 10:42:46 +00:00
gotErrBytes , err := io . ReadAll ( errBuff )
2020-10-01 15:28:00 +00:00
if err != nil {
t . Error ( err )
}
2024-03-12 10:42:46 +00:00
gotOutBytes , err := io . ReadAll ( outBuff )
2020-10-01 15:28:00 +00:00
if err != nil {
t . Error ( err )
}
if wantErr := [ ] byte ( "PrintErrPrintErr line\nPrintErr" ) ; ! bytes . Equal ( gotErrBytes , wantErr ) {
t . Errorf ( "got: '%s' want: '%s'" , gotErrBytes , wantErr )
}
if wantOut := [ ] byte ( "PrintPrint line\nPrint" ) ; ! bytes . Equal ( gotOutBytes , wantOut ) {
t . Errorf ( "got: '%s' want: '%s'" , gotOutBytes , wantOut )
}
}
2016-05-25 21:27:02 +00:00
func TestFlagErrorFunc ( t * testing . T ) {
2017-10-31 18:58:37 +00:00
c := & Command { Use : "c" , Run : emptyRun }
2016-05-25 21:27:02 +00:00
2017-10-31 18:58:37 +00:00
expectedFmt := "This is expected: %v"
c . SetFlagErrorFunc ( func ( _ * Command , err error ) error {
2016-05-25 21:27:02 +00:00
return fmt . Errorf ( expectedFmt , err )
} )
2017-10-31 18:58:37 +00:00
_ , err := executeCommand ( c , "--unknown-flag" )
2016-05-25 21:27:02 +00:00
2017-10-31 18:58:37 +00:00
got := err . Error ( )
expected := fmt . Sprintf ( expectedFmt , "unknown flag: --unknown-flag" )
if got != expected {
t . Errorf ( "Expected %v, got %v" , expected , got )
2016-05-25 21:27:02 +00:00
}
}
2017-04-19 11:59:20 +00:00
2022-06-21 02:02:33 +00:00
func TestFlagErrorFuncHelp ( t * testing . T ) {
c := & Command { Use : "c" , Run : emptyRun }
c . PersistentFlags ( ) . Bool ( "help" , false , "help for c" )
c . SetFlagErrorFunc ( func ( _ * Command , err error ) error {
return fmt . Errorf ( "wrap error: %w" , err )
} )
out , err := executeCommand ( c , "--help" )
if err != nil {
t . Errorf ( "--help should not fail: %v" , err )
}
expected := ` Usage :
c [ flags ]
Flags :
-- help help for c
`
if out != expected {
t . Errorf ( "Expected: %v, got: %v" , expected , out )
}
out , err = executeCommand ( c , "-h" )
if err != nil {
t . Errorf ( "-h should not fail: %v" , err )
}
if out != expected {
t . Errorf ( "Expected: %v, got: %v" , expected , out )
}
}
2017-04-19 11:59:20 +00:00
// TestSortedFlags checks,
// if cmd.LocalFlags() is unsorted when cmd.Flags().SortFlags set to false.
2017-05-12 18:22:26 +00:00
// Related to https://github.com/spf13/cobra/issues/404.
2017-04-19 11:59:20 +00:00
func TestSortedFlags ( t * testing . T ) {
2017-10-31 18:58:37 +00:00
c := & Command { }
c . Flags ( ) . SortFlags = false
2017-04-19 11:59:20 +00:00
names := [ ] string { "C" , "B" , "A" , "D" }
for _ , name := range names {
2017-10-31 18:58:37 +00:00
c . Flags ( ) . Bool ( name , false , "" )
2017-04-19 11:59:20 +00:00
}
i := 0
2017-10-31 18:58:37 +00:00
c . LocalFlags ( ) . VisitAll ( func ( f * pflag . Flag ) {
2017-04-19 11:59:20 +00:00
if i == len ( names ) {
return
}
2017-10-31 18:58:37 +00:00
if stringInSlice ( f . Name , names ) {
2017-04-19 11:59:20 +00:00
if names [ i ] != f . Name {
t . Errorf ( "Incorrect order. Expected %v, got %v" , names [ i ] , f . Name )
}
i ++
}
} )
}
2017-05-12 18:22:26 +00:00
// TestMergeCommandLineToFlags checks,
// if pflag.CommandLine is correctly merged to c.Flags() after first call
// of c.mergePersistentFlags.
// Related to https://github.com/spf13/cobra/issues/443.
func TestMergeCommandLineToFlags ( t * testing . T ) {
pflag . Bool ( "boolflag" , false , "" )
2017-10-31 18:58:37 +00:00
c := & Command { Use : "c" , Run : emptyRun }
2017-05-12 18:22:26 +00:00
c . mergePersistentFlags ( )
if c . Flags ( ) . Lookup ( "boolflag" ) == nil {
t . Fatal ( "Expecting to have flag from CommandLine in c.Flags()" )
}
2017-10-31 18:58:37 +00:00
resetCommandLineFlagSet ( )
2017-05-12 18:22:26 +00:00
}
2017-06-13 08:33:50 +00:00
// TestUseDeprecatedFlags checks,
// if cobra.Execute() prints a message, if a deprecated flag is used.
// Related to https://github.com/spf13/cobra/issues/463.
func TestUseDeprecatedFlags ( t * testing . T ) {
2017-10-31 18:58:37 +00:00
c := & Command { Use : "c" , Run : emptyRun }
2017-06-13 08:33:50 +00:00
c . Flags ( ) . BoolP ( "deprecated" , "d" , false , "deprecated flag" )
2021-02-08 00:08:50 +00:00
assertNoErr ( t , c . Flags ( ) . MarkDeprecated ( "deprecated" , "This flag is deprecated" ) )
2017-06-13 08:33:50 +00:00
2017-10-31 18:58:37 +00:00
output , err := executeCommand ( c , "c" , "-d" )
if err != nil {
2017-06-29 10:52:34 +00:00
t . Error ( "Unexpected error:" , err )
}
2017-11-02 13:27:24 +00:00
checkStringContains ( t , output , "This flag is deprecated" )
2017-06-13 08:33:50 +00:00
}
2017-10-07 21:29:11 +00:00
func TestTraverseWithParentFlags ( t * testing . T ) {
2017-10-31 18:58:37 +00:00
rootCmd := & Command { Use : "root" , TraverseChildren : true }
rootCmd . Flags ( ) . String ( "str" , "" , "" )
rootCmd . Flags ( ) . BoolP ( "bool" , "b" , false , "" )
2017-10-07 21:29:11 +00:00
2017-10-31 18:58:37 +00:00
childCmd := & Command { Use : "child" }
childCmd . Flags ( ) . Int ( "int" , - 1 , "" )
2017-10-07 21:29:11 +00:00
2017-10-31 18:58:37 +00:00
rootCmd . AddCommand ( childCmd )
c , args , err := rootCmd . Traverse ( [ ] string { "-b" , "--str" , "ok" , "child" , "--int" } )
2017-10-07 21:29:11 +00:00
if err != nil {
2017-10-31 18:58:37 +00:00
t . Errorf ( "Unexpected error: %v" , err )
2017-10-07 21:29:11 +00:00
}
2024-09-14 17:31:57 +00:00
if len ( args ) != 1 || args [ 0 ] != "--int" {
2017-10-31 18:58:37 +00:00
t . Errorf ( "Wrong args: %v" , args )
2017-10-07 21:29:11 +00:00
}
2017-10-31 18:58:37 +00:00
if c . Name ( ) != childCmd . Name ( ) {
t . Errorf ( "Expected command: %q, got: %q" , childCmd . Name ( ) , c . Name ( ) )
2017-10-07 21:29:11 +00:00
}
}
2024-09-14 17:31:57 +00:00
func TestTraverseWithShorthandCombinationInParentFlags ( t * testing . T ) {
rootCmd := & Command { Use : "root" , TraverseChildren : true }
stringVal := rootCmd . Flags ( ) . StringP ( "str" , "s" , "" , "" )
boolVal := rootCmd . Flags ( ) . BoolP ( "bool" , "b" , false , "" )
childCmd := & Command { Use : "child" }
childCmd . Flags ( ) . Int ( "int" , - 1 , "" )
rootCmd . AddCommand ( childCmd )
c , args , err := rootCmd . Traverse ( [ ] string { "-bs" , "ok" , "child" , "--int" } )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if len ( args ) != 1 || args [ 0 ] != "--int" {
t . Errorf ( "Wrong args: %v" , args )
}
if c . Name ( ) != childCmd . Name ( ) {
t . Errorf ( "Expected command: %q, got: %q" , childCmd . Name ( ) , c . Name ( ) )
}
if * stringVal != "ok" {
t . Errorf ( "Expected -s to be set to: %s, got: %s" , "ok" , * stringVal )
}
if ! * boolVal {
t . Errorf ( "Expected -b to be set" )
}
}
func TestTraverseWithArgumentIdenticalToCommandName ( t * testing . T ) {
rootCmd := & Command { Use : "root" , TraverseChildren : true }
stringVal := rootCmd . Flags ( ) . StringP ( "str" , "s" , "" , "" )
boolVal := rootCmd . Flags ( ) . BoolP ( "bool" , "b" , false , "" )
childCmd := & Command { Use : "child" }
childCmd . Flags ( ) . Int ( "int" , - 1 , "" )
rootCmd . AddCommand ( childCmd )
c , args , err := rootCmd . Traverse ( [ ] string { "-bs" , "child" , "child" , "--int" } )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if len ( args ) != 1 || args [ 0 ] != "--int" {
t . Errorf ( "Wrong args: %v" , args )
}
if c . Name ( ) != childCmd . Name ( ) {
t . Errorf ( "Expected command: %q, got: %q" , childCmd . Name ( ) , c . Name ( ) )
}
if * stringVal != "child" {
t . Errorf ( "Expected -s to be set to: %s, got: %s" , "child" , * stringVal )
}
if ! * boolVal {
t . Errorf ( "Expected -b to be set" )
}
}
2017-10-07 21:29:11 +00:00
func TestTraverseNoParentFlags ( t * testing . T ) {
2017-10-31 18:58:37 +00:00
rootCmd := & Command { Use : "root" , TraverseChildren : true }
rootCmd . Flags ( ) . String ( "foo" , "" , "foo things" )
2017-10-07 21:29:11 +00:00
2017-10-31 18:58:37 +00:00
childCmd := & Command { Use : "child" }
childCmd . Flags ( ) . String ( "str" , "" , "" )
rootCmd . AddCommand ( childCmd )
2017-10-07 21:29:11 +00:00
2017-10-31 18:58:37 +00:00
c , args , err := rootCmd . Traverse ( [ ] string { "child" } )
2017-10-07 21:29:11 +00:00
if err != nil {
2017-10-31 18:58:37 +00:00
t . Errorf ( "Unexpected error: %v" , err )
2017-10-07 21:29:11 +00:00
}
if len ( args ) != 0 {
2017-10-31 18:58:37 +00:00
t . Errorf ( "Wrong args %v" , args )
2017-10-07 21:29:11 +00:00
}
2017-10-31 18:58:37 +00:00
if c . Name ( ) != childCmd . Name ( ) {
t . Errorf ( "Expected command: %q, got: %q" , childCmd . Name ( ) , c . Name ( ) )
2017-10-07 21:29:11 +00:00
}
}
func TestTraverseWithBadParentFlags ( t * testing . T ) {
2017-10-31 18:58:37 +00:00
rootCmd := & Command { Use : "root" , TraverseChildren : true }
childCmd := & Command { Use : "child" }
childCmd . Flags ( ) . String ( "str" , "" , "" )
rootCmd . AddCommand ( childCmd )
2017-10-07 21:29:11 +00:00
2017-10-31 18:58:37 +00:00
expected := "unknown flag: --str"
2017-10-07 21:29:11 +00:00
2017-10-31 18:58:37 +00:00
c , _ , err := rootCmd . Traverse ( [ ] string { "--str" , "ok" , "child" } )
if err == nil || ! strings . Contains ( err . Error ( ) , expected ) {
t . Errorf ( "Expected error, %q, got %q" , expected , err )
2017-10-07 21:29:11 +00:00
}
if c != nil {
2017-10-31 18:58:37 +00:00
t . Errorf ( "Expected nil command" )
2017-10-07 21:29:11 +00:00
}
}
func TestTraverseWithBadChildFlag ( t * testing . T ) {
2017-10-31 18:58:37 +00:00
rootCmd := & Command { Use : "root" , TraverseChildren : true }
rootCmd . Flags ( ) . String ( "str" , "" , "" )
2017-10-07 21:29:11 +00:00
2017-10-31 18:58:37 +00:00
childCmd := & Command { Use : "child" }
rootCmd . AddCommand ( childCmd )
2017-10-07 21:29:11 +00:00
// Expect no error because the last commands args shouldn't be parsed in
2017-10-31 18:58:37 +00:00
// Traverse.
c , args , err := rootCmd . Traverse ( [ ] string { "child" , "--str" } )
2017-10-07 21:29:11 +00:00
if err != nil {
2017-10-31 18:58:37 +00:00
t . Errorf ( "Unexpected error: %v" , err )
2017-10-07 21:29:11 +00:00
}
2024-09-14 17:31:57 +00:00
if len ( args ) != 1 || args [ 0 ] != "--str" {
2017-10-31 18:58:37 +00:00
t . Errorf ( "Wrong args: %v" , args )
2017-10-07 21:29:11 +00:00
}
2017-10-31 18:58:37 +00:00
if c . Name ( ) != childCmd . Name ( ) {
t . Errorf ( "Expected command %q, got: %q" , childCmd . Name ( ) , c . Name ( ) )
2017-10-07 21:29:11 +00:00
}
}
2017-10-10 03:44:33 +00:00
2017-10-12 18:25:33 +00:00
func TestTraverseWithTwoSubcommands ( t * testing . T ) {
2017-10-31 18:58:37 +00:00
rootCmd := & Command { Use : "root" , TraverseChildren : true }
2017-10-12 18:25:33 +00:00
2017-10-31 18:58:37 +00:00
subCmd := & Command { Use : "sub" , TraverseChildren : true }
rootCmd . AddCommand ( subCmd )
2017-10-12 18:25:33 +00:00
2017-10-31 18:58:37 +00:00
subsubCmd := & Command {
2017-10-12 18:25:33 +00:00
Use : "subsub" ,
}
2017-10-31 18:58:37 +00:00
subCmd . AddCommand ( subsubCmd )
2017-10-12 18:25:33 +00:00
2017-10-31 18:58:37 +00:00
c , _ , err := rootCmd . Traverse ( [ ] string { "sub" , "subsub" } )
2017-10-12 18:25:33 +00:00
if err != nil {
2017-10-31 18:58:37 +00:00
t . Fatalf ( "Unexpected error: %v" , err )
2017-10-10 03:44:33 +00:00
}
2017-10-31 18:58:37 +00:00
if c . Name ( ) != subsubCmd . Name ( ) {
t . Fatalf ( "Expected command: %q, got %q" , subsubCmd . Name ( ) , c . Name ( ) )
2017-10-10 03:44:33 +00:00
}
}
2017-10-12 16:50:22 +00:00
// TestUpdateName checks if c.Name() updates on changed c.Use.
// Related to https://github.com/spf13/cobra/pull/422#discussion_r143918343.
func TestUpdateName ( t * testing . T ) {
c := & Command { Use : "name xyz" }
originalName := c . Name ( )
c . Use = "changedName abc"
if originalName == c . Name ( ) || c . Name ( ) != "changedName" {
t . Error ( "c.Name() should be updated on changed c.Use" )
}
}
2018-02-04 16:58:53 +00:00
type calledAsTestcase struct {
args [ ] string
call string
want string
epm bool
}
func ( tc * calledAsTestcase ) test ( t * testing . T ) {
defer func ( ov bool ) { EnablePrefixMatching = ov } ( EnablePrefixMatching )
EnablePrefixMatching = tc . epm
var called * Command
run := func ( c * Command , _ [ ] string ) { t . Logf ( "called: %q" , c . Name ( ) ) ; called = c }
parent := & Command { Use : "parent" , Run : run }
child1 := & Command { Use : "child1" , Run : run , Aliases : [ ] string { "this" } }
child2 := & Command { Use : "child2" , Run : run , Aliases : [ ] string { "that" } }
parent . AddCommand ( child1 )
parent . AddCommand ( child2 )
parent . SetArgs ( tc . args )
output := new ( bytes . Buffer )
2020-04-06 17:36:04 +00:00
parent . SetOut ( output )
parent . SetErr ( output )
2018-02-04 16:58:53 +00:00
2021-02-08 00:08:50 +00:00
_ = parent . Execute ( )
2018-02-04 16:58:53 +00:00
if called == nil {
if tc . call != "" {
t . Errorf ( "missing expected call to command: %s" , tc . call )
}
return
}
if called . Name ( ) != tc . call {
t . Errorf ( "called command == %q; Wanted %q" , called . Name ( ) , tc . call )
} else if got := called . CalledAs ( ) ; got != tc . want {
t . Errorf ( "%s.CalledAs() == %q; Wanted: %q" , tc . call , got , tc . want )
}
}
func TestCalledAs ( t * testing . T ) {
tests := map [ string ] calledAsTestcase {
2021-02-08 00:08:50 +00:00
"find/no-args" : { nil , "parent" , "parent" , false } ,
"find/real-name" : { [ ] string { "child1" } , "child1" , "child1" , false } ,
"find/full-alias" : { [ ] string { "that" } , "child2" , "that" , false } ,
"find/part-no-prefix" : { [ ] string { "thi" } , "" , "" , false } ,
"find/part-alias" : { [ ] string { "thi" } , "child1" , "this" , true } ,
"find/conflict" : { [ ] string { "th" } , "" , "" , true } ,
"traverse/no-args" : { nil , "parent" , "parent" , false } ,
"traverse/real-name" : { [ ] string { "child1" } , "child1" , "child1" , false } ,
"traverse/full-alias" : { [ ] string { "that" } , "child2" , "that" , false } ,
"traverse/part-no-prefix" : { [ ] string { "thi" } , "" , "" , false } ,
"traverse/part-alias" : { [ ] string { "thi" } , "child1" , "this" , true } ,
"traverse/conflict" : { [ ] string { "th" } , "" , "" , true } ,
2018-02-04 16:58:53 +00:00
}
for name , tc := range tests {
t . Run ( name , tc . test )
}
}
2018-03-31 12:36:20 +00:00
func TestFParseErrWhitelistBackwardCompatibility ( t * testing . T ) {
c := & Command { Use : "c" , Run : emptyRun }
c . Flags ( ) . BoolP ( "boola" , "a" , false , "a boolean flag" )
output , err := executeCommand ( c , "c" , "-a" , "--unknown" , "flag" )
if err == nil {
t . Error ( "expected unknown flag error" )
}
checkStringContains ( t , output , "unknown flag: --unknown" )
}
func TestFParseErrWhitelistSameCommand ( t * testing . T ) {
c := & Command {
Use : "c" ,
Run : emptyRun ,
FParseErrWhitelist : FParseErrWhitelist {
UnknownFlags : true ,
} ,
}
c . Flags ( ) . BoolP ( "boola" , "a" , false , "a boolean flag" )
_ , err := executeCommand ( c , "c" , "-a" , "--unknown" , "flag" )
if err != nil {
t . Error ( "unexpected error: " , err )
}
}
func TestFParseErrWhitelistParentCommand ( t * testing . T ) {
root := & Command {
Use : "root" ,
Run : emptyRun ,
FParseErrWhitelist : FParseErrWhitelist {
UnknownFlags : true ,
} ,
}
c := & Command {
Use : "child" ,
Run : emptyRun ,
}
c . Flags ( ) . BoolP ( "boola" , "a" , false , "a boolean flag" )
root . AddCommand ( c )
output , err := executeCommand ( root , "child" , "-a" , "--unknown" , "flag" )
if err == nil {
t . Error ( "expected unknown flag error" )
}
checkStringContains ( t , output , "unknown flag: --unknown" )
}
func TestFParseErrWhitelistChildCommand ( t * testing . T ) {
root := & Command {
Use : "root" ,
Run : emptyRun ,
}
c := & Command {
Use : "child" ,
Run : emptyRun ,
FParseErrWhitelist : FParseErrWhitelist {
UnknownFlags : true ,
} ,
}
c . Flags ( ) . BoolP ( "boola" , "a" , false , "a boolean flag" )
root . AddCommand ( c )
_ , err := executeCommand ( root , "child" , "-a" , "--unknown" , "flag" )
if err != nil {
t . Error ( "unexpected error: " , err . Error ( ) )
}
}
func TestFParseErrWhitelistSiblingCommand ( t * testing . T ) {
root := & Command {
Use : "root" ,
Run : emptyRun ,
}
c := & Command {
Use : "child" ,
Run : emptyRun ,
FParseErrWhitelist : FParseErrWhitelist {
UnknownFlags : true ,
} ,
}
c . Flags ( ) . BoolP ( "boola" , "a" , false , "a boolean flag" )
s := & Command {
Use : "sibling" ,
Run : emptyRun ,
}
s . Flags ( ) . BoolP ( "boolb" , "b" , false , "a boolean flag" )
root . AddCommand ( c )
root . AddCommand ( s )
output , err := executeCommand ( root , "sibling" , "-b" , "--unknown" , "flag" )
if err == nil {
t . Error ( "expected unknown flag error" )
}
checkStringContains ( t , output , "unknown flag: --unknown" )
}
2022-03-18 10:01:58 +00:00
func TestSetContext ( t * testing . T ) {
type key struct { }
val := "foobar"
root := & Command {
Use : "root" ,
Run : func ( cmd * Command , args [ ] string ) {
key := cmd . Context ( ) . Value ( key { } )
got , ok := key . ( string )
if ! ok {
t . Error ( "key not found in context" )
}
if got != val {
t . Errorf ( "Expected value: \n %v\nGot:\n %v\n" , val , got )
}
} ,
}
ctx := context . WithValue ( context . Background ( ) , key { } , val )
root . SetContext ( ctx )
err := root . Execute ( )
if err != nil {
t . Error ( err )
}
}
func TestSetContextPreRun ( t * testing . T ) {
type key struct { }
val := "barr"
root := & Command {
Use : "root" ,
PreRun : func ( cmd * Command , args [ ] string ) {
ctx := context . WithValue ( cmd . Context ( ) , key { } , val )
cmd . SetContext ( ctx )
} ,
Run : func ( cmd * Command , args [ ] string ) {
val := cmd . Context ( ) . Value ( key { } )
got , ok := val . ( string )
if ! ok {
t . Error ( "key not found in context" )
}
if got != val {
t . Errorf ( "Expected value: \n %v\nGot:\n %v\n" , val , got )
}
} ,
}
err := root . Execute ( )
if err != nil {
t . Error ( err )
}
}
func TestSetContextPreRunOverwrite ( t * testing . T ) {
type key struct { }
val := "blah"
root := & Command {
Use : "root" ,
Run : func ( cmd * Command , args [ ] string ) {
key := cmd . Context ( ) . Value ( key { } )
_ , ok := key . ( string )
if ok {
t . Error ( "key found in context when not expected" )
}
} ,
}
ctx := context . WithValue ( context . Background ( ) , key { } , val )
root . SetContext ( ctx )
err := root . ExecuteContext ( context . Background ( ) )
if err != nil {
t . Error ( err )
}
}
func TestSetContextPersistentPreRun ( t * testing . T ) {
type key struct { }
val := "barbar"
root := & Command {
Use : "root" ,
PersistentPreRun : func ( cmd * Command , args [ ] string ) {
ctx := context . WithValue ( cmd . Context ( ) , key { } , val )
cmd . SetContext ( ctx )
} ,
}
child := & Command {
Use : "child" ,
Run : func ( cmd * Command , args [ ] string ) {
key := cmd . Context ( ) . Value ( key { } )
got , ok := key . ( string )
if ! ok {
t . Error ( "key not found in context" )
}
if got != val {
t . Errorf ( "Expected value: \n %v\nGot:\n %v\n" , val , got )
}
} ,
}
root . AddCommand ( child )
root . SetArgs ( [ ] string { "child" } )
err := root . Execute ( )
if err != nil {
t . Error ( err )
}
}
2022-09-30 18:26:05 +00:00
const VersionFlag = "--version"
const HelpFlag = "--help"
func TestNoRootRunCommandExecutedWithVersionSet ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Version : "1.0.0" , Long : "Long description" }
rootCmd . AddCommand ( & Command { Use : "child" , Run : emptyRun } )
output , err := executeCommand ( rootCmd )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , rootCmd . Long )
checkStringContains ( t , output , HelpFlag )
checkStringContains ( t , output , VersionFlag )
}
func TestNoRootRunCommandExecutedWithoutVersionSet ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Long : "Long description" }
rootCmd . AddCommand ( & Command { Use : "child" , Run : emptyRun } )
output , err := executeCommand ( rootCmd )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , rootCmd . Long )
checkStringContains ( t , output , HelpFlag )
checkStringOmits ( t , output , VersionFlag )
}
func TestHelpCommandExecutedWithVersionSet ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Version : "1.0.0" , Long : "Long description" , Run : emptyRun }
rootCmd . AddCommand ( & Command { Use : "child" , Run : emptyRun } )
output , err := executeCommand ( rootCmd , "help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , rootCmd . Long )
checkStringContains ( t , output , HelpFlag )
checkStringContains ( t , output , VersionFlag )
}
func TestHelpCommandExecutedWithoutVersionSet ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Long : "Long description" , Run : emptyRun }
rootCmd . AddCommand ( & Command { Use : "child" , Run : emptyRun } )
output , err := executeCommand ( rootCmd , "help" )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , rootCmd . Long )
checkStringContains ( t , output , HelpFlag )
checkStringOmits ( t , output , VersionFlag )
}
func TestHelpflagCommandExecutedWithVersionSet ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Version : "1.0.0" , Long : "Long description" , Run : emptyRun }
rootCmd . AddCommand ( & Command { Use : "child" , Run : emptyRun } )
output , err := executeCommand ( rootCmd , HelpFlag )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , rootCmd . Long )
checkStringContains ( t , output , HelpFlag )
checkStringContains ( t , output , VersionFlag )
}
func TestHelpflagCommandExecutedWithoutVersionSet ( t * testing . T ) {
rootCmd := & Command { Use : "root" , Long : "Long description" , Run : emptyRun }
rootCmd . AddCommand ( & Command { Use : "child" , Run : emptyRun } )
output , err := executeCommand ( rootCmd , HelpFlag )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
checkStringContains ( t , output , rootCmd . Long )
checkStringContains ( t , output , HelpFlag )
checkStringOmits ( t , output , VersionFlag )
}
2022-11-08 04:12:02 +00:00
func TestFind ( t * testing . T ) {
var foo , bar string
2024-09-14 14:08:27 +00:00
var persist bool
2022-11-08 04:12:02 +00:00
root := & Command {
Use : "root" ,
}
root . PersistentFlags ( ) . StringVarP ( & foo , "foo" , "f" , "" , "" )
root . PersistentFlags ( ) . StringVarP ( & bar , "bar" , "b" , "something" , "" )
2024-09-14 14:08:27 +00:00
root . PersistentFlags ( ) . BoolVarP ( & persist , "persist" , "p" , false , "" )
2022-11-08 04:12:02 +00:00
child := & Command {
Use : "child" ,
}
root . AddCommand ( child )
testCases := [ ] struct {
args [ ] string
expectedFoundArgs [ ] string
} {
{
[ ] string { "child" } ,
[ ] string { } ,
} ,
{
[ ] string { "child" , "child" } ,
[ ] string { "child" } ,
} ,
{
[ ] string { "child" , "foo" , "child" , "bar" , "child" , "baz" , "child" } ,
[ ] string { "foo" , "child" , "bar" , "child" , "baz" , "child" } ,
} ,
{
[ ] string { "-f" , "child" , "child" } ,
[ ] string { "-f" , "child" } ,
} ,
{
[ ] string { "child" , "-f" , "child" } ,
[ ] string { "-f" , "child" } ,
} ,
{
[ ] string { "-b" , "child" , "child" } ,
[ ] string { "-b" , "child" } ,
} ,
{
[ ] string { "child" , "-b" , "child" } ,
[ ] string { "-b" , "child" } ,
} ,
{
[ ] string { "child" , "-b" } ,
[ ] string { "-b" } ,
} ,
{
[ ] string { "-b" , "-f" , "child" , "child" } ,
[ ] string { "-b" , "-f" , "child" } ,
} ,
{
[ ] string { "-f" , "child" , "-b" , "something" , "child" } ,
[ ] string { "-f" , "child" , "-b" , "something" } ,
} ,
{
[ ] string { "-f" , "child" , "child" , "-b" } ,
[ ] string { "-f" , "child" , "-b" } ,
} ,
{
[ ] string { "-f=child" , "-b=something" , "child" } ,
[ ] string { "-f=child" , "-b=something" } ,
} ,
{
[ ] string { "--foo" , "child" , "--bar" , "something" , "child" } ,
[ ] string { "--foo" , "child" , "--bar" , "something" } ,
} ,
2024-09-14 14:08:27 +00:00
{
[ ] string { "-f" , "value" , "child" } ,
[ ] string { "-f" , "value" } ,
} ,
{
[ ] string { "-f=value" , "child" } ,
[ ] string { "-f=value" } ,
} ,
{
[ ] string { "-fvalue" , "child" } ,
[ ] string { "-fvalue" } ,
} ,
{
[ ] string { "-pf" , "value" , "child" } ,
[ ] string { "-pf" , "value" } ,
} ,
{
[ ] string { "-pf=value" , "child" } ,
[ ] string { "-pf=value" } ,
} ,
{
[ ] string { "-pfvalue" , "child" } ,
[ ] string { "-pfvalue" } ,
} ,
{
[ ] string { "-pf" , "child" , "child" } ,
[ ] string { "-pf" , "child" } ,
} ,
{
[ ] string { "-pf" , "child" , "-pb" , "something" , "child" } ,
[ ] string { "-pf" , "child" , "-pb" , "something" } ,
} ,
2022-11-08 04:12:02 +00:00
}
for _ , tc := range testCases {
t . Run ( fmt . Sprintf ( "%v" , tc . args ) , func ( t * testing . T ) {
cmd , foundArgs , err := root . Find ( tc . args )
if err != nil {
t . Fatal ( err )
}
if cmd != child {
t . Fatal ( "Expected cmd to be child, but it was not" )
}
if ! reflect . DeepEqual ( tc . expectedFoundArgs , foundArgs ) {
t . Fatalf ( "Wrong args\nExpected: %v\nGot: %v" , tc . expectedFoundArgs , foundArgs )
}
} )
}
}
2022-11-15 02:46:57 +00:00
func TestUnknownFlagShouldReturnSameErrorRegardlessOfArgPosition ( t * testing . T ) {
testCases := [ ] [ ] string {
2024-04-01 12:42:08 +00:00
// {"--unknown", "--namespace", "foo", "child", "--bar"}, // FIXME: This test case fails, returning the error `unknown command "foo" for "root"` instead of the expected error `unknown flag: --unknown`
2022-11-15 02:46:57 +00:00
{ "--namespace" , "foo" , "--unknown" , "child" , "--bar" } ,
{ "--namespace" , "foo" , "child" , "--unknown" , "--bar" } ,
{ "--namespace" , "foo" , "child" , "--bar" , "--unknown" } ,
{ "--unknown" , "--namespace=foo" , "child" , "--bar" } ,
{ "--namespace=foo" , "--unknown" , "child" , "--bar" } ,
{ "--namespace=foo" , "child" , "--unknown" , "--bar" } ,
{ "--namespace=foo" , "child" , "--bar" , "--unknown" } ,
{ "--unknown" , "--namespace=foo" , "child" , "--bar=true" } ,
{ "--namespace=foo" , "--unknown" , "child" , "--bar=true" } ,
{ "--namespace=foo" , "child" , "--unknown" , "--bar=true" } ,
{ "--namespace=foo" , "child" , "--bar=true" , "--unknown" } ,
}
root := & Command {
Use : "root" ,
Run : emptyRun ,
}
root . PersistentFlags ( ) . String ( "namespace" , "" , "a string flag" )
c := & Command {
Use : "child" ,
Run : emptyRun ,
}
c . Flags ( ) . Bool ( "bar" , false , "a boolean flag" )
root . AddCommand ( c )
for _ , tc := range testCases {
t . Run ( strings . Join ( tc , " " ) , func ( t * testing . T ) {
output , err := executeCommand ( root , tc ... )
if err == nil {
t . Error ( "expected unknown flag error" )
}
checkStringContains ( t , output , "unknown flag: --unknown" )
} )
}
}