From 9faa4cb1c8ebd05cde1cf283b2d312d5104cb836 Mon Sep 17 00:00:00 2001 From: Masahiro Nagano Date: Sat, 15 Aug 2026 22:32:32 +0900 Subject: [PATCH 1/5] feat: add Checker and Shipper interfaces, update README, and implement tests --- README.md | 79 ++++++++++++++-- flagrun.go | 125 ++++++++++++++++++++------ flagrun_chek_test.go | 116 ++++++++++++++++++++++++ flagrun_test.go => flagrun_go_test.go | 60 +++++++++++-- go.mod | 1 + go.sum | 2 + 6 files changed, 345 insertions(+), 38 deletions(-) create mode 100644 flagrun_chek_test.go rename flagrun_test.go => flagrun_go_test.go (75%) diff --git a/README.md b/README.md index a6b293e..9efe3e2 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,12 @@ monitoring-forgeのMackerel pluginで広く利用している [go-flags](https:/ - 引数が必要かどうかの判定 - エラー時の終了コード返却(UNKNOWN) +また、用途に応じて以下の3種類のインターフェースを提供します。 + +- `Runner[T]` — 汎用的な `(メッセージ, 終了コード)` を返す形式 +- `Checker` — [mackerelio/checkers](https://github.com/mackerelio/checkers) の `*checkers.Checker` を返す形式 +- `Shipper` — 何も返さず、副作用でメトリクスなどを送信する形式 + ## インストール ```bash @@ -19,7 +25,9 @@ go get github.com/monitoring-forge/flagrun ## 使い方 -`Runner` インターフェースを実装した構造体を `flagrun.Go` に渡します。 +### `Runner[T]` — 汎用的な実行 + +`Runner[T]` インターフェースを実装した構造体を `flagrun.Go` に渡します。 `Run` メソッドの戻り値は `(メッセージ, 終了コード)` です。終了コードが `OK` の場合、メッセージは標準出力へ出力されます。`OK` 以外の場合は標準エラー出力へ出力されます。終了コードは `os.Exit` に渡されます。 @@ -27,7 +35,6 @@ go get github.com/monitoring-forge/flagrun package main import ( - _ "github.com/jessevdk/go-flags" "github.com/monitoring-forge/flagrun" ) @@ -47,21 +54,83 @@ func main() { os.Exit(flagrun.Go( opt, flagrun.Version(version), - flagrun.Commit(commit), + )) +} +``` + +### `Checker` — mackerelio/checkers を使う + +`Checker` インターフェースを実装した構造体を `flagrun.Check` に渡します。 + +`Run` メソッドの戻り値は `*checkers.Checker` です。`Checker.String()` の結果を標準出力へ出力し、`Checker.Status` を終了コードとして返します。 + +```go +package main + +import ( + "github.com/mackerelio/checkers" + "github.com/monitoring-forge/flagrun" +) + +type Opt struct { + Host string `short:"H" long:"host" default:"localhost" description:"Target host"` + Version bool `short:"v" long:"version" description:"Show version"` +} + +func (p *Opt) Run(args []string) *checkers.Checker { + return checkers.Ok("service is reachable") +} + +func main() { + opt := &Opt{} + os.Exit(flagrun.Check( + opt, + flagrun.Version(version), + )) +} +``` + +### `Shipper` — 副作用だけで実行 + +`Shipper` インターフェースを実装した構造体を `flagrun.Ship` に渡します。 + +`Run` メソッドは戻り値を持ちません。メトリクスの送信など、副作用だけを行いたい場合に使います。終了コードは常に `OK` を返します。 + +```go +package main + +import ( + "github.com/monitoring-forge/flagrun" +) + +type Opt struct { + Host string `short:"H" long:"host" default:"localhost" description:"Target host"` + Version bool `short:"v" long:"version" description:"Show version"` +} + +func (p *Opt) Run(args []string) { + // 副作用でメトリクスを送信 +} + +func main() { + opt := &Opt{} + os.Exit(flagrun.Ship( + opt, + flagrun.Version(version), )) } ``` ## オプション -`flagrun.Go` では、以下の関数を使って動作をカスタマイズできます。 +| `flagrun.Go` / `flagrun.Check` / `flagrun.Ship` では、以下の関数を使って動作をカスタマイズできます。 | 関数 | 説明 | |------|------| | `flagrun.Version(version string)` | バージョン表示に使用する文字列を指定します。 | | `flagrun.Commit(commit string)` | コミットハッシュなどを指定します(デフォルト: `dev`)。 | | `flagrun.ArgsRequired()` | コマンドライン引数を必須にします。引数がない場合は UNKNOWN で終了します。 | -| `flagrun.AlwaysStdout()` | `Run` の戻り値を、終了コードに関係なく標準出力へ出力します。 | +| `flagrun.AlwaysStdout()` | `Run` の戻り値を、終了コードに関係なく標準出力へ出力します。`flagrun.Check` では常に標準出力へ出力されるため、このオプションは不要です。 | ## 終了コード diff --git a/flagrun.go b/flagrun.go index d52704f..73c2975 100644 --- a/flagrun.go +++ b/flagrun.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/jessevdk/go-flags" + "github.com/mackerelio/checkers" ) const ( @@ -19,9 +20,19 @@ const ( UNKNOWN ) -type Runner interface { +type Runner[T any] interface { // Run executes the command with the provided flags and arguments. - Run([]string) (string, int) + Run([]string) (T, int) +} + +type Checker interface { + // Check executes the command with the provided flags and arguments. + Run([]string) *checkers.Checker +} + +type Shipper interface { + // Run executes the command with the provided flags and arguments. + Run([]string) } type Flagrun struct { @@ -72,20 +83,8 @@ func printLine(w io.Writer, s string) error { return err } -func Go(opt Runner, options ...FlagrunOptions) int { - f, msg, code := internalGo(os.Args[1:], os.Stdout, os.Stderr, opt, options...) - if msg != "" { - if code == OK || f.AlwaysStdout { - _ = printLine(os.Stdout, msg) - } else { - _ = printLine(os.Stderr, msg) - } - } - return code -} - // hasBooleanVersionField checks if the struct has a Version field of type bool and its value is true -func hasBooleanVersionField(opt Runner) bool { +func hasBooleanVersionField(opt any) bool { if opt == nil { return false } @@ -134,13 +133,7 @@ func buildCommitHash() string { return commit } -func internalGo( - argv []string, - stdout io.Writer, - stderr io.Writer, - opt Runner, - options ...FlagrunOptions, -) (*Flagrun, string, int) { +func buildFlagrun(options ...FlagrunOptions) *Flagrun { f := &Flagrun{ Commit: buildCommitHash(), Version: "unknown", @@ -148,7 +141,14 @@ func internalGo( for _, option := range options { option(f) } + return f +} + +func nullint(i int) *int { + return &i +} +func (f *Flagrun) parseArgs(argv []string, stdout, stderr io.Writer, opt any) ([]string, *int) { psr := flags.NewParser(opt, flags.HelpFlag|flags.PassDoubleDash) if f.ArgsRequired { psr.Usage = "[OPTIONS] -- command [args...]" @@ -165,18 +165,89 @@ func internalGo( runtime.GOARCH, runtime.Version(), f.Commit) - return f, "", OK + return nil, nullint(OK) } else if flags.WroteHelp(err) { fmt.Fprintf(stdout, "%v\n", err) - return f, "", OK + return nil, nullint(OK) } else if err != nil { fmt.Fprintf(stderr, "%v\n", err) - return f, "", UNKNOWN + return nil, nullint(UNKNOWN) } else if f.ArgsRequired && len(args) == 0 { fmt.Fprintf(stderr, "command is required\n") psr.WriteHelp(stderr) - return f, "", UNKNOWN + return nil, nullint(UNKNOWN) + } + return args, nil +} + +func internalGo[T any]( + f *Flagrun, + argv []string, + stdout io.Writer, + stderr io.Writer, + opt Runner[T], +) (string, int) { + args, c := f.parseArgs(argv, stdout, stderr, opt) + if c != nil { + return "", *c } msg, code := opt.Run(args) - return f, msg, code + return fmt.Sprintf("%v", msg), code +} + +// Checker return *checkers.Checker +func (f *Flagrun) internalChecker( + argv []string, + stdout io.Writer, + stderr io.Writer, + opt Checker, +) (string, int) { + args, c := f.parseArgs(argv, stdout, stderr, opt) + if c != nil { + return "", *c + } + f.AlwaysStdout = true + chk := opt.Run(args) + return chk.String(), int(chk.Status) +} + +func (f *Flagrun) internalShipper( + argv []string, + stdout io.Writer, + stderr io.Writer, + opt Shipper, +) { + args, c := f.parseArgs(argv, stdout, stderr, opt) + if c != nil { + return + } + opt.Run(args) +} + +func Go[T any](opt Runner[T], options ...FlagrunOptions) int { + f := buildFlagrun(options...) + msg, code := internalGo(f, os.Args[1:], os.Stdout, os.Stderr, opt) + if msg != "" { + if code == OK || f.AlwaysStdout { + _ = printLine(os.Stdout, msg) + } else { + _ = printLine(os.Stderr, msg) + } + } + return code +} + +func Check(opt Checker, options ...FlagrunOptions) int { + f := buildFlagrun(options...) + msg, code := f.internalChecker(os.Args[1:], os.Stdout, os.Stderr, opt) + if msg != "" { + _ = printLine(os.Stdout, msg) + } + return code +} + +func Ship(opt Shipper, options ...FlagrunOptions) int { + f := buildFlagrun(options...) + f.internalShipper(os.Args[1:], os.Stdout, os.Stderr, opt) + return OK } diff --git a/flagrun_chek_test.go b/flagrun_chek_test.go new file mode 100644 index 0000000..d6e50f3 --- /dev/null +++ b/flagrun_chek_test.go @@ -0,0 +1,116 @@ +package flagrun + +import ( + "bytes" + "os" + "testing" + + "github.com/mackerelio/checkers" + "github.com/stretchr/testify/assert" +) + +type testChecker struct { + Version bool `short:"v" long:"version" description:"Show version"` + status checkers.Status + msg string +} + +func (c *testChecker) Run(_ []string) *checkers.Checker { + return checkers.NewChecker(c.status, c.msg) +} + +type testShipper struct { + Version bool `short:"v" long:"version" description:"Show version"` + ran bool +} + +func (s *testShipper) Run(_ []string) { + s.ran = true +} + +func TestInternalChecker(t *testing.T) { + tests := []struct { + name string + status checkers.Status + msg string + wantStdout string + wantCode int + }{ + { + name: "ok", + status: checkers.OK, + msg: "service is ok", + wantStdout: " OK: service is ok", + wantCode: OK, + }, + { + name: "warning", + status: checkers.WARNING, + msg: "service is warning", + wantStdout: " WARNING: service is warning", + wantCode: WARNING, + }, + { + name: "critical", + status: checkers.CRITICAL, + msg: "service is critical", + wantStdout: " CRITICAL: service is critical", + wantCode: CRITICAL, + }, + { + name: "unknown", + status: checkers.UNKNOWN, + msg: "service is unknown", + wantStdout: " UNKNOWN: service is unknown", + wantCode: UNKNOWN, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + f := buildFlagrun() + o := &testChecker{status: tt.status, msg: tt.msg} + var stdout bytes.Buffer + var stderr bytes.Buffer + msg, code := f.internalChecker([]string{}, &stdout, &stderr, o) + stdoutStr := stdout.String() + + assert.Equal(t, "", stdoutStr) + assert.Equal(t, tt.wantStdout, msg) + assert.Equal(t, tt.wantCode, code) + }) + } +} + +func TestInternalShipper(t *testing.T) { + f := buildFlagrun() + o := &testShipper{} + var stdout bytes.Buffer + var stderr bytes.Buffer + f.internalShipper([]string{}, &stdout, &stderr, o) + + assert.True(t, o.ran) +} + +func TestShip(t *testing.T) { + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + os.Args = []string{"test"} + + o := &testShipper{} + code := Ship(o) + + assert.Equal(t, OK, code) + assert.True(t, o.ran) +} + +func TestCheck(t *testing.T) { + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + os.Args = []string{"test"} + + o := &testChecker{status: checkers.OK, msg: "ok"} + code := Check(o) + + assert.Equal(t, OK, code) +} diff --git a/flagrun_test.go b/flagrun_go_test.go similarity index 75% rename from flagrun_test.go rename to flagrun_go_test.go index c0a2001..27ca61f 100644 --- a/flagrun_test.go +++ b/flagrun_go_test.go @@ -2,6 +2,7 @@ package flagrun import ( "bytes" + "fmt" "testing" "github.com/stretchr/testify/assert" @@ -75,7 +76,7 @@ func TestInternalGo(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - o := &testRunner{} + runner := &testRunner{} options := []FlagrunOptions{} if tt.wantArgs { options = append(options, ArgsRequired()) @@ -85,7 +86,8 @@ func TestInternalGo(t *testing.T) { } var stdout bytes.Buffer var stderr bytes.Buffer - f, msg, code := internalGo(tt.args, &stdout, &stderr, o, options...) + f := buildFlagrun(options...) + msg, code := internalGo(f, tt.args, &stdout, &stderr, runner) stdoutStr := stdout.String() stderrStr := stderr.String() require.NotNil(t, f, "%s Flagrun instance should not be nil", tt.name) @@ -94,7 +96,7 @@ func TestInternalGo(t *testing.T) { assert.Contains(t, stderrStr, tt.wantStderr, "%s stderr", tt.name) assert.Equal(t, code, tt.wantCode, "%s code", tt.name) if tt.wantArgs { - assert.Equal(t, tt.wantArgv, o.argv, "%s argv", tt.name) + assert.Equal(t, tt.wantArgv, runner.argv, "%s argv", tt.name) } }) } @@ -113,12 +115,13 @@ func TestInternalGoWithRequiredParameters(t *testing.T) { o := &requiredRunner{} var stdout bytes.Buffer var stderr bytes.Buffer - f, msg, code := internalGo([]string{}, &stdout, &stderr, o) + f := buildFlagrun() + msg, code := internalGo(f, []string{}, &stdout, &stderr, o) stdoutStr := stdout.String() stderrStr := stderr.String() assert.NotNil(t, f, "Flagrun instance should not be nil") - assert.Equal(t, "", msg) + assert.Equal(t, "", fmt.Sprintf("%v", msg), "msg should be empty") assert.Contains(t, stdoutStr, "") assert.Contains(t, stderrStr, "the required flag `-r, --required") assert.Equal(t, UNKNOWN, code) @@ -148,7 +151,7 @@ func (r *stringVersionRunner) Run(_ []string) (string, int) { func TestHasBooleanVersionField(t *testing.T) { tests := []struct { name string - opt Runner + opt Runner[string] want bool }{ { @@ -184,3 +187,48 @@ func TestHasBooleanVersionField(t *testing.T) { }) } } + +type anyMessageRunner struct { + Switch bool `short:"s" long:"switch" description:"A boolean switch"` +} + +func (r *anyMessageRunner) Run(_ []string) (any, int) { + if r.Switch { + return fmt.Errorf("Switch is %v", r.Switch), CRITICAL + } + return "Switch is OFF", OK +} + +func TestInternalGoWithAnyMessageType(t *testing.T) { + tests := []struct { + name string + args []string + wantMsg string + wantCode int + }{ + { + name: "Switch is OFF", + args: []string{}, + wantMsg: "Switch is OFF", + wantCode: OK, + }, + { + name: "Switch is ON", + args: []string{"--switch"}, + wantMsg: "Switch is true", + wantCode: CRITICAL, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + o := &anyMessageRunner{} + var stdout bytes.Buffer + var stderr bytes.Buffer + f := buildFlagrun() + msg, code := internalGo(f, tt.args, &stdout, &stderr, o) // T is inferred + assert.Equal(t, tt.wantMsg, msg, "%s msg", tt.name) + assert.Equal(t, code, tt.wantCode, "%s code", tt.name) + }) + } +} diff --git a/go.mod b/go.mod index 481a656..01c749e 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( ) require ( + github.com/mackerelio/checkers v0.2.1 github.com/stretchr/testify v1.11.1 golang.org/x/sys v0.47.0 // indirect ) diff --git a/go.sum b/go.sum index 98f3e17..00f5f80 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4= github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc= +github.com/mackerelio/checkers v0.2.1 h1:vRXzAT+CEyaLjSrHVxKUBjyWq1kfo8QcI8ZoSKZATQs= +github.com/mackerelio/checkers v0.2.1/go.mod h1:CW3k/5bvHhxDrfKgWvMvNH0R51zco141ZVxlI7o/KAc= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= From 763d846d872029301e3645d76f7688e4a00f73b9 Mon Sep 17 00:00:00 2001 From: Masahiro Nagano Date: Sat, 15 Aug 2026 22:36:00 +0900 Subject: [PATCH 2/5] Update flagrun.go Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- flagrun.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/flagrun.go b/flagrun.go index 73c2975..da02ddf 100644 --- a/flagrun.go +++ b/flagrun.go @@ -208,6 +208,9 @@ func (f *Flagrun) internalChecker( } f.AlwaysStdout = true chk := opt.Run(args) + if chk == nil { + return "UNKNOWN: checker returned nil", UNKNOWN + } return chk.String(), int(chk.Status) } From a1efaf410833ecd2db120af70639cadfc0fc129b Mon Sep 17 00:00:00 2001 From: Masahiro Nagano Date: Sat, 15 Aug 2026 22:46:06 +0900 Subject: [PATCH 3/5] fix: return status code from internalShipper and update Ship function --- flagrun.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flagrun.go b/flagrun.go index da02ddf..7b5a331 100644 --- a/flagrun.go +++ b/flagrun.go @@ -219,12 +219,13 @@ func (f *Flagrun) internalShipper( stdout io.Writer, stderr io.Writer, opt Shipper, -) { +) int { args, c := f.parseArgs(argv, stdout, stderr, opt) if c != nil { - return + return *c } opt.Run(args) + return OK } func Go[T any](opt Runner[T], options ...FlagrunOptions) int { @@ -251,6 +252,5 @@ func Check(opt Checker, options ...FlagrunOptions) int { func Ship(opt Shipper, options ...FlagrunOptions) int { f := buildFlagrun(options...) - f.internalShipper(os.Args[1:], os.Stdout, os.Stderr, opt) - return OK + return f.internalShipper(os.Args[1:], os.Stdout, os.Stderr, opt) } From d6d0b1ea79d74e33f11687fe26970f900f129037 Mon Sep 17 00:00:00 2001 From: Masahiro Nagano Date: Sat, 15 Aug 2026 22:54:43 +0900 Subject: [PATCH 4/5] Update flagrun.go Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- flagrun.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/flagrun.go b/flagrun.go index 7b5a331..b4964d5 100644 --- a/flagrun.go +++ b/flagrun.go @@ -211,7 +211,16 @@ func (f *Flagrun) internalChecker( if chk == nil { return "UNKNOWN: checker returned nil", UNKNOWN } - return chk.String(), int(chk.Status) + switch chk.Status { + case checkers.OK: + return chk.String(), OK + case checkers.WARNING: + return chk.String(), WARNING + case checkers.CRITICAL: + return chk.String(), CRITICAL + default: + return chk.String(), UNKNOWN + } } func (f *Flagrun) internalShipper( From 8110eb390294ecf49f788dcfb5038a05d6ce6e14 Mon Sep 17 00:00:00 2001 From: Masahiro Nagano Date: Sat, 15 Aug 2026 23:09:06 +0900 Subject: [PATCH 5/5] feat: add tests for internalChecker and internalShipper functions --- flagrun_chek_test.go => flagrun_check_test.go | 38 +++++------ flagrun_shipper_test.go | 65 +++++++++++++++++++ 2 files changed, 82 insertions(+), 21 deletions(-) rename flagrun_chek_test.go => flagrun_check_test.go (74%) create mode 100644 flagrun_shipper_test.go diff --git a/flagrun_chek_test.go b/flagrun_check_test.go similarity index 74% rename from flagrun_chek_test.go rename to flagrun_check_test.go index d6e50f3..0bf826e 100644 --- a/flagrun_chek_test.go +++ b/flagrun_check_test.go @@ -19,15 +19,6 @@ func (c *testChecker) Run(_ []string) *checkers.Checker { return checkers.NewChecker(c.status, c.msg) } -type testShipper struct { - Version bool `short:"v" long:"version" description:"Show version"` - ran bool -} - -func (s *testShipper) Run(_ []string) { - s.ran = true -} - func TestInternalChecker(t *testing.T) { tests := []struct { name string @@ -82,26 +73,31 @@ func TestInternalChecker(t *testing.T) { } } -func TestInternalShipper(t *testing.T) { +func TestInternalCheckerHelp(t *testing.T) { f := buildFlagrun() - o := &testShipper{} + o := &testChecker{} var stdout bytes.Buffer var stderr bytes.Buffer - f.internalShipper([]string{}, &stdout, &stderr, o) + msg, code := f.internalChecker([]string{"--help"}, &stdout, &stderr, o) + stdoutStr := stdout.String() - assert.True(t, o.ran) + assert.Equal(t, "", msg) + assert.Equal(t, OK, code) + assert.Contains(t, stdoutStr, "Show version") + assert.Contains(t, stdoutStr, "Show this help message") } -func TestShip(t *testing.T) { - oldArgs := os.Args - defer func() { os.Args = oldArgs }() - os.Args = []string{"test"} - - o := &testShipper{} - code := Ship(o) +func TestInternalCheckerVersion(t *testing.T) { + f := buildFlagrun(Version("1.0.0")) + o := &testChecker{} + var stdout bytes.Buffer + var stderr bytes.Buffer + msg, code := f.internalChecker([]string{"--version"}, &stdout, &stderr, o) + stdoutStr := stdout.String() + assert.Equal(t, "", msg) assert.Equal(t, OK, code) - assert.True(t, o.ran) + assert.Contains(t, stdoutStr, "test-1.0.0") } func TestCheck(t *testing.T) { diff --git a/flagrun_shipper_test.go b/flagrun_shipper_test.go new file mode 100644 index 0000000..fd88aec --- /dev/null +++ b/flagrun_shipper_test.go @@ -0,0 +1,65 @@ +package flagrun + +import ( + "bytes" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +type testShipper struct { + Version bool `short:"v" long:"version" description:"Show version"` + ran bool +} + +func (s *testShipper) Run(_ []string) { + s.ran = true +} + +func TestInternalShipper(t *testing.T) { + f := buildFlagrun() + o := &testShipper{} + var stdout bytes.Buffer + var stderr bytes.Buffer + f.internalShipper([]string{}, &stdout, &stderr, o) + + assert.True(t, o.ran) +} + +func TestInternalShipperHelp(t *testing.T) { + f := buildFlagrun() + o := &testShipper{} + var stdout bytes.Buffer + var stderr bytes.Buffer + f.internalShipper([]string{"--help"}, &stdout, &stderr, o) + stdoutStr := stdout.String() + + assert.False(t, o.ran) + assert.Contains(t, stdoutStr, "Show version") + assert.Contains(t, stdoutStr, "Show this help message") +} + +func TestInternalShipperVersion(t *testing.T) { + f := buildFlagrun(Version("1.0.0")) + o := &testShipper{} + var stdout bytes.Buffer + var stderr bytes.Buffer + f.internalShipper([]string{"--version"}, &stdout, &stderr, o) + stdoutStr := stdout.String() + + assert.False(t, o.ran) + assert.Contains(t, stdoutStr, "test-1.0.0") +} + +func TestShip(t *testing.T) { + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + os.Args = []string{"test"} + + o := &testShipper{} + code := Ship(o) + + assert.Equal(t, OK, code) + assert.True(t, o.ran) +}