summaryrefslogtreecommitdiff
path: root/test/subcommand_test.go
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2024-01-14 14:25:54 -0600
committerJeff Carr <[email protected]>2024-01-14 14:25:54 -0600
commit530fcb84d482355ce44af5371142c9f97e20672d (patch)
treef208647640f050bc8c47aad4746c70223270979f /test/subcommand_test.go
parentbf629a16cbe505e81b6347813a918770a3b727df (diff)
isolate tests
Signed-off-by: Jeff Carr <[email protected]>
Diffstat (limited to 'test/subcommand_test.go')
-rw-r--r--test/subcommand_test.go508
1 files changed, 508 insertions, 0 deletions
diff --git a/test/subcommand_test.go b/test/subcommand_test.go
new file mode 100644
index 0000000..00efae0
--- /dev/null
+++ b/test/subcommand_test.go
@@ -0,0 +1,508 @@
+package arg
+
+import (
+ "reflect"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// This file contains tests for parse.go but I decided to put them here
+// since that file is getting large
+
+func TestSubcommandNotAPointer(t *testing.T) {
+ var args struct {
+ A string `arg:"subcommand"`
+ }
+ _, err := NewParser(Config{}, &args)
+ assert.Error(t, err)
+}
+
+func TestSubcommandNotAPointerToStruct(t *testing.T) {
+ var args struct {
+ A struct{} `arg:"subcommand"`
+ }
+ _, err := NewParser(Config{}, &args)
+ assert.Error(t, err)
+}
+
+func TestPositionalAndSubcommandNotAllowed(t *testing.T) {
+ var args struct {
+ A string `arg:"positional"`
+ B *struct{} `arg:"subcommand"`
+ }
+ _, err := NewParser(Config{}, &args)
+ assert.Error(t, err)
+}
+
+func TestMinimalSubcommand(t *testing.T) {
+ type listCmd struct {
+ }
+ var args struct {
+ List *listCmd `arg:"subcommand"`
+ }
+ p, err := pparse("list", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, args.List, p.Subcommand())
+ assert.Equal(t, []string{"list"}, p.SubcommandNames())
+}
+
+func TestSubcommandNamesBeforeParsing(t *testing.T) {
+ type listCmd struct{}
+ var args struct {
+ List *listCmd `arg:"subcommand"`
+ }
+ p, err := NewParser(Config{}, &args)
+ require.NoError(t, err)
+ assert.Nil(t, p.Subcommand())
+ assert.Nil(t, p.SubcommandNames())
+}
+
+func TestNoSuchSubcommand(t *testing.T) {
+ type listCmd struct {
+ }
+ var args struct {
+ List *listCmd `arg:"subcommand"`
+ }
+ _, err := pparse("invalid", &args)
+ assert.Error(t, err)
+}
+
+func TestNamedSubcommand(t *testing.T) {
+ type listCmd struct {
+ }
+ var args struct {
+ List *listCmd `arg:"subcommand:ls"`
+ }
+ p, err := pparse("ls", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, args.List, p.Subcommand())
+ assert.Equal(t, []string{"ls"}, p.SubcommandNames())
+}
+
+func TestSubcommandAliases(t *testing.T) {
+ type listCmd struct {
+ }
+ var args struct {
+ List *listCmd `arg:"subcommand:list|ls"`
+ }
+ p, err := pparse("ls", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, args.List, p.Subcommand())
+ assert.Equal(t, []string{"ls"}, p.SubcommandNames())
+}
+
+func TestEmptySubcommand(t *testing.T) {
+ type listCmd struct {
+ }
+ var args struct {
+ List *listCmd `arg:"subcommand"`
+ }
+ p, err := pparse("", &args)
+ require.NoError(t, err)
+ assert.Nil(t, args.List)
+ assert.Nil(t, p.Subcommand())
+ assert.Empty(t, p.SubcommandNames())
+}
+
+func TestTwoSubcommands(t *testing.T) {
+ type getCmd struct {
+ }
+ type listCmd struct {
+ }
+ var args struct {
+ Get *getCmd `arg:"subcommand"`
+ List *listCmd `arg:"subcommand"`
+ }
+ p, err := pparse("list", &args)
+ require.NoError(t, err)
+ assert.Nil(t, args.Get)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, args.List, p.Subcommand())
+ assert.Equal(t, []string{"list"}, p.SubcommandNames())
+}
+
+func TestTwoSubcommandsWithAliases(t *testing.T) {
+ type getCmd struct {
+ }
+ type listCmd struct {
+ }
+ var args struct {
+ Get *getCmd `arg:"subcommand:get|g"`
+ List *listCmd `arg:"subcommand:list|ls"`
+ }
+ p, err := pparse("ls", &args)
+ require.NoError(t, err)
+ assert.Nil(t, args.Get)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, args.List, p.Subcommand())
+ assert.Equal(t, []string{"ls"}, p.SubcommandNames())
+}
+
+func TestSubcommandsWithOptions(t *testing.T) {
+ type getCmd struct {
+ Name string
+ }
+ type listCmd struct {
+ Limit int
+ }
+ type cmd struct {
+ Verbose bool
+ Get *getCmd `arg:"subcommand"`
+ List *listCmd `arg:"subcommand"`
+ }
+
+ {
+ var args cmd
+ err := parse("list", &args)
+ require.NoError(t, err)
+ assert.Nil(t, args.Get)
+ assert.NotNil(t, args.List)
+ }
+
+ {
+ var args cmd
+ err := parse("list --limit 3", &args)
+ require.NoError(t, err)
+ assert.Nil(t, args.Get)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, args.List.Limit, 3)
+ }
+
+ {
+ var args cmd
+ err := parse("list --limit 3 --verbose", &args)
+ require.NoError(t, err)
+ assert.Nil(t, args.Get)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, args.List.Limit, 3)
+ assert.True(t, args.Verbose)
+ }
+
+ {
+ var args cmd
+ err := parse("list --verbose --limit 3", &args)
+ require.NoError(t, err)
+ assert.Nil(t, args.Get)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, args.List.Limit, 3)
+ assert.True(t, args.Verbose)
+ }
+
+ {
+ var args cmd
+ err := parse("--verbose list --limit 3", &args)
+ require.NoError(t, err)
+ assert.Nil(t, args.Get)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, args.List.Limit, 3)
+ assert.True(t, args.Verbose)
+ }
+
+ {
+ var args cmd
+ err := parse("get", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.Get)
+ assert.Nil(t, args.List)
+ }
+
+ {
+ var args cmd
+ err := parse("get --name test", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.Get)
+ assert.Nil(t, args.List)
+ assert.Equal(t, args.Get.Name, "test")
+ }
+}
+
+func TestSubcommandsWithEnvVars(t *testing.T) {
+ type getCmd struct {
+ Name string `arg:"env"`
+ }
+ type listCmd struct {
+ Limit int `arg:"env"`
+ }
+ type cmd struct {
+ Verbose bool
+ Get *getCmd `arg:"subcommand"`
+ List *listCmd `arg:"subcommand"`
+ }
+
+ {
+ var args cmd
+ setenv(t, "LIMIT", "123")
+ err := parse("list", &args)
+ require.NoError(t, err)
+ require.NotNil(t, args.List)
+ assert.Equal(t, 123, args.List.Limit)
+ }
+
+ {
+ var args cmd
+ setenv(t, "LIMIT", "not_an_integer")
+ err := parse("list", &args)
+ assert.Error(t, err)
+ }
+}
+
+func TestNestedSubcommands(t *testing.T) {
+ type child struct{}
+ type parent struct {
+ Child *child `arg:"subcommand"`
+ }
+ type grandparent struct {
+ Parent *parent `arg:"subcommand"`
+ }
+ type root struct {
+ Grandparent *grandparent `arg:"subcommand"`
+ }
+
+ {
+ var args root
+ p, err := pparse("grandparent parent child", &args)
+ require.NoError(t, err)
+ require.NotNil(t, args.Grandparent)
+ require.NotNil(t, args.Grandparent.Parent)
+ require.NotNil(t, args.Grandparent.Parent.Child)
+ assert.Equal(t, args.Grandparent.Parent.Child, p.Subcommand())
+ assert.Equal(t, []string{"grandparent", "parent", "child"}, p.SubcommandNames())
+ }
+
+ {
+ var args root
+ p, err := pparse("grandparent parent", &args)
+ require.NoError(t, err)
+ require.NotNil(t, args.Grandparent)
+ require.NotNil(t, args.Grandparent.Parent)
+ require.Nil(t, args.Grandparent.Parent.Child)
+ assert.Equal(t, args.Grandparent.Parent, p.Subcommand())
+ assert.Equal(t, []string{"grandparent", "parent"}, p.SubcommandNames())
+ }
+
+ {
+ var args root
+ p, err := pparse("grandparent", &args)
+ require.NoError(t, err)
+ require.NotNil(t, args.Grandparent)
+ require.Nil(t, args.Grandparent.Parent)
+ assert.Equal(t, args.Grandparent, p.Subcommand())
+ assert.Equal(t, []string{"grandparent"}, p.SubcommandNames())
+ }
+
+ {
+ var args root
+ p, err := pparse("", &args)
+ require.NoError(t, err)
+ require.Nil(t, args.Grandparent)
+ assert.Nil(t, p.Subcommand())
+ assert.Empty(t, p.SubcommandNames())
+ }
+}
+
+func TestNestedSubcommandsWithAliases(t *testing.T) {
+ type child struct{}
+ type parent struct {
+ Child *child `arg:"subcommand:child|ch"`
+ }
+ type grandparent struct {
+ Parent *parent `arg:"subcommand:parent|pa"`
+ }
+ type root struct {
+ Grandparent *grandparent `arg:"subcommand:grandparent|gp"`
+ }
+
+ {
+ var args root
+ p, err := pparse("gp parent child", &args)
+ require.NoError(t, err)
+ require.NotNil(t, args.Grandparent)
+ require.NotNil(t, args.Grandparent.Parent)
+ require.NotNil(t, args.Grandparent.Parent.Child)
+ assert.Equal(t, args.Grandparent.Parent.Child, p.Subcommand())
+ assert.Equal(t, []string{"gp", "parent", "child"}, p.SubcommandNames())
+ }
+
+ {
+ var args root
+ p, err := pparse("grandparent pa", &args)
+ require.NoError(t, err)
+ require.NotNil(t, args.Grandparent)
+ require.NotNil(t, args.Grandparent.Parent)
+ require.Nil(t, args.Grandparent.Parent.Child)
+ assert.Equal(t, args.Grandparent.Parent, p.Subcommand())
+ assert.Equal(t, []string{"grandparent", "pa"}, p.SubcommandNames())
+ }
+
+ {
+ var args root
+ p, err := pparse("grandparent", &args)
+ require.NoError(t, err)
+ require.NotNil(t, args.Grandparent)
+ require.Nil(t, args.Grandparent.Parent)
+ assert.Equal(t, args.Grandparent, p.Subcommand())
+ assert.Equal(t, []string{"grandparent"}, p.SubcommandNames())
+ }
+
+ {
+ var args root
+ p, err := pparse("", &args)
+ require.NoError(t, err)
+ require.Nil(t, args.Grandparent)
+ assert.Nil(t, p.Subcommand())
+ assert.Empty(t, p.SubcommandNames())
+ }
+}
+
+func TestSubcommandsWithPositionals(t *testing.T) {
+ type listCmd struct {
+ Pattern string `arg:"positional"`
+ }
+ type cmd struct {
+ Format string
+ List *listCmd `arg:"subcommand"`
+ }
+
+ {
+ var args cmd
+ err := parse("list", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, "", args.List.Pattern)
+ }
+
+ {
+ var args cmd
+ err := parse("list --format json", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, "", args.List.Pattern)
+ assert.Equal(t, "json", args.Format)
+ }
+
+ {
+ var args cmd
+ err := parse("list somepattern", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, "somepattern", args.List.Pattern)
+ }
+
+ {
+ var args cmd
+ err := parse("list somepattern --format json", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, "somepattern", args.List.Pattern)
+ assert.Equal(t, "json", args.Format)
+ }
+
+ {
+ var args cmd
+ err := parse("list --format json somepattern", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, "somepattern", args.List.Pattern)
+ assert.Equal(t, "json", args.Format)
+ }
+
+ {
+ var args cmd
+ err := parse("--format json list somepattern", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.List)
+ assert.Equal(t, "somepattern", args.List.Pattern)
+ assert.Equal(t, "json", args.Format)
+ }
+
+ {
+ var args cmd
+ err := parse("--format json", &args)
+ require.NoError(t, err)
+ assert.Nil(t, args.List)
+ assert.Equal(t, "json", args.Format)
+ }
+}
+func TestSubcommandsWithMultiplePositionals(t *testing.T) {
+ type getCmd struct {
+ Items []string `arg:"positional"`
+ }
+ type cmd struct {
+ Limit int
+ Get *getCmd `arg:"subcommand"`
+ }
+
+ {
+ var args cmd
+ err := parse("get", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.Get)
+ assert.Empty(t, args.Get.Items)
+ }
+
+ {
+ var args cmd
+ err := parse("get --limit 5", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.Get)
+ assert.Empty(t, args.Get.Items)
+ assert.Equal(t, 5, args.Limit)
+ }
+
+ {
+ var args cmd
+ err := parse("get item1", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.Get)
+ assert.Equal(t, []string{"item1"}, args.Get.Items)
+ }
+
+ {
+ var args cmd
+ err := parse("get item1 item2 item3", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.Get)
+ assert.Equal(t, []string{"item1", "item2", "item3"}, args.Get.Items)
+ }
+
+ {
+ var args cmd
+ err := parse("get item1 --limit 5 item2", &args)
+ require.NoError(t, err)
+ assert.NotNil(t, args.Get)
+ assert.Equal(t, []string{"item1", "item2"}, args.Get.Items)
+ assert.Equal(t, 5, args.Limit)
+ }
+}
+
+func TestValForNilStruct(t *testing.T) {
+ type subcmd struct{}
+ var cmd struct {
+ Sub *subcmd `arg:"subcommand"`
+ }
+
+ p, err := NewParser(Config{}, &cmd)
+ require.NoError(t, err)
+
+ typ := reflect.TypeOf(cmd)
+ subField, _ := typ.FieldByName("Sub")
+
+ v := p.val(path{fields: []reflect.StructField{subField, subField}})
+ assert.False(t, v.IsValid())
+}
+
+func TestSubcommandInvalidInternal(t *testing.T) {
+ // this situation should never arise in practice but still good to test for it
+ var cmd struct{}
+ p, err := NewParser(Config{}, &cmd)
+ require.NoError(t, err)
+
+ p.subcommand = []string{"should", "never", "happen"}
+ sub := p.Subcommand()
+ assert.Nil(t, sub)
+}