github.com/kristofferahl/go-centry@v1.5.0/cmd/centry/runtime_test.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"strings"
     7  	"testing"
     8  
     9  	. "github.com/franela/goblin"
    10  	"github.com/kristofferahl/go-centry/internal/pkg/io"
    11  	test "github.com/kristofferahl/go-centry/internal/pkg/test"
    12  )
    13  
    14  func TestMain(t *testing.T) {
    15  	g := Goblin(t)
    16  
    17  	// Esuring the workdir is the root of the repo
    18  	os.Chdir("../../")
    19  
    20  	g.Describe("runtime", func() {
    21  		g.Describe("manifest file", func() {
    22  			g.It("tries to use ./centry.yaml as the default file", func() {
    23  				context := NewContext(CLI, io.Headless())
    24  				runtime, err := NewRuntime([]string{}, context)
    25  				g.Assert(runtime == nil).IsTrue("expected runtime to be nil, %v", runtime)
    26  				g.Assert(err != nil).IsTrue("expected error, %v", err)
    27  				g.Assert(err.Error()).Eql("manifest file not found (path=./centry.yaml)")
    28  			})
    29  
    30  			g.It("tries to use file specified by CENTRY_FILE environment variable", func() {
    31  				os.Setenv("CENTRY_FILE", "./centry-environment.yaml")
    32  				context := NewContext(CLI, io.Headless())
    33  				runtime, err := NewRuntime([]string{}, context)
    34  				g.Assert(runtime == nil).IsTrue("expected runtime to be nil, %v", runtime)
    35  				g.Assert(err != nil).IsTrue("expected error, %v", err)
    36  				g.Assert(err.Error()).Eql("manifest file not found (path=./centry-environment.yaml)")
    37  				os.Setenv("CENTRY_FILE", "")
    38  			})
    39  
    40  			g.It("tries to use file specified by --centry-file flag", func() {
    41  				context := NewContext(CLI, io.Headless())
    42  				runtime, err := NewRuntime([]string{"--centry-file", "./centry-flag.yaml"}, context)
    43  				g.Assert(runtime == nil).IsTrue("expected runtime to be nil, %v", runtime)
    44  				g.Assert(err != nil).IsTrue("expected error, %v", err)
    45  				g.Assert(err.Error()).Eql("manifest file not found (path=./centry-flag.yaml)")
    46  			})
    47  
    48  			g.It("tries to use file specified by --centry-file= flag", func() {
    49  				context := NewContext(CLI, io.Headless())
    50  				runtime, err := NewRuntime([]string{"--centry-file=./centry-flag-equals.yaml"}, context)
    51  				g.Assert(runtime == nil).IsTrue("expected runtime to be nil, %v", runtime)
    52  				g.Assert(err != nil).IsTrue("expected error, %v", err)
    53  				g.Assert(err.Error()).Eql("manifest file not found (path=./centry-flag-equals.yaml)")
    54  			})
    55  
    56  			g.It("tries to use file specified by --centry-file= flag even when it contains equal signs", func() {
    57  				context := NewContext(CLI, io.Headless())
    58  				runtime, err := NewRuntime([]string{"--centry-file=./foo=bar.yaml"}, context)
    59  				g.Assert(runtime == nil).IsTrue("expected runtime to be nil, %v", runtime)
    60  				g.Assert(err != nil).IsTrue("expected error, %v", err)
    61  				g.Assert(err.Error()).Eql("manifest file not found (path=./foo=bar.yaml)")
    62  			})
    63  
    64  			g.It("gives an error when --centry-file flag is missing it's value", func() {
    65  				context := NewContext(CLI, io.Headless())
    66  				runtime, err := NewRuntime([]string{"--centry-file"}, context)
    67  				g.Assert(runtime == nil).IsTrue("expected runtime to be nil, %v", runtime)
    68  				g.Assert(err != nil).IsTrue("expected error, %v", err)
    69  				g.Assert(err.Error()).Eql("a value must be specified for --centry-file")
    70  			})
    71  		})
    72  	})
    73  
    74  	g.Describe("scripts", func() {
    75  		g.It("loads script in the expected order", func() {
    76  			expected := "Loading init.sh\nLoading helpers.sh"
    77  			os.Setenv("OUTPUT_DEBUG", "true")
    78  			out := execQuiet("scripttest")
    79  			test.AssertNoError(g, out.Error)
    80  			test.AssertStringContains(g, out.Stdout, expected)
    81  			os.Unsetenv("OUTPUT_DEBUG")
    82  		})
    83  	})
    84  
    85  	g.Describe("commands", func() {
    86  		g.Describe("invoking invalid command", func() {
    87  			g.It("should exit with status code 127", func() {
    88  				out := execQuiet("commandnotdefined")
    89  				g.Assert(out.ExitCode).Equal(127)
    90  			})
    91  		})
    92  
    93  		g.Describe("invoking command that exits with a status code", func() {
    94  			g.It("should exit with exit code from command", func() {
    95  				out := execQuiet("commandtest exitcode")
    96  				g.Assert(out.ExitCode).Equal(111)
    97  			})
    98  		})
    99  
   100  		g.Describe("invoking command with undefined option", func() {
   101  			g.It("should exit with exit code", func() {
   102  				out := execWithLogging("commandtest --undef")
   103  				g.Assert(out.ExitCode).Equal(127)
   104  			})
   105  		})
   106  
   107  		g.Describe("invoking command", func() {
   108  			g.Describe("with arguments", func() {
   109  				g.It("should have arguments passed", func() {
   110  					expected := "command args (foo bar)"
   111  					out := execQuiet("commandtest foo bar")
   112  					test.AssertStringContains(g, out.Stdout, expected)
   113  				})
   114  
   115  				g.It("should pass any flags followed by -- as arguments", func() {
   116  					expected := "command args (--foo bar)"
   117  					out := execQuiet("commandtest -- --foo bar")
   118  					test.AssertStringContains(g, out.Stdout, expected)
   119  				})
   120  			})
   121  
   122  			g.Describe("without arguments", func() {
   123  				g.It("should have no arguments passed", func() {
   124  					expected := "command args ()"
   125  					out := execQuiet("commandtest")
   126  					test.AssertStringContains(g, out.Stdout, expected)
   127  				})
   128  			})
   129  		})
   130  
   131  		g.Describe("invoking sub command", func() {
   132  			g.Describe("with arguments", func() {
   133  				g.It("should have arguments passed", func() {
   134  					expected := "subcommand args (foo bar)"
   135  					out := execQuiet("commandtest subcommand foo bar")
   136  					test.AssertStringContains(g, out.Stdout, expected)
   137  				})
   138  
   139  				g.It("should pass any flags followed by -- as arguments", func() {
   140  					expected := "subcommand args (--foo bar)"
   141  					out := execQuiet("commandtest subcommand -- --foo bar")
   142  					test.AssertStringContains(g, out.Stdout, expected)
   143  				})
   144  			})
   145  
   146  			g.Describe("without arguments", func() {
   147  				g.It("should have no arguments passed", func() {
   148  					expected := "subcommand args ()"
   149  					out := execQuiet("commandtest subcommand")
   150  					test.AssertStringContains(g, out.Stdout, expected)
   151  				})
   152  			})
   153  		})
   154  
   155  		g.Describe("command options", func() {
   156  			g.Describe("invoking command with options", func() {
   157  				g.It("should have arguments passed", func() {
   158  					expected := "command args (foo bar baz)"
   159  					out := execQuiet("commandtest options args --cmdstringopt=hello --cmdboolopt --cmdsel2 foo bar baz")
   160  					test.AssertStringContains(g, out.Stdout, expected)
   161  				})
   162  
   163  				g.It("should have environment variables set", func() {
   164  					out := execQuiet("commandtest options printenv --cmdstringopt=world --cmdboolopt --cmdsel2 --dashed-opt dashed-val")
   165  					test.AssertStringHasKeyValue(g, out.Stdout, "CMDSTRINGOPT", "world")
   166  					test.AssertStringHasKeyValue(g, out.Stdout, "CMDBOOLOPT", "true")
   167  					test.AssertStringHasKeyValue(g, out.Stdout, "CMDSELECTOPT", "cmdsel2")
   168  					test.AssertStringHasKeyValue(g, out.Stdout, "DASHED_OPT", "dashed-val")
   169  				})
   170  
   171  				g.It("should hav prefixed environment variables set", func() {
   172  					out := execCentry("commandtest options printenv --cmdstringopt=world --cmdboolopt --cmdsel2", true, "test/data/runtime_test_environment_prefix.yaml")
   173  					test.AssertStringHasKeyValue(g, out.Stdout, "ENV_PREFIX_CMDSTRINGOPT", "world")
   174  					test.AssertStringHasKeyValue(g, out.Stdout, "ENV_PREFIX_CMDBOOLOPT", "true")
   175  					test.AssertStringHasKeyValue(g, out.Stdout, "ENV_PREFIX_CMDSELECTOPT", "cmdsel2")
   176  				})
   177  			})
   178  		})
   179  	})
   180  
   181  	g.Describe("options", func() {
   182  		g.Describe("invoke without option", func() {
   183  			g.It("should pass arguments", func() {
   184  				expected := "args (foo bar)"
   185  				out := execQuiet("optiontest args foo bar")
   186  				test.AssertStringContains(g, out.Stdout, expected)
   187  			})
   188  
   189  			g.It("should have default value for environment variable set", func() {
   190  				out := execQuiet("optiontest printenv")
   191  				test.AssertStringHasKeyValue(g, out.Stdout, "BOOLOPT", "false")
   192  				test.AssertStringHasKeyValue(g, out.Stdout, "STRINGOPT", "foobar")
   193  			})
   194  
   195  			g.It("should have prefixed environment variables set", func() {
   196  				out := execCentry("optiontest printenv", true, "test/data/runtime_test_environment_prefix.yaml")
   197  				test.AssertStringHasKeyValue(g, out.Stdout, "ENV_PREFIX_BOOLOPT", "false")
   198  				test.AssertStringHasKeyValue(g, out.Stdout, "ENV_PREFIX_STRINGOPT", "foobar")
   199  			})
   200  		})
   201  
   202  		g.Describe("invoke with single option", func() {
   203  			g.It("should have arguments passed", func() {
   204  				expected := "args (foo bar)"
   205  				out := execQuiet("--boolopt optiontest args foo bar")
   206  				test.AssertStringContains(g, out.Stdout, expected)
   207  			})
   208  
   209  			g.It("should have environment set for select option (v1)", func() {
   210  				out := execQuiet("--selectopt1 optiontest printenv")
   211  				test.AssertStringHasKeyValue(g, out.Stdout, "SELECTOPT", "selectopt1")
   212  			})
   213  
   214  			g.It("should have environment set for select option (v2)", func() {
   215  				out := execQuiet("--opt1 optiontest printenv")
   216  				test.AssertStringHasKeyValue(g, out.Stdout, "SELECTOPTV2", "value1")
   217  			})
   218  		})
   219  
   220  		g.Describe("invoke with multiple options", func() {
   221  			g.It("should have arguments passed", func() {
   222  				expected := "args (bar foo)"
   223  				out := execQuiet("--boolopt --stringopt=foo optiontest args bar foo")
   224  				test.AssertStringContains(g, out.Stdout, expected)
   225  			})
   226  
   227  			g.It("should have multipe environment variables set", func() {
   228  				out := execQuiet("--selectopt2 --stringopt=blazer --boolopt optiontest printenv")
   229  
   230  				test.AssertStringHasKeyValue(g, out.Stdout, "STRINGOPT", "blazer")
   231  				test.AssertStringHasKeyValue(g, out.Stdout, "BOOLOPT", "true")
   232  				test.AssertStringHasKeyValue(g, out.Stdout, "SELECTOPT", "selectopt2")
   233  			})
   234  		})
   235  
   236  		g.Describe("invoke with invalid option", func() {
   237  			g.It("should fail with error message", func() {
   238  				out := execQuiet("--invalidoption optiontest args")
   239  				test.AssertStringContains(g, out.Stdout, "Incorrect Usage. flag provided but not defined: -invalidoption")
   240  				test.AssertStringContains(g, out.Stderr, "flag provided but not defined: -invalidoption")
   241  				test.AssertNoError(g, out.Error)
   242  			})
   243  
   244  			g.It("should fail with error when specifying multiple options for the same select option group (v1)", func() {
   245  				out := execCentry("--selectopt1 --selectopt2 optiontest args", false, "test/data/runtime_test.yaml")
   246  				test.AssertStringContains(g, out.Stderr, "level=error msg=\"global flag specified multiple times for select option group \\\"SELECTOPT\\\" (one of \\\" selectopt1 | selectopt2 \\\" must be provided)")
   247  			})
   248  
   249  			g.It("should fail with error when specifying multiple options for the same select option group (v2)", func() {
   250  				out := execCentry("--opt1 --opt2 optiontest args", false, "test/data/runtime_test.yaml")
   251  				test.AssertStringContains(g, out.Stderr, "level=error msg=\"global flag specified multiple times for select option group \\\"selectoptv2\\\" (one of \\\" opt1 | opt2 \\\" must be provided)")
   252  			})
   253  		})
   254  
   255  		g.Describe("invoke without required option", func() {
   256  			g.Describe("of type string", func() {
   257  				g.It("should fail with error message", func() {
   258  					out := execCentry("optiontest required --boolopt --intopt=999 --selectopt1 --selectopt_v2_1", false, "test/data/runtime_test.yaml")
   259  					test.AssertStringContains(g, out.Stderr, "level=error msg=\"Required flag \\\"stringopt\\\" not set\"")
   260  				})
   261  			})
   262  			g.Describe("of type bool", func() {
   263  				g.It("should fail with error message", func() {
   264  					out := execCentry("optiontest required --stringopt=foo --intopt=999 --selectopt1 --selectopt_v2_1", false, "test/data/runtime_test.yaml")
   265  					test.AssertStringContains(g, out.Stderr, "level=error msg=\"Required flag \\\"boolopt\\\" not set\"")
   266  				})
   267  			})
   268  			g.Describe("of type integer", func() {
   269  				g.It("should fail with error message", func() {
   270  					out := execCentry("optiontest required --stringopt=foo --boolopt --selectopt1 --selectopt_v2_1", false, "test/data/runtime_test.yaml")
   271  					test.AssertStringContains(g, out.Stderr, "level=error msg=\"Required flag \\\"intopt\\\" not set\"")
   272  				})
   273  			})
   274  			g.Describe("of type select", func() {
   275  				g.It("should fail with error message", func() {
   276  					out := execCentry("optiontest required --stringopt=foo --boolopt --intopt=999 --selectopt_v2_1", false, "test/data/runtime_test.yaml")
   277  					test.AssertStringContains(g, out.Stderr, "level=error msg=\"Required command flag missing for select option group \\\"SELECTOPTV1\\\" (one of \\\" selectopt1 | selectopt2 \\\" must be provided)")
   278  				})
   279  			})
   280  			g.Describe("of type select/v2", func() {
   281  				g.It("should fail with error message", func() {
   282  					out := execCentry("optiontest required --stringopt=foo --boolopt --intopt=999 --selectopt1", false, "test/data/runtime_test.yaml")
   283  					test.AssertStringContains(g, out.Stderr, "level=error msg=\"Required command flag missing for select option group \\\"selectoptv2\\\" (one of \\\" selectopt_v2_1 | selectopt_v2_2 \\\" must be provided)")
   284  				})
   285  			})
   286  		})
   287  
   288  		g.Describe("invoke with required option", func() {
   289  			g.It("should pass", func() {
   290  				out := execCentry("optiontest required --stringopt=foo --boolopt --intopt=111 --selectopt1 --selectopt_v2_1", false, "test/data/runtime_test.yaml")
   291  				test.AssertStringHasKeyValue(g, out.Stdout, "STRINGOPT", "foo")
   292  				test.AssertStringHasKeyValue(g, out.Stdout, "BOOLOPT", "true")
   293  				test.AssertStringHasKeyValue(g, out.Stdout, "INTOPT", "111")
   294  				test.AssertStringHasKeyValue(g, out.Stdout, "SELECTOPTV1", "selectopt1")
   295  				test.AssertStringHasKeyValue(g, out.Stdout, "SELECTOPTV2", "selectopt_v2_1")
   296  			})
   297  		})
   298  	})
   299  
   300  	g.Describe("global options", func() {
   301  		g.Describe("version", func() {
   302  			g.Describe("--version", func() {
   303  				g.It("should display version", func() {
   304  					expected := `1.0.0`
   305  					out := execQuiet("--version")
   306  					test.AssertStringContains(g, out.Stdout, expected)
   307  				})
   308  			})
   309  
   310  			g.Describe("-v", func() {
   311  				g.It("should display version", func() {
   312  					expected := `1.0.0`
   313  					out := execQuiet("-v")
   314  					test.AssertStringContains(g, out.Stdout, expected)
   315  				})
   316  			})
   317  		})
   318  
   319  		g.Describe("--centry-quiet", func() {
   320  			g.It("should disable logging", func() {
   321  				expected := `changing loglevel to panic (from debug)`
   322  				out := execWithLogging("--centry-quiet")
   323  				test.AssertStringContains(g, out.Stderr, expected)
   324  			})
   325  
   326  			g.It("should have environment variable set", func() {
   327  				out := execCentry("optiontest printenv", true, defaultManifestPath)
   328  				test.AssertStringHasKeyValue(g, out.Stdout, "CENTRY_QUIET", "true")
   329  			})
   330  
   331  			g.It("should not have prefixed environment variable set", func() {
   332  				out := execCentry("optiontest printenv", true, "test/data/runtime_test_environment_prefix.yaml")
   333  				test.AssertStringHasKeyValue(g, out.Stdout, "CENTRY_QUIET", "true") // Make sure we don't prefix internal options
   334  			})
   335  		})
   336  
   337  		g.Describe("--centry-config-log-level=info", func() {
   338  			g.It("should change log level to info", func() {
   339  				expected := `changing loglevel to info (from debug)`
   340  				out := execCentry("--centry-config-log-level=info optiontest printenv", false, defaultManifestPath)
   341  				test.AssertStringContains(g, out.Stderr, expected)
   342  				test.AssertStringHasKeyValue(g, out.Stdout, "CENTRY_CONFIG_LOG_LEVEL", "info")
   343  			})
   344  		})
   345  
   346  		g.Describe("--centry-config-log-level=error", func() {
   347  			g.It("should change log level to error", func() {
   348  				expected := `changing loglevel to error (from debug)`
   349  				out := execCentry("--centry-config-log-level=error optiontest printenv", false, defaultManifestPath)
   350  				test.AssertStringHasKeyValue(g, out.Stdout, "CENTRY_CONFIG_LOG_LEVEL", "error")
   351  				test.AssertStringContains(g, out.Stderr, expected)
   352  			})
   353  		})
   354  	})
   355  
   356  	g.Describe("environment", func() {
   357  		g.Describe("centry environment variables", func() {
   358  			g.It("should have environment variables set", func() {
   359  				out := execCentry("optiontest printenv", false, defaultManifestPath)
   360  				test.AssertStringHasKeyValue(g, out.Stdout, "CENTRY_QUIET", "false")
   361  				test.AssertStringHasKeyValue(g, out.Stdout, "CENTRY_CONFIG_LOG_LEVEL", "debug")
   362  				test.AssertStringHasKeyValue(g, out.Stdout, "CENTRY_SCRIPT_FUNCTION", "optiontest:printenv")
   363  				test.AssertStringHasKeyValue(g, out.Stdout, "CENTRY_SCRIPT_PATH", "commands/option_test.sh")
   364  				test.AssertStringHasKeyValue(g, out.Stdout, "CENTRY_COMMAND_NAME", "optiontest")
   365  			})
   366  		})
   367  	})
   368  
   369  	g.Describe("help", func() {
   370  		g.Describe("call with no arguments", func() {
   371  			g.It("should display help", func() {
   372  				expected := "USAGE:"
   373  				out := execQuiet("")
   374  				test.AssertStringContains(g, out.Stdout, expected)
   375  			})
   376  		})
   377  
   378  		g.Describe("call with -h", func() {
   379  			g.It("should display help", func() {
   380  				expected := "USAGE:"
   381  				out := execQuiet("-h")
   382  				test.AssertStringContains(g, out.Stdout, expected)
   383  			})
   384  		})
   385  
   386  		g.Describe("call with --help", func() {
   387  			g.It("should display help", func() {
   388  				expected := "USAGE:"
   389  				out := execQuiet("--help")
   390  				test.AssertStringContains(g, out.Stdout, expected)
   391  			})
   392  		})
   393  
   394  		g.Describe("output", func() {
   395  			out := execQuiet("")
   396  
   397  			g.It("should display the program name", func() {
   398  				expected := `NAME:
   399     centry`
   400  				test.AssertStringContains(g, out.Stdout, expected)
   401  			})
   402  
   403  			g.It("should display the program description", func() {
   404  				expected := "A manifest file used for testing purposes"
   405  				test.AssertStringContains(g, out.Stdout, expected)
   406  			})
   407  
   408  			g.It("should display available commands", func() {
   409  				expected := `COMMANDS:
   410     commandtest  Command tests
   411     helptest     Help tests
   412     optiontest   Option tests
   413     scripttest   Script tests`
   414  
   415  				test.AssertStringContains(g, out.Stdout, expected)
   416  			})
   417  
   418  			g.It("should display global options", func() {
   419  				expected := `OPTIONS:
   420     --boolopt, -B                A custom option (default: false)
   421     --intopt value, -I value     A custom option (default: 0)
   422     --selectopt1                 Sets the selection to option 1 (default: false)
   423     --selectopt2                 Sets the selection to option 2 (default: false)
   424     --opt1, --o1                 Sets the selection (default: false)
   425     --opt2, --o2                 Sets the selection (default: false)
   426     --stringopt value, -S value  A custom option (default: "foobar")
   427     --help, -h                   Show help (default: false)
   428     --version, -v                Print the version (default: false)`
   429  
   430  				test.AssertStringContains(g, out.Stdout, expected)
   431  			})
   432  
   433  			g.Describe("default config output", func() {
   434  				g.It("should display the default program description", func() {
   435  					expected := `NAME:
   436     name - A declarative cli built using centry`
   437  					out := execQuiet("", "test/data/runtime_test_default_config.yaml")
   438  					test.AssertNoError(g, out.Error)
   439  					test.AssertStringContains(g, out.Stdout, expected)
   440  				})
   441  			})
   442  		})
   443  
   444  		g.Describe("command help output", func() {
   445  			g.It("should display full help", func() {
   446  				expected := `NAME:
   447     centry helptest - Help tests
   448  
   449  USAGE:
   450     centry helptest command [command options] [arguments...]
   451  
   452  COMMANDS:
   453     placeholder  ...
   454     subcommand   Description for subcommand
   455  
   456  OPTIONS:
   457     --help, -h  Show help (default: false)`
   458  
   459  				out := execQuiet("helptest --help")
   460  				test.AssertStringContains(g, out.Stdout, expected)
   461  			})
   462  		})
   463  
   464  		g.Describe("subcommand help output", func() {
   465  			g.It("should display full help", func() {
   466  				expected := `NAME:
   467     centry helptest subcommand - Description for subcommand
   468  
   469  USAGE:
   470     Help text for sub command
   471  
   472  OPTIONS:
   473     --opt1 value, -o value  Help text for opt1 (default: "footothebar")
   474     --help, -h              Show help (default: false)`
   475  
   476  				out := execQuiet("helptest subcommand --help")
   477  				test.AssertStringContains(g, out.Stdout, expected)
   478  			})
   479  		})
   480  
   481  		g.Describe("placeholder help output", func() {
   482  			g.It("should display full help", func() {
   483  				expected := `NAME:
   484     centry helptest placeholder - ...
   485  
   486  USAGE:
   487     centry helptest placeholder command [command options] [arguments...]
   488  
   489  COMMANDS:
   490     subcommand1  Description for placeholder subcommand1
   491     subcommand2  Description for placeholder subcommand2
   492  
   493  OPTIONS:
   494     --help, -h  Show help (default: false)`
   495  
   496  				out := execQuiet("helptest placeholder --help")
   497  				test.AssertStringContains(g, out.Stdout, expected)
   498  			})
   499  		})
   500  
   501  		g.Describe("placeholder subcommand help output", func() {
   502  			g.It("should display full help", func() {
   503  				expected := `NAME:
   504     centry helptest placeholder subcommand1 - Description for placeholder subcommand1
   505  
   506  USAGE:
   507     Help text for placeholder subcommand1
   508  
   509  OPTIONS:
   510     --opt1 value  Help text for opt1
   511     --help, -h    Show help (default: false)`
   512  
   513  				out := execQuiet("helptest placeholder subcommand1 --help")
   514  				test.AssertStringContains(g, out.Stdout, expected)
   515  			})
   516  		})
   517  
   518  		g.Describe("hidden commands", func() {
   519  			g.It("should not display internal or hidden commands", func() {
   520  				out := execQuiet("", "test/data/runtime_test_hidden_commands.yaml")
   521  				expected := `COMMANDS:
   522     helptest  Help tests`
   523  
   524  				test.AssertStringContains(g, out.Stdout, expected)
   525  			})
   526  
   527  			g.It("should not display hidden subcommands", func() {
   528  				out := execQuiet("helptest --help", "test/data/runtime_test_hidden_commands.yaml")
   529  				expected := `COMMANDS:
   530     placeholder  ...
   531     subcommand   Description for subcommand`
   532  
   533  				test.AssertStringContains(g, out.Stdout, expected)
   534  			})
   535  
   536  			g.It("should display internal commands when hide is set to false", func() {
   537  				out := execQuiet("", "test/data/runtime_test_display_internal_commands.yaml")
   538  				expected := `COMMANDS:
   539     internal  Internal centry commands`
   540  
   541  				test.AssertStringContains(g, out.Stdout, expected)
   542  			})
   543  		})
   544  
   545  		g.Describe("hidden options", func() {
   546  			g.It("should not display internal or hidden options", func() {
   547  				out := execQuiet("", "test/data/runtime_test_hidden_options.yaml")
   548  				expected := `OPTIONS:
   549     --visible value  A visible option
   550     --help, -h       Show help (default: false)
   551     --version, -v    Print the version (default: false)`
   552  
   553  				test.AssertStringContains(g, out.Stdout, expected)
   554  			})
   555  
   556  			g.It("should not display hidden subcommand options", func() {
   557  				out := execQuiet("helptest subcommand --help", "test/data/runtime_test_hidden_options.yaml")
   558  				expected := `OPTIONS:
   559     --opt1 value, -o value  Help text for opt1 (default: "footothebar")
   560     --help, -h              Show help (default: false)`
   561  
   562  				test.AssertStringContains(g, out.Stdout, expected)
   563  			})
   564  
   565  			g.It("should display internal options when hide is set to false", func() {
   566  				out := execQuiet("", "test/data/runtime_test_display_internal_options.yaml")
   567  				expected := `OPTIONS:
   568     --centry-config-log-level value  Overrides the log level (default: "info")
   569     --centry-quiet                   Disables logging (default: false)`
   570  
   571  				test.AssertStringContains(g, out.Stdout, expected)
   572  			})
   573  		})
   574  	})
   575  }
   576  
   577  const defaultManifestPath string = "test/data/runtime_test.yaml"
   578  
   579  type execResult struct {
   580  	Source   string
   581  	ExitCode int
   582  	Error    error
   583  	Stdout   string
   584  	Stderr   string
   585  }
   586  
   587  func execQuiet(source string, params ...string) *execResult {
   588  	manifestPath := defaultManifestPath
   589  	if len(params) > 0 {
   590  		if params[0] != "" {
   591  			manifestPath = params[0]
   592  		}
   593  	}
   594  	return execCentry(source, true, manifestPath)
   595  }
   596  
   597  func execWithLogging(source string, params ...string) *execResult {
   598  	manifestPath := defaultManifestPath
   599  	if len(params) > 0 {
   600  		if params[0] != "" {
   601  			manifestPath = params[0]
   602  		}
   603  	}
   604  	return execCentry(source, false, manifestPath)
   605  }
   606  
   607  func execCentry(source string, quiet bool, manifestPath string) *execResult {
   608  	var exitCode int
   609  	var runtimeErr error
   610  
   611  	out := test.CaptureOutput(func() {
   612  		if quiet {
   613  			source = fmt.Sprintf("--centry-quiet %s", source)
   614  		}
   615  		if manifestPath != "" {
   616  			source = fmt.Sprintf("--centry-file %s %s", manifestPath, source)
   617  		}
   618  		context := NewContext(CLI, io.Headless())
   619  		os.Args = strings.Split(fmt.Sprintf("program %s", source), " ")
   620  		runtime, err := NewRuntime(os.Args[1:], context)
   621  		if err != nil {
   622  			exitCode = 1
   623  			runtimeErr = err
   624  		} else {
   625  			exitCode = runtime.Execute()
   626  		}
   627  	})
   628  
   629  	if out.ExitCode > 0 {
   630  		exitCode = out.ExitCode
   631  	}
   632  
   633  	return &execResult{
   634  		Source:   source,
   635  		ExitCode: exitCode,
   636  		Error:    runtimeErr,
   637  		Stdout:   out.Stdout,
   638  		Stderr:   out.Stderr,
   639  	}
   640  }