go-arg/v2/subcommand_test.go

412 lines
8.9 KiB
Go

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(&args)
assert.Error(t, err)
}
func TestSubcommandNotAPointerToStruct(t *testing.T) {
var args struct {
A struct{} `arg:"subcommand"`
}
_, err := NewParser(&args)
assert.Error(t, err)
}
func TestPositionalAndSubcommandNotAllowed(t *testing.T) {
var args struct {
A string `arg:"positional"`
B *struct{} `arg:"subcommand"`
}
_, err := NewParser(&args)
assert.Error(t, err)
}
func TestMinimalSubcommand(t *testing.T) {
type listCmd struct {
}
var args struct {
List *listCmd `arg:"subcommand"`
}
p, err := parse(&args, "list")
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(&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 := parse(&args, "invalid")
assert.Error(t, err)
}
func TestNamedSubcommand(t *testing.T) {
type listCmd struct {
}
var args struct {
List *listCmd `arg:"subcommand:ls"`
}
p, err := parse(&args, "ls")
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 := parse(&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 := parse(&args, "list")
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 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(&args, "list")
require.NoError(t, err)
assert.Nil(t, args.Get)
assert.NotNil(t, args.List)
}
{
var args cmd
_, err := parse(&args, "list --limit 3")
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(&args, "list --limit 3 --verbose")
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(&args, "list --verbose --limit 3")
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(&args, "--verbose list --limit 3")
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(&args, "get")
require.NoError(t, err)
assert.NotNil(t, args.Get)
assert.Nil(t, args.List)
}
{
var args cmd
_, err := parse(&args, "get --name test")
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
_, err := parse(&args, "list", "LIMIT=123")
require.NoError(t, err)
require.NotNil(t, args.List)
assert.Equal(t, 123, args.List.Limit)
}
{
var args cmd
_, err := parse(&args, "list", "LIMIT=not_an_integer")
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 := parse(&args, "grandparent parent child")
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 := parse(&args, "grandparent parent")
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 := parse(&args, "grandparent")
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 := parse(&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(&args, "list")
require.NoError(t, err)
assert.NotNil(t, args.List)
assert.Equal(t, "", args.List.Pattern)
}
{
var args cmd
_, err := parse(&args, "list --format json")
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(&args, "list somepattern")
require.NoError(t, err)
assert.NotNil(t, args.List)
assert.Equal(t, "somepattern", args.List.Pattern)
}
{
var args cmd
_, err := parse(&args, "list somepattern --format json")
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(&args, "list --format json somepattern")
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(&args, "--format json list somepattern")
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(&args, "--format json")
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(&args, "get")
require.NoError(t, err)
assert.NotNil(t, args.Get)
assert.Empty(t, args.Get.Items)
}
{
var args cmd
_, err := parse(&args, "get --limit 5")
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(&args, "get item1")
require.NoError(t, err)
assert.NotNil(t, args.Get)
assert.Equal(t, []string{"item1"}, args.Get.Items)
}
{
var args cmd
_, err := parse(&args, "get item1 item2 item3")
require.NoError(t, err)
assert.NotNil(t, args.Get)
assert.Equal(t, []string{"item1", "item2", "item3"}, args.Get.Items)
}
{
var args cmd
_, err := parse(&args, "get item1 --limit 5 item2")
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(&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())
}