package diary_test import ( "context" "io" "strings" "testing" "github.com/spf13/cobra" "git.golem15.com/golem15/summercms/modules/bonfire" "git.golem15.com/golem15/summercms/modules/diary" ) // helpOnlyCases are the rows shared by TestHelpOnly and // TestHelpOnlyAgreesWithCobra. usage marks the rows cobra rejects as a // usage error, which the agreement check leaves out. var helpOnlyCases = []struct { args []string want bool usage bool }{ {args: []string{}, want: true}, {args: []string{"--help"}, want: true}, {args: []string{"-h"}, want: true}, {args: []string{"serve", "--help"}, want: true}, {args: []string{"serve", "-h"}, want: true}, {args: []string{"-h", "serve"}, want: true}, {args: []string{"serve", "--help=true"}, want: true}, {args: []string{"serve", "--help=1"}, want: true}, {args: []string{"-nh", "serve"}, want: true}, {args: []string{"-vh", "serve"}, want: true}, {args: []string{"serve", "-vh=true"}, want: true}, {args: []string{"list"}, want: true}, {args: []string{"list", "--format=json"}, want: true}, {args: []string{"help"}, want: true}, {args: []string{"help", "serve"}, want: true}, {args: []string{"--env", "staging"}, want: true}, {args: []string{"--env=staging"}, want: true}, {args: []string{"-v"}, want: true}, {args: []string{"--help=false"}, want: true}, {args: []string{"--env", "help"}, want: true}, {args: []string{"__complete", "serve", ""}, want: true}, {args: []string{"__completeNoDesc", "se"}, want: true}, {args: []string{"serve"}}, {args: []string{"migrate", "-v"}}, {args: []string{"queue:work"}}, {args: []string{"--env", "list", "serve"}}, {args: []string{"serve", "--", "--help"}}, {args: []string{"serve", "--help=false"}}, {args: []string{"serve", "--help", "--help=false"}}, {args: []string{"serve", "-h=false"}}, {args: []string{"serve", "-qv"}}, {args: []string{"serve", "-xh"}, usage: true}, {args: []string{"serve", "--help=yes"}, usage: true}, {args: []string{"blog:import", "https://example.com/help"}}, {args: []string{"blog:import", "help"}}, {args: []string{"-q", "--env=list", "migrate"}}, } func TestHelpOnly(t *testing.T) { for _, tc := range helpOnlyCases { if got := diary.HelpOnly(tc.args); got != tc.want { t.Errorf("helpOnly(%q) = %v, want %v", tc.args, got, tc.want) } } } // helpOnlyRoot builds a root whose commands record whether their Run ran. func helpOnlyRoot(t *testing.T, ran *bool) *cobra.Command { t.Helper() run := func(context.Context, bonfire.Input, bonfire.Output) error { *ran = true return nil } optional := []bonfire.Arg{{Name: "target", Description: "An optional argument"}} commands := []bonfire.Command{ {Name: "serve", Description: "Start the HTTP server", Args: optional, Run: run}, {Name: "migrate", Description: "Run the migrations", Run: run}, {Name: "queue:work", Description: "Run the job workers", Run: run}, {Name: "blog:import", Description: "Import posts", Args: optional, Run: run}, {Name: "acme:tool", Description: "Run a tool with its own flags", Passthrough: true, Run: run}, } root, err := bonfire.NewRootIO("acme", commands, strings.NewReader(""), io.Discard, io.Discard, bonfire.WithVersion(bonfire.Version{App: "v1.0.0", Framework: "v1.0.0"})) if err != nil { t.Fatal(err) } return root } // TestHelpOnlyAgreesWithCobra: for every row cobra accepts, a command runs // exactly when helpOnly reports false. A passthrough command is the // documented exception: its --help reaches its Run, while helpOnly, which // cannot know the command before boot, counts it. func TestHelpOnlyAgreesWithCobra(t *testing.T) { for _, tc := range helpOnlyCases { var ran bool code := bonfire.Execute(context.Background(), helpOnlyRoot(t, &ran), tc.args) if tc.usage { if code != bonfire.ExitUsage { t.Errorf("Execute(%q) = %d, want the usage error %d", tc.args, code, bonfire.ExitUsage) } continue } if code != bonfire.ExitOK { t.Errorf("Execute(%q) = %d, want 0", tc.args, code) continue } if ran != !diary.HelpOnly(tc.args) { t.Errorf("Execute(%q) ran a command = %v, but helpOnly = %v", tc.args, ran, diary.HelpOnly(tc.args)) } } t.Run("passthrough --help", func(t *testing.T) { args := []string{"acme:tool", "--help"} var ran bool if code := bonfire.Execute(context.Background(), helpOnlyRoot(t, &ran), args); code != bonfire.ExitOK { t.Fatalf("Execute(%q) = %d, want 0", args, code) } if !ran || !diary.HelpOnly(args) { t.Errorf("Execute(%q) ran = %v, helpOnly = %v; want both true (the documented exception)", args, ran, diary.HelpOnly(args)) } }) if diary.CompleteRequestCmd != cobra.ShellCompRequestCmd { t.Errorf("completion command %q, cobra uses %q", diary.CompleteRequestCmd, cobra.ShellCompRequestCmd) } if diary.CompleteNoDescRequestCmd != cobra.ShellCompNoDescRequestCmd { t.Errorf("completion command %q, cobra uses %q", diary.CompleteNoDescRequestCmd, cobra.ShellCompNoDescRequestCmd) } }