summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/example_test.go12
-rw-r--r--test/parse_test.go88
-rw-r--r--test/usage_test.go375
3 files changed, 446 insertions, 29 deletions
diff --git a/test/example_test.go b/test/example_test.go
index 4bd7632..9b72b90 100644
--- a/test/example_test.go
+++ b/test/example_test.go
@@ -163,6 +163,7 @@ func Example_helpText() {
// This is only necessary when running inside golang's runnable example harness
mustParseExit = func(int) {}
+ mustParseOut = os.Stdout
MustParse(&args)
@@ -195,17 +196,17 @@ func Example_helpPlaceholder() {
// This is only necessary when running inside golang's runnable example harness
mustParseExit = func(int) {}
+ mustParseOut = os.Stdout
MustParse(&args)
// output:
-
// Usage: example [--optimize LEVEL] [--maxjobs N] SRC [DST [DST ...]]
-
+ //
// Positional arguments:
// SRC
// DST
-
+ //
// Options:
// --optimize LEVEL, -O LEVEL
// optimization level
@@ -235,6 +236,7 @@ func Example_helpTextWithSubcommand() {
// This is only necessary when running inside golang's runnable example harness
mustParseExit = func(int) {}
+ mustParseOut = os.Stdout
MustParse(&args)
@@ -272,6 +274,7 @@ func Example_helpTextWhenUsingSubcommand() {
// This is only necessary when running inside golang's runnable example harness
mustParseExit = func(int) {}
+ mustParseOut = os.Stdout
MustParse(&args)
@@ -392,6 +395,7 @@ func Example_errorText() {
// This is only necessary when running inside golang's runnable example harness
mustParseExit = func(int) {}
+ mustParseOut = os.Stdout
MustParse(&args)
@@ -415,6 +419,7 @@ func Example_errorTextForSubcommand() {
// This is only necessary when running inside golang's runnable example harness
mustParseExit = func(int) {}
+ mustParseOut = os.Stdout
MustParse(&args)
@@ -450,6 +455,7 @@ func Example_subcommand() {
// This is only necessary when running inside golang's runnable example harness
mustParseExit = func(int) {}
+ mustParseOut = os.Stdout
MustParse(&args)
diff --git a/test/parse_test.go b/test/parse_test.go
index d53b483..249cbf3 100644
--- a/test/parse_test.go
+++ b/test/parse_test.go
@@ -28,11 +28,11 @@ func parse(cmdline string, dest interface{}) error {
}
func pparse(cmdline string, dest interface{}) (*Parser, error) {
- return parseWithEnv(cmdline, nil, dest)
+ return parseWithEnv(Config{}, cmdline, nil, dest)
}
-func parseWithEnv(cmdline string, env []string, dest interface{}) (*Parser, error) {
- p, err := NewParser(Config{}, dest)
+func parseWithEnv(config Config, cmdline string, env []string, dest interface{}) (*Parser, error) {
+ p, err := NewParser(config, dest)
if err != nil {
return nil, err
}
@@ -231,7 +231,7 @@ func TestRequiredWithEnvOnly(t *testing.T) {
var args struct {
Foo string `arg:"required,--,-,env:FOO"`
}
- _, err := parseWithEnv("", []string{}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{}, &args)
require.Error(t, err, "environment variable FOO is required")
}
@@ -609,6 +609,15 @@ func TestNoMoreOptionsBeforeHelp(t *testing.T) {
assert.NotEqual(t, ErrHelp, err)
}
+func TestNoMoreOptionsTwice(t *testing.T) {
+ var args struct {
+ X []string `arg:"positional"`
+ }
+ err := parse("-- --", &args)
+ require.NoError(t, err)
+ assert.Equal(t, []string{"--"}, args.X)
+}
+
func TestHelpFlag(t *testing.T) {
var args struct {
Foo string
@@ -692,11 +701,26 @@ func TestMustParse(t *testing.T) {
assert.NotNil(t, parser)
}
+func TestMustParseError(t *testing.T) {
+ var args struct {
+ Foo []string `default:""`
+ }
+ var exitCode int
+ var stdout bytes.Buffer
+ mustParseExit = func(code int) { exitCode = code }
+ mustParseOut = &stdout
+ os.Args = []string{"example"}
+ parser := MustParse(&args)
+ assert.Nil(t, parser)
+ assert.Equal(t, 2, exitCode)
+ assert.Contains(t, stdout.String(), "default values are not supported for slice or map fields")
+}
+
func TestEnvironmentVariable(t *testing.T) {
var args struct {
Foo string `arg:"env"`
}
- _, err := parseWithEnv("", []string{"FOO=bar"}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{"FOO=bar"}, &args)
require.NoError(t, err)
assert.Equal(t, "bar", args.Foo)
}
@@ -705,7 +729,7 @@ func TestEnvironmentVariableNotPresent(t *testing.T) {
var args struct {
NotPresent string `arg:"env"`
}
- _, err := parseWithEnv("", nil, &args)
+ _, err := parseWithEnv(Config{}, "", nil, &args)
require.NoError(t, err)
assert.Equal(t, "", args.NotPresent)
}
@@ -714,7 +738,7 @@ func TestEnvironmentVariableOverrideName(t *testing.T) {
var args struct {
Foo string `arg:"env:BAZ"`
}
- _, err := parseWithEnv("", []string{"BAZ=bar"}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{"BAZ=bar"}, &args)
require.NoError(t, err)
assert.Equal(t, "bar", args.Foo)
}
@@ -723,7 +747,7 @@ func TestEnvironmentVariableOverrideArgument(t *testing.T) {
var args struct {
Foo string `arg:"env"`
}
- _, err := parseWithEnv("--foo zzz", []string{"FOO=bar"}, &args)
+ _, err := parseWithEnv(Config{}, "--foo zzz", []string{"FOO=bar"}, &args)
require.NoError(t, err)
assert.Equal(t, "zzz", args.Foo)
}
@@ -732,7 +756,7 @@ func TestEnvironmentVariableError(t *testing.T) {
var args struct {
Foo int `arg:"env"`
}
- _, err := parseWithEnv("", []string{"FOO=bar"}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{"FOO=bar"}, &args)
assert.Error(t, err)
}
@@ -740,7 +764,7 @@ func TestEnvironmentVariableRequired(t *testing.T) {
var args struct {
Foo string `arg:"env,required"`
}
- _, err := parseWithEnv("", []string{"FOO=bar"}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{"FOO=bar"}, &args)
require.NoError(t, err)
assert.Equal(t, "bar", args.Foo)
}
@@ -749,7 +773,7 @@ func TestEnvironmentVariableSliceArgumentString(t *testing.T) {
var args struct {
Foo []string `arg:"env"`
}
- _, err := parseWithEnv("", []string{`FOO=bar,"baz, qux"`}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{`FOO=bar,"baz, qux"`}, &args)
require.NoError(t, err)
assert.Equal(t, []string{"bar", "baz, qux"}, args.Foo)
}
@@ -758,7 +782,7 @@ func TestEnvironmentVariableSliceEmpty(t *testing.T) {
var args struct {
Foo []string `arg:"env"`
}
- _, err := parseWithEnv("", []string{`FOO=`}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{`FOO=`}, &args)
require.NoError(t, err)
assert.Len(t, args.Foo, 0)
}
@@ -767,7 +791,7 @@ func TestEnvironmentVariableSliceArgumentInteger(t *testing.T) {
var args struct {
Foo []int `arg:"env"`
}
- _, err := parseWithEnv("", []string{`FOO=1,99`}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{`FOO=1,99`}, &args)
require.NoError(t, err)
assert.Equal(t, []int{1, 99}, args.Foo)
}
@@ -776,7 +800,7 @@ func TestEnvironmentVariableSliceArgumentFloat(t *testing.T) {
var args struct {
Foo []float32 `arg:"env"`
}
- _, err := parseWithEnv("", []string{`FOO=1.1,99.9`}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{`FOO=1.1,99.9`}, &args)
require.NoError(t, err)
assert.Equal(t, []float32{1.1, 99.9}, args.Foo)
}
@@ -785,7 +809,7 @@ func TestEnvironmentVariableSliceArgumentBool(t *testing.T) {
var args struct {
Foo []bool `arg:"env"`
}
- _, err := parseWithEnv("", []string{`FOO=true,false,0,1`}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{`FOO=true,false,0,1`}, &args)
require.NoError(t, err)
assert.Equal(t, []bool{true, false, false, true}, args.Foo)
}
@@ -794,7 +818,7 @@ func TestEnvironmentVariableSliceArgumentWrongCsv(t *testing.T) {
var args struct {
Foo []int `arg:"env"`
}
- _, err := parseWithEnv("", []string{`FOO=1,99\"`}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{`FOO=1,99\"`}, &args)
assert.Error(t, err)
}
@@ -802,7 +826,7 @@ func TestEnvironmentVariableSliceArgumentWrongType(t *testing.T) {
var args struct {
Foo []bool `arg:"env"`
}
- _, err := parseWithEnv("", []string{`FOO=one,two`}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{`FOO=one,two`}, &args)
assert.Error(t, err)
}
@@ -810,7 +834,7 @@ func TestEnvironmentVariableMap(t *testing.T) {
var args struct {
Foo map[int]string `arg:"env"`
}
- _, err := parseWithEnv("", []string{`FOO=1=one,99=ninetynine`}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{`FOO=1=one,99=ninetynine`}, &args)
require.NoError(t, err)
assert.Len(t, args.Foo, 2)
assert.Equal(t, "one", args.Foo[1])
@@ -821,11 +845,21 @@ func TestEnvironmentVariableEmptyMap(t *testing.T) {
var args struct {
Foo map[int]string `arg:"env"`
}
- _, err := parseWithEnv("", []string{`FOO=`}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{`FOO=`}, &args)
require.NoError(t, err)
assert.Len(t, args.Foo, 0)
}
+func TestEnvironmentVariableWithPrefix(t *testing.T) {
+ var args struct {
+ Foo string `arg:"env"`
+ }
+
+ _, err := parseWithEnv(Config{EnvPrefix: "MYAPP_"}, "", []string{"MYAPP_FOO=bar"}, &args)
+ require.NoError(t, err)
+ assert.Equal(t, "bar", args.Foo)
+}
+
func TestEnvironmentVariableIgnored(t *testing.T) {
var args struct {
Foo string `arg:"env"`
@@ -858,7 +892,7 @@ func TestRequiredEnvironmentOnlyVariableIsMissing(t *testing.T) {
Foo string `arg:"required,--,env:FOO"`
}
- _, err := parseWithEnv("", []string{""}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{""}, &args)
assert.Error(t, err)
}
@@ -867,7 +901,7 @@ func TestOptionalEnvironmentOnlyVariable(t *testing.T) {
Foo string `arg:"env:FOO"`
}
- _, err := parseWithEnv("", []string{}, &args)
+ _, err := parseWithEnv(Config{}, "", []string{}, &args)
assert.NoError(t, err)
}
@@ -906,7 +940,7 @@ func TestParserMustParse(t *testing.T) {
}{
{name: "help", args: struct{}{}, cmdLine: []string{"--help"}, code: 0, output: "display this help and exit"},
{name: "version", args: versioned{}, cmdLine: []string{"--version"}, code: 0, output: "example 3.2.1"},
- {name: "invalid", args: struct{}{}, cmdLine: []string{"invalid"}, code: -1, output: ""},
+ {name: "invalid", args: struct{}{}, cmdLine: []string{"invalid"}, code: 2, output: ""},
}
for _, tt := range tests {
@@ -1556,7 +1590,7 @@ func TestMustParseInvalidParser(t *testing.T) {
}
parser := mustParse(Config{Out: &stdout, Exit: exit}, &args)
assert.Nil(t, parser)
- assert.Equal(t, -1, exitCode)
+ assert.Equal(t, 2, exitCode)
}
func TestMustParsePrintsHelp(t *testing.T) {
@@ -1737,3 +1771,11 @@ func TestSubcommandGlobalFlag_InCommand_Strict_Inner(t *testing.T) {
require.NotNil(t, args.Sub)
assert.True(t, args.Sub.Guard)
}
+
+func TestExitFunctionAndOutStreamGetFilledIn(t *testing.T) {
+ var args struct{}
+ p, err := NewParser(Config{}, &args)
+ require.NoError(t, err)
+ assert.NotNil(t, p.config.Exit) // go prohibits function pointer comparison
+ assert.Equal(t, p.config.Out, os.Stdout)
+}
diff --git a/test/usage_test.go b/test/usage_test.go
index b1693a9..e276e1a 100644
--- a/test/usage_test.go
+++ b/test/usage_test.go
@@ -237,7 +237,7 @@ func (versioned) Version() string {
}
func TestUsageWithVersion(t *testing.T) {
- expectedUsage := "example 3.2.1\nUsage: example"
+ expectedUsage := "Usage: example"
expectedHelp := `
example 3.2.1
@@ -260,6 +260,233 @@ Options:
assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
}
+func TestUsageWithUserDefinedVersionFlag(t *testing.T) {
+ expectedUsage := "Usage: example [--version]"
+
+ expectedHelp := `
+Usage: example [--version]
+
+Options:
+ --version this is a user-defined version flag
+ --help, -h display this help and exit
+`
+
+ var args struct {
+ ShowVersion bool `arg:"--version" help:"this is a user-defined version flag"`
+ }
+
+ os.Args[0] = "example"
+ p, err := NewParser(Config{}, &args)
+ require.NoError(t, err)
+
+ var help bytes.Buffer
+ p.WriteHelp(&help)
+ assert.Equal(t, expectedHelp[1:], help.String())
+
+ var usage bytes.Buffer
+ p.WriteUsage(&usage)
+ assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
+}
+
+func TestUsageWithVersionAndUserDefinedVersionFlag(t *testing.T) {
+ expectedUsage := "Usage: example [--version]"
+
+ expectedHelp := `
+Usage: example [--version]
+
+Options:
+ --version this is a user-defined version flag
+ --help, -h display this help and exit
+`
+
+ var args struct {
+ versioned
+ ShowVersion bool `arg:"--version" help:"this is a user-defined version flag"`
+ }
+
+ os.Args[0] = "example"
+ p, err := NewParser(Config{}, &args)
+ require.NoError(t, err)
+
+ var help bytes.Buffer
+ p.WriteHelp(&help)
+ assert.Equal(t, expectedHelp[1:], help.String())
+
+ var usage bytes.Buffer
+ p.WriteUsage(&usage)
+ assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
+}
+
+type subcommand struct {
+ Number int `arg:"-n,--number" help:"compute something on the given number"`
+}
+
+func TestUsageWithVersionAndSubcommand(t *testing.T) {
+ expectedUsage := "Usage: example <command> [<args>]"
+
+ expectedHelp := `
+example 3.2.1
+Usage: example <command> [<args>]
+
+Options:
+ --help, -h display this help and exit
+ --version display version and exit
+
+Commands:
+ cmd
+`
+
+ var args struct {
+ versioned
+ Cmd *subcommand `arg:"subcommand"`
+ }
+
+ os.Args[0] = "example"
+ p, err := NewParser(Config{}, &args)
+ require.NoError(t, err)
+
+ var help bytes.Buffer
+ p.WriteHelp(&help)
+ assert.Equal(t, expectedHelp[1:], help.String())
+
+ var usage bytes.Buffer
+ p.WriteUsage(&usage)
+ assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
+
+ expectedUsage = "Usage: example cmd [--number NUMBER]"
+
+ expectedHelp = `
+example 3.2.1
+Usage: example cmd [--number NUMBER]
+
+Options:
+ --number NUMBER, -n NUMBER
+ compute something on the given number
+ --help, -h display this help and exit
+ --version display version and exit
+`
+ _ = p.Parse([]string{"cmd"})
+
+ help = bytes.Buffer{}
+ p.WriteHelp(&help)
+ assert.Equal(t, expectedHelp[1:], help.String())
+
+ usage = bytes.Buffer{}
+ p.WriteUsage(&usage)
+ assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
+}
+
+func TestUsageWithUserDefinedVersionFlagAndSubcommand(t *testing.T) {
+ expectedUsage := "Usage: example [--version] <command> [<args>]"
+
+ expectedHelp := `
+Usage: example [--version] <command> [<args>]
+
+Options:
+ --version this is a user-defined version flag
+ --help, -h display this help and exit
+
+Commands:
+ cmd
+`
+
+ var args struct {
+ Cmd *subcommand `arg:"subcommand"`
+ ShowVersion bool `arg:"--version" help:"this is a user-defined version flag"`
+ }
+
+ os.Args[0] = "example"
+ p, err := NewParser(Config{}, &args)
+ require.NoError(t, err)
+
+ var help bytes.Buffer
+ p.WriteHelp(&help)
+ assert.Equal(t, expectedHelp[1:], help.String())
+
+ var usage bytes.Buffer
+ p.WriteUsage(&usage)
+ assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
+
+ expectedUsage = "Usage: example cmd [--number NUMBER]"
+
+ expectedHelp = `
+Usage: example cmd [--number NUMBER]
+
+Options:
+ --number NUMBER, -n NUMBER
+ compute something on the given number
+
+Global options:
+ --version this is a user-defined version flag
+ --help, -h display this help and exit
+`
+ _ = p.Parse([]string{"cmd"})
+
+ help = bytes.Buffer{}
+ p.WriteHelp(&help)
+ assert.Equal(t, expectedHelp[1:], help.String())
+
+ usage = bytes.Buffer{}
+ p.WriteUsage(&usage)
+ assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
+}
+
+func TestUsageWithVersionAndUserDefinedVersionFlagAndSubcommand(t *testing.T) {
+ expectedUsage := "Usage: example [--version] <command> [<args>]"
+
+ expectedHelp := `
+Usage: example [--version] <command> [<args>]
+
+Options:
+ --version this is a user-defined version flag
+ --help, -h display this help and exit
+
+Commands:
+ cmd
+`
+
+ var args struct {
+ versioned
+ Cmd *subcommand `arg:"subcommand"`
+ ShowVersion bool `arg:"--version" help:"this is a user-defined version flag"`
+ }
+
+ os.Args[0] = "example"
+ p, err := NewParser(Config{}, &args)
+ require.NoError(t, err)
+
+ var help bytes.Buffer
+ p.WriteHelp(&help)
+ assert.Equal(t, expectedHelp[1:], help.String())
+
+ var usage bytes.Buffer
+ p.WriteUsage(&usage)
+ assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
+
+ expectedUsage = "Usage: example cmd [--number NUMBER]"
+
+ expectedHelp = `
+Usage: example cmd [--number NUMBER]
+
+Options:
+ --number NUMBER, -n NUMBER
+ compute something on the given number
+
+Global options:
+ --version this is a user-defined version flag
+ --help, -h display this help and exit
+`
+ _ = p.Parse([]string{"cmd"})
+
+ help = bytes.Buffer{}
+ p.WriteHelp(&help)
+ assert.Equal(t, expectedHelp[1:], help.String())
+
+ usage = bytes.Buffer{}
+ p.WriteUsage(&usage)
+ assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
+}
+
type described struct{}
// Described returns the description for this program
@@ -415,6 +642,50 @@ Options:
assert.Equal(t, expectedUsage, usage.String())
}
+func TestUsageWithSubcommands(t *testing.T) {
+ expectedUsage := "Usage: example child [--values VALUES]"
+
+ expectedHelp := `
+Usage: example child [--values VALUES]
+
+Options:
+ --values VALUES Values
+
+Global options:
+ --verbose, -v verbosity level
+ --help, -h display this help and exit
+`
+
+ var args struct {
+ Verbose bool `arg:"-v" help:"verbosity level"`
+ Child *struct {
+ Values []float64 `help:"Values"`
+ } `arg:"subcommand:child"`
+ }
+
+ os.Args[0] = "example"
+ p, err := NewParser(Config{}, &args)
+ require.NoError(t, err)
+
+ _ = p.Parse([]string{"child"})
+
+ var help bytes.Buffer
+ p.WriteHelp(&help)
+ assert.Equal(t, expectedHelp[1:], help.String())
+
+ var help2 bytes.Buffer
+ p.WriteHelpForSubcommand(&help2, "child")
+ assert.Equal(t, expectedHelp[1:], help2.String())
+
+ var usage bytes.Buffer
+ p.WriteUsage(&usage)
+ assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
+
+ var usage2 bytes.Buffer
+ p.WriteUsageForSubcommand(&usage2, "child")
+ assert.Equal(t, expectedUsage, strings.TrimSpace(usage2.String()))
+}
+
func TestUsageWithNestedSubcommands(t *testing.T) {
expectedUsage := "Usage: example child nested [--enable] OUTPUT"
@@ -524,6 +795,35 @@ Options:
assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
}
+func TestUsageWithEmptyPlaceholder(t *testing.T) {
+ expectedUsage := "Usage: example [-a] [--b] [--c]"
+
+ expectedHelp := `
+Usage: example [-a] [--b] [--c]
+
+Options:
+ -a some help for a
+ --b some help for b
+ --c, -c some help for c
+ --help, -h display this help and exit
+`
+ var args struct {
+ ShortOnly string `arg:"-a,--" placeholder:"" help:"some help for a"`
+ LongOnly string `arg:"--b" placeholder:"" help:"some help for b"`
+ Both string `arg:"-c,--c" placeholder:"" help:"some help for c"`
+ }
+ p, err := NewParser(Config{Program: "example"}, &args)
+ require.NoError(t, err)
+
+ var help bytes.Buffer
+ p.WriteHelp(&help)
+ assert.Equal(t, expectedHelp[1:], help.String())
+
+ var usage bytes.Buffer
+ p.WriteUsage(&usage)
+ assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
+}
+
func TestUsageWithShortFirst(t *testing.T) {
expectedUsage := "Usage: example [-c CAT] [--dog DOG]"
@@ -632,7 +932,7 @@ error: something went wrong
p.Fail("something went wrong")
assert.Equal(t, expectedStdout[1:], stdout.String())
- assert.Equal(t, -1, exitCode)
+ assert.Equal(t, 2, exitCode)
}
func TestFailSubcommand(t *testing.T) {
@@ -655,7 +955,7 @@ error: something went wrong
require.NoError(t, err)
assert.Equal(t, expectedStdout[1:], stdout.String())
- assert.Equal(t, -1, exitCode)
+ assert.Equal(t, 2, exitCode)
}
type lengthOf struct {
@@ -715,3 +1015,72 @@ Commands:
p.WriteHelp(&help)
assert.Equal(t, expectedHelp[1:], help.String())
}
+
+func TestHelpShowsPositionalWithDefault(t *testing.T) {
+ expectedHelp := `
+Usage: example [FOO]
+
+Positional arguments:
+ FOO this is a positional with a default [default: bar]
+
+Options:
+ --help, -h display this help and exit
+`
+
+ var args struct {
+ Foo string `arg:"positional" default:"bar" help:"this is a positional with a default"`
+ }
+
+ p, err := NewParser(Config{Program: "example"}, &args)
+ require.NoError(t, err)
+
+ var help bytes.Buffer
+ p.WriteHelp(&help)
+ assert.Equal(t, expectedHelp[1:], help.String())
+}
+
+func TestHelpShowsPositionalWithEnv(t *testing.T) {
+ expectedHelp := `
+Usage: example [FOO]
+
+Positional arguments:
+ FOO this is a positional with an env variable [env: FOO]
+
+Options:
+ --help, -h display this help and exit
+`
+
+ var args struct {
+ Foo string `arg:"positional,env:FOO" help:"this is a positional with an env variable"`
+ }
+
+ p, err := NewParser(Config{Program: "example"}, &args)
+ require.NoError(t, err)
+
+ var help bytes.Buffer
+ p.WriteHelp(&help)
+ assert.Equal(t, expectedHelp[1:], help.String())
+}
+
+func TestHelpShowsPositionalWithDefaultAndEnv(t *testing.T) {
+ expectedHelp := `
+Usage: example [FOO]
+
+Positional arguments:
+ FOO this is a positional with a default and an env variable [default: bar, env: FOO]
+
+Options:
+ --help, -h display this help and exit
+`
+
+ var args struct {
+ Foo string `arg:"positional,env:FOO" default:"bar" help:"this is a positional with a default and an env variable"`
+ }
+
+ p, err := NewParser(Config{Program: "example"}, &args)
+ require.NoError(t, err)
+
+ var help bytes.Buffer
+ p.WriteHelp(&help)
+ assert.Equal(t, expectedHelp[1:], help.String())
+}