package cli_test import ( "fmt" "os/exec" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "sneak.berlin/go/secret/internal/secret" ) // TestUnknownSubcommandFails is a regression test for // https://git.eeqj.de/sneak/secret/issues/183: given a subcommand it does not // have, `secret vault`, `secret unlocker`, `secret version` and `secret // generate` printed their help and exited 0, so a script could not tell a // mistyped command from a successful one. Each runs here as the built binary // and must exit 1 naming the subcommand, as an unknown command does at the // top level, and must still print its help and exit 0 when given nothing. func TestUnknownSubcommandFails(t *testing.T) { t.Parallel() stateDir := t.TempDir() // run runs the built binary with args and returns what it printed and // its exit code run := func(args ...string) (string, int) { //nolint:gosec // G204: test executes the freshly built secret binary cmd := exec.CommandContext(t.Context(), secretBinaryPath(t), args...) cmd.Env = []string{secret.EnvStateDir + "=" + stateDir} output, err := cmd.CombinedOutput() if err != nil { var exitErr *exec.ExitError require.ErrorAs(t, err, &exitErr, "secret %v did not run", args) } return string(output), cmd.ProcessState.ExitCode() } tests := []struct { parent string unknown string }{ {parent: "vault", unknown: "improt"}, {parent: "unlocker", unknown: "foo"}, {parent: "version", unknown: "foo"}, {parent: "generate", unknown: "foo"}, } for _, tt := range tests { output, exitCode := run(tt.parent, tt.unknown) assert.Equal(t, 1, exitCode, "secret %s %s should fail:\n%s", tt.parent, tt.unknown, output) assert.Contains(t, output, fmt.Sprintf( "unknown command %q for \"secret %s\"", tt.unknown, tt.parent)) output, exitCode = run(tt.parent) assert.Equal(t, 0, exitCode, "secret %s should succeed:\n%s", tt.parent, output) assert.Contains(t, output, usageHeading, "secret %s should print its help", tt.parent) } }