| // 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) | |
| } | |
| } |