diff --git a/command.go b/command.go index 9cc5fc2..e5ce7ac 100644 --- a/command.go +++ b/command.go @@ -181,11 +181,6 @@ type example struct { command string // The command string for the example. } -// String implements [fmt.Stringer] for [Example]. -func (e example) String() string { - return fmt.Sprintf("\n # %s\n $ %s\n", e.comment, e.command) -} - // Execute parses the flags and arguments, and invokes the Command's Run // function, returning any error. // diff --git a/command_test.go b/command_test.go index 8092b4e..6f1af28 100644 --- a/command_test.go +++ b/command_test.go @@ -64,6 +64,28 @@ func TestExecute(t *testing.T) { }, wantErr: true, }, + { + name: "bad arg", + stdout: "", + stderr: "", + options: []cli.Option{ + cli.OverrideArgs([]string{"arg1", "notanumber"}), // Provided arg for 'second' is not an int + cli.Arg(new(string), "first", "The first arg"), + cli.Arg(new(int), "second", "The second arg"), + }, + wantErr: true, + }, + { + name: "missing required argument", + stdout: "", + stderr: "", + options: []cli.Option{ + cli.OverrideArgs([]string{"hello"}), // "second" is not provided + cli.Arg(new(string), "first", "The first word"), // Expect the positional arguments + cli.Arg(new(string), "second", "The second word"), + }, + wantErr: true, + }, } for _, tt := range tests { diff --git a/internal/arg/arg_test.go b/internal/arg/arg_test.go index a7fe51f..d87e32c 100644 --- a/internal/arg/arg_test.go +++ b/internal/arg/arg_test.go @@ -26,8 +26,9 @@ func TestArgableTypes(t *testing.T) { err = intArg.Set("42") test.Ok(t, err) test.Equal(t, i, 42) - test.Equal(t, intArg.Type(), "int") + test.Equal(t, intArg.Type(), format.TypeInt) test.Equal(t, intArg.String(), "42") + test.Equal(t, intArg.Usage(), "Set an int value") test.Equal(t, intArg.Default(), "") }) @@ -51,7 +52,8 @@ func TestArgableTypes(t *testing.T) { err = intArg.Set("42") test.Ok(t, err) test.Equal(t, i, int8(42)) - test.Equal(t, intArg.Type(), "int8") + test.Equal(t, intArg.Type(), format.TypeInt8) + test.Equal(t, intArg.Usage(), "Set an int8 value") test.Equal(t, intArg.String(), "42") }) @@ -75,7 +77,8 @@ func TestArgableTypes(t *testing.T) { err = intArg.Set("42") test.Ok(t, err) test.Equal(t, i, int16(42)) - test.Equal(t, intArg.Type(), "int16") + test.Equal(t, intArg.Type(), format.TypeInt16) + test.Equal(t, intArg.Usage(), "Set an int16 value") test.Equal(t, intArg.String(), "42") }) @@ -99,7 +102,8 @@ func TestArgableTypes(t *testing.T) { err = intArg.Set("42") test.Ok(t, err) test.Equal(t, i, int32(42)) - test.Equal(t, intArg.Type(), "int32") + test.Equal(t, intArg.Type(), format.TypeInt32) + test.Equal(t, intArg.Usage(), "Set an int32 value") test.Equal(t, intArg.String(), "42") }) @@ -123,7 +127,8 @@ func TestArgableTypes(t *testing.T) { err = intArg.Set("42") test.Ok(t, err) test.Equal(t, i, int64(42)) - test.Equal(t, intArg.Type(), "int64") + test.Equal(t, intArg.Type(), format.TypeInt64) + test.Equal(t, intArg.Usage(), "Set an int64 value") test.Equal(t, intArg.String(), "42") }) @@ -147,7 +152,8 @@ func TestArgableTypes(t *testing.T) { err = intArg.Set("42") test.Ok(t, err) test.Equal(t, i, 42) - test.Equal(t, intArg.Type(), "uint") + test.Equal(t, intArg.Type(), format.TypeUint) + test.Equal(t, intArg.Usage(), "Set a uint value") test.Equal(t, intArg.String(), "42") }) @@ -172,6 +178,7 @@ func TestArgableTypes(t *testing.T) { test.Ok(t, err) test.Equal(t, i, uint8(42)) test.Equal(t, intArg.Type(), "uint8") + test.Equal(t, intArg.Usage(), "Set a uint8 value") test.Equal(t, intArg.String(), "42") }) @@ -195,7 +202,8 @@ func TestArgableTypes(t *testing.T) { err = intArg.Set("42") test.Ok(t, err) test.Equal(t, i, uint16(42)) - test.Equal(t, intArg.Type(), "uint16") + test.Equal(t, intArg.Type(), format.TypeUint16) + test.Equal(t, intArg.Usage(), "Set a uint16 value") test.Equal(t, intArg.String(), "42") }) @@ -219,7 +227,8 @@ func TestArgableTypes(t *testing.T) { err = intArg.Set("42") test.Ok(t, err) test.Equal(t, i, uint32(42)) - test.Equal(t, intArg.Type(), "uint32") + test.Equal(t, intArg.Type(), format.TypeUint32) + test.Equal(t, intArg.Usage(), "Set a uint32 value") test.Equal(t, intArg.String(), "42") }) @@ -243,7 +252,8 @@ func TestArgableTypes(t *testing.T) { err = intArg.Set("42") test.Ok(t, err) test.Equal(t, i, uint64(42)) - test.Equal(t, intArg.Type(), "uint64") + test.Equal(t, intArg.Type(), format.TypeUint64) + test.Equal(t, intArg.Usage(), "Set a uint64 value") test.Equal(t, intArg.String(), "42") }) @@ -267,7 +277,8 @@ func TestArgableTypes(t *testing.T) { err = intArg.Set("42") test.Ok(t, err) test.Equal(t, i, uintptr(42)) - test.Equal(t, intArg.Type(), "uintptr") + test.Equal(t, intArg.Type(), format.TypeUintptr) + test.Equal(t, intArg.Usage(), "Set a uintptr value") test.Equal(t, intArg.String(), "42") }) @@ -291,7 +302,8 @@ func TestArgableTypes(t *testing.T) { err = floatArg.Set("3.14159") test.Ok(t, err) test.Equal(t, f, 3.14159) - test.Equal(t, floatArg.Type(), "float32") + test.Equal(t, floatArg.Type(), format.TypeFloat32) + test.Equal(t, floatArg.Usage(), "Set a float32 value") test.Equal(t, floatArg.String(), "3.14159") }) @@ -315,7 +327,8 @@ func TestArgableTypes(t *testing.T) { err = floatArg.Set("3.14159") test.Ok(t, err) test.Equal(t, f, 3.14159) - test.Equal(t, floatArg.Type(), "float64") + test.Equal(t, floatArg.Type(), format.TypeFloat64) + test.Equal(t, floatArg.Usage(), "Set a float64 value") test.Equal(t, floatArg.String(), "3.14159") }) @@ -339,7 +352,8 @@ func TestArgableTypes(t *testing.T) { err = boolArg.Set(format.True) test.Ok(t, err) test.Equal(t, b, true) - test.Equal(t, boolArg.Type(), "bool") + test.Equal(t, boolArg.Type(), format.TypeBool) + test.Equal(t, boolArg.Usage(), "Set a bool value") test.Equal(t, boolArg.String(), format.True) }) @@ -365,7 +379,8 @@ func TestArgableTypes(t *testing.T) { err = strArg.Set("newvalue") test.Ok(t, err) test.Equal(t, str, "newvalue") - test.Equal(t, strArg.Type(), "string") + test.Equal(t, strArg.Type(), format.TypeString) + test.Equal(t, strArg.Usage(), "Set a string value") test.Equal(t, strArg.String(), "newvalue") }) @@ -378,7 +393,8 @@ func TestArgableTypes(t *testing.T) { err = byteArg.Set("5e") test.Ok(t, err) test.EqualFunc(t, byt, []byte("^"), bytes.Equal) - test.Equal(t, byteArg.Type(), "bytesHex") + test.Equal(t, byteArg.Type(), format.TypeBytesHex) + test.Equal(t, byteArg.Usage(), "Set a byte slice value") test.Equal(t, byteArg.String(), "5e") }) @@ -405,7 +421,8 @@ func TestArgableTypes(t *testing.T) { want, err := time.Parse(time.RFC3339, "2024-07-17T07:38:05Z") test.Ok(t, err) test.Equal(t, tyme, want) - test.Equal(t, timeArg.Type(), "time") + test.Equal(t, timeArg.Type(), format.TypeTime) + test.Equal(t, timeArg.Usage(), "Set a time value") test.Equal(t, timeArg.String(), "2024-07-17T07:38:05Z") }) @@ -432,7 +449,8 @@ func TestArgableTypes(t *testing.T) { want, err := time.ParseDuration("300ms") test.Ok(t, err) test.Equal(t, duration, want) - test.Equal(t, durationArg.Type(), "duration") + test.Equal(t, durationArg.Type(), format.TypeDuration) + test.Equal(t, durationArg.Usage(), "Set a duration value") test.Equal(t, durationArg.String(), "300ms") }) @@ -456,7 +474,8 @@ func TestArgableTypes(t *testing.T) { err = ipArg.Set("192.0.2.1") test.Ok(t, err) test.DiffBytes(t, ip, net.ParseIP("192.0.2.1")) - test.Equal(t, ipArg.Type(), "ip") + test.Equal(t, ipArg.Type(), format.TypeIP) + test.Equal(t, ipArg.Usage(), "Set an IP address") test.Equal(t, ipArg.String(), "192.0.2.1") }) @@ -471,3 +490,19 @@ func TestArgableTypes(t *testing.T) { test.True(t, errors.Is(err, parse.Err)) }) } + +func TestDefaults(t *testing.T) { + str, err := arg.New(new(string), "str", "A string", arg.Config[string]{DefaultValue: pointer("hello")}) + test.Ok(t, err) + + intArg, err := arg.New(new(int), "int", "A string", arg.Config[int]{DefaultValue: pointer(27)}) + test.Ok(t, err) + + test.Equal(t, str.Default(), "hello") + test.Equal(t, intArg.Default(), "27") +} + +// pointer creates a new variable of the given value and returns its pointer. +func pointer[T any](value T) *T { + return &value +} diff --git a/internal/parse/parse_test.go b/internal/parse/parse_test.go index 2a46a5c..766170b 100644 --- a/internal/parse/parse_test.go +++ b/internal/parse/parse_test.go @@ -1,9 +1,12 @@ package parse //nolint:testpackage // I need the base and bits values and don't want to export them. import ( + "errors" "strconv" "testing" "testing/quick" + + "go.followtheprocess.codes/test" ) // These are basically all just testing that I haven't broken anything @@ -11,6 +14,11 @@ import ( // by hand. func TestInt(t *testing.T) { + // Check a basic happy path then let quick handle the rest + got, err := Int("5") + test.Ok(t, err) + test.Equal(t, got, 5) + test := Int reference := func(str string) (int, error) { @@ -24,6 +32,10 @@ func TestInt(t *testing.T) { } func TestInt8(t *testing.T) { + got, err := Int8("4") + test.Ok(t, err) + test.Equal(t, got, 4) + test := Int8 reference := func(str string) (int8, error) { @@ -37,6 +49,10 @@ func TestInt8(t *testing.T) { } func TestInt16(t *testing.T) { + got, err := Int16("32") + test.Ok(t, err) + test.Equal(t, got, 32) + test := Int16 reference := func(str string) (int16, error) { @@ -50,6 +66,10 @@ func TestInt16(t *testing.T) { } func TestInt32(t *testing.T) { + got, err := Int32("12") + test.Ok(t, err) + test.Equal(t, got, 12) + test := Int32 reference := func(str string) (int32, error) { @@ -63,6 +83,10 @@ func TestInt32(t *testing.T) { } func TestInt64(t *testing.T) { + got, err := Int64("27") + test.Ok(t, err) + test.Equal(t, got, 27) + test := Int64 reference := func(str string) (int64, error) { @@ -76,6 +100,10 @@ func TestInt64(t *testing.T) { } func TestUint(t *testing.T) { + got, err := Uint("2") + test.Ok(t, err) + test.Equal(t, got, 2) + test := Uint reference := func(str string) (uint, error) { @@ -89,6 +117,10 @@ func TestUint(t *testing.T) { } func TestUint8(t *testing.T) { + got, err := Uint8("8") + test.Ok(t, err) + test.Equal(t, got, 8) + test := Uint8 reference := func(str string) (uint8, error) { @@ -102,6 +134,10 @@ func TestUint8(t *testing.T) { } func TestUint16(t *testing.T) { + got, err := Uint16("7") + test.Ok(t, err) + test.Equal(t, got, 7) + test := Uint16 reference := func(str string) (uint16, error) { @@ -115,6 +151,10 @@ func TestUint16(t *testing.T) { } func TestUint32(t *testing.T) { + got, err := Uint32("47") + test.Ok(t, err) + test.Equal(t, got, 47) + test := Uint32 reference := func(str string) (uint32, error) { @@ -128,6 +168,10 @@ func TestUint32(t *testing.T) { } func TestUint64(t *testing.T) { + got, err := Uint64("102") + test.Ok(t, err) + test.Equal(t, got, 102) + test := Uint64 reference := func(str string) (uint64, error) { @@ -141,6 +185,10 @@ func TestUint64(t *testing.T) { } func TestFloat32(t *testing.T) { + got, err := Float32("102.8975") + test.Ok(t, err) + test.NearlyEqual(t, got, 102.8975) + test := Float32 reference := func(str string) (float32, error) { @@ -154,6 +202,10 @@ func TestFloat32(t *testing.T) { } func TestFloat64(t *testing.T) { + got, err := Float64("916156.123") + test.Ok(t, err) + test.NearlyEqual(t, got, 916156.123) + test := Float64 reference := func(str string) (float64, error) { @@ -165,3 +217,17 @@ func TestFloat64(t *testing.T) { t.Error(err) } } + +func TestError(t *testing.T) { + got := Error(KindArgument, "test", "blah", "string", errors.New("underlying")) + want := `parse error: argument "test" received invalid value "blah" (expected string): underlying` + + test.Equal(t, got.Error(), want) +} + +func TestErrorSlice(t *testing.T) { + got := ErrorSlice(KindArgument, "test", "blah", "string", errors.New("underlying")) + want := `parse error: argument "test" (type string) cannot append element "blah": underlying` + + test.Equal(t, got.Error(), want) +}