// Copyright 2013-2023 The Cobra Authors // // 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. package cobra import ( "fmt" "os" "strings" "testing" ) const ( activeHelpMessage = "This is an activeHelp message" activeHelpMessage2 = "This is the rest of the activeHelp message" ) func TestActiveHelpAlone(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } activeHelpFunc := func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { comps := AppendActiveHelp(nil, activeHelpMessage) return comps, ShellCompDirectiveDefault } // Test that activeHelp can be added to a root command rootCmd.ValidArgsFunction = activeHelpFunc output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ fmt.Sprintf("%s%s", activeHelpMarker, activeHelpMessage), ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } rootCmd.ValidArgsFunction = nil // Test that activeHelp can be added to a child command childCmd := &Command{ Use: "thechild", Short: "The child command", Run: emptyRun, } rootCmd.AddCommand(childCmd) childCmd.ValidArgsFunction = activeHelpFunc output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "thechild", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ fmt.Sprintf("%s%s", activeHelpMarker, activeHelpMessage), ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestActiveHelpWithComps(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } childCmd := &Command{ Use: "thechild", Short: "The child command", Run: emptyRun, } rootCmd.AddCommand(childCmd) // Test that activeHelp can be added following other completions childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { comps := []string{"first", "second"} comps = AppendActiveHelp(comps, activeHelpMessage) return comps, ShellCompDirectiveDefault } output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "thechild", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "first", "second", fmt.Sprintf("%s%s", activeHelpMarker, activeHelpMessage), ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that activeHelp can be added preceding other completions childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { var comps []string comps = AppendActiveHelp(comps, activeHelpMessage) comps = append(comps, []string{"first", "second"}...) return comps, ShellCompDirectiveDefault } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "thechild", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ fmt.Sprintf("%s%s", activeHelpMarker, activeHelpMessage), "first", "second", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that activeHelp can be added interleaved with other completions childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { comps := []string{"first"} comps = AppendActiveHelp(comps, activeHelpMessage) comps = append(comps, "second") return comps, ShellCompDirectiveDefault } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "thechild", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "first", fmt.Sprintf("%s%s", activeHelpMarker, activeHelpMessage), "second", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestMultiActiveHelp(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } childCmd := &Command{ Use: "thechild", Short: "The child command", Run: emptyRun, } rootCmd.AddCommand(childCmd) // Test that multiple activeHelp message can be added childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { comps := AppendActiveHelp(nil, activeHelpMessage) comps = AppendActiveHelp(comps, activeHelpMessage2) return comps, ShellCompDirectiveNoFileComp } output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "thechild", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ fmt.Sprintf("%s%s", activeHelpMarker, activeHelpMessage), fmt.Sprintf("%s%s", activeHelpMarker, activeHelpMessage2), ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that multiple activeHelp messages can be used along with completions childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { comps := []string{"first"} comps = AppendActiveHelp(comps, activeHelpMessage) comps = append(comps, "second") comps = AppendActiveHelp(comps, activeHelpMessage2) return comps, ShellCompDirectiveNoFileComp } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "thechild", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "first", fmt.Sprintf("%s%s", activeHelpMarker, activeHelpMessage), "second", fmt.Sprintf("%s%s", activeHelpMarker, activeHelpMessage2), ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestActiveHelpForFlag(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } flagname := "flag" rootCmd.Flags().String(flagname, "", "A flag") // Test that multiple activeHelp message can be added _ = rootCmd.RegisterFlagCompletionFunc(flagname, func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { comps := []string{"first"} comps = AppendActiveHelp(comps, activeHelpMessage) comps = append(comps, "second") comps = AppendActiveHelp(comps, activeHelpMessage2) return comps, ShellCompDirectiveNoFileComp }) output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--flag", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "first", fmt.Sprintf("%s%s", activeHelpMarker, activeHelpMessage), "second", fmt.Sprintf("%s%s", activeHelpMarker, activeHelpMessage2), ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestConfigActiveHelp(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } childCmd := &Command{ Use: "thechild", Short: "The child command", Run: emptyRun, } rootCmd.AddCommand(childCmd) activeHelpCfg := "someconfig,anotherconfig" // Set the variable that the user would be setting os.Setenv(activeHelpEnvVar(rootCmd.Name()), activeHelpCfg) childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { receivedActiveHelpCfg := GetActiveHelpConfig(cmd) if receivedActiveHelpCfg != activeHelpCfg { t.Errorf("expected activeHelpConfig: %q, but got: %q", activeHelpCfg, receivedActiveHelpCfg) } return nil, ShellCompDirectiveDefault } _, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "thechild", "") if err != nil { t.Errorf("Unexpected error: %v", err) } // Test active help config for a flag activeHelpCfg = "a config for a flag" // Set the variable that the completions scripts will be setting os.Setenv(activeHelpEnvVar(rootCmd.Name()), activeHelpCfg) flagname := "flag" childCmd.Flags().String(flagname, "", "A flag") // Test that multiple activeHelp message can be added _ = childCmd.RegisterFlagCompletionFunc(flagname, func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { receivedActiveHelpCfg := GetActiveHelpConfig(cmd) if receivedActiveHelpCfg != activeHelpCfg { t.Errorf("expected activeHelpConfig: %q, but got: %q", activeHelpCfg, receivedActiveHelpCfg) } return nil, ShellCompDirectiveDefault }) _, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "thechild", "--flag", "") if err != nil { t.Errorf("Unexpected error: %v", err) } } func TestDisableActiveHelp(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } childCmd := &Command{ Use: "thechild", Short: "The child command", Run: emptyRun, } rootCmd.AddCommand(childCmd) // Test the disabling of activeHelp using the specific program // environment variable that the completions scripts will be setting. // Make sure the disabling value is "0" by hard-coding it in the tests; // this is for backwards-compatibility as programs will be using this value. os.Setenv(activeHelpEnvVar(rootCmd.Name()), "0") childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { comps := []string{"first"} comps = AppendActiveHelp(comps, activeHelpMessage) return comps, ShellCompDirectiveDefault } output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "thechild", "") if err != nil { t.Errorf("Unexpected error: %v", err) } os.Unsetenv(activeHelpEnvVar(rootCmd.Name())) // Make sure there is no ActiveHelp in the output expected := strings.Join([]string{ "first", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Now test the global disabling of ActiveHelp os.Setenv(activeHelpGlobalEnvVar, "0") // Set the specific variable, to make sure it is ignored when the global env // var is set properly os.Setenv(activeHelpEnvVar(rootCmd.Name()), "1") output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "thechild", "") if err != nil { t.Errorf("Unexpected error: %v", err) } // Make sure there is no ActiveHelp in the output expected = strings.Join([]string{ "first", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Make sure that if the global env variable is set to anything else than // the disable value it is ignored os.Setenv(activeHelpGlobalEnvVar, "on") // Set the specific variable, to make sure it is used (while ignoring the global env var) activeHelpCfg := "1" os.Setenv(activeHelpEnvVar(rootCmd.Name()), activeHelpCfg) childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { receivedActiveHelpCfg := GetActiveHelpConfig(cmd) if receivedActiveHelpCfg != activeHelpCfg { t.Errorf("expected activeHelpConfig: %q, but got: %q", activeHelpCfg, receivedActiveHelpCfg) } return nil, ShellCompDirectiveDefault } _, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "thechild", "") if err != nil { t.Errorf("Unexpected error: %v", err) } }