Allow "bare" tags and moved tag tests into tag_test.go. Fixes #19
This commit is contained in:
committed by
Alec Thomas
parent
fdc7230e22
commit
ed123d1c06
@@ -49,7 +49,7 @@ func buildNode(v reflect.Value, typ NodeType, seenFlags map[string]bool) *Node {
|
|||||||
name = strings.ToLower(dashedString(ft.Name))
|
name = strings.ToLower(dashedString(ft.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
tag := parseTag(fv, ft.Tag.Get("kong"))
|
tag := parseTag(fv, ft)
|
||||||
|
|
||||||
// Nested structs are either commands or args.
|
// Nested structs are either commands or args.
|
||||||
if ft.Type.Kind() == reflect.Struct && (tag.Cmd || tag.Arg) {
|
if ft.Type.Kind() == reflect.Struct && (tag.Cmd || tag.Arg) {
|
||||||
|
|||||||
@@ -246,64 +246,6 @@ func TestMixedRequiredArgs(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDefaultValueForOptionalArg(t *testing.T) {
|
|
||||||
var cli struct {
|
|
||||||
Arg string `kong:"arg,optional,default='👌'"`
|
|
||||||
}
|
|
||||||
p := mustNew(t, &cli)
|
|
||||||
_, err := p.Parse(nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, "👌", cli.Arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNoValueInTag(t *testing.T) {
|
|
||||||
var cli struct {
|
|
||||||
Empty1 string `kong:"default"`
|
|
||||||
Empty2 string `kong:"default="`
|
|
||||||
}
|
|
||||||
p := mustNew(t, &cli)
|
|
||||||
_, err := p.Parse(nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, "", cli.Empty1)
|
|
||||||
require.Equal(t, "", cli.Empty2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCommaInQuotes(t *testing.T) {
|
|
||||||
var cli struct {
|
|
||||||
Numbers string `kong:"default='1,2'"`
|
|
||||||
}
|
|
||||||
p := mustNew(t, &cli)
|
|
||||||
_, err := p.Parse(nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, "1,2", cli.Numbers)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBadString(t *testing.T) {
|
|
||||||
var cli struct {
|
|
||||||
Numbers string `kong:"default='yay'n"`
|
|
||||||
}
|
|
||||||
_, err := New(&cli)
|
|
||||||
require.Error(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNoQuoteEnd(t *testing.T) {
|
|
||||||
var cli struct {
|
|
||||||
Numbers string `kong:"default='yay"`
|
|
||||||
}
|
|
||||||
_, err := New(&cli)
|
|
||||||
require.Error(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEscapedQuote(t *testing.T) {
|
|
||||||
var cli struct {
|
|
||||||
DoYouKnow string `kong:"default='i don\\'t know'"`
|
|
||||||
}
|
|
||||||
p := mustNew(t, &cli)
|
|
||||||
_, err := p.Parse(nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, "i don't know", cli.DoYouKnow)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInvalidDefaultErrors(t *testing.T) {
|
func TestInvalidDefaultErrors(t *testing.T) {
|
||||||
var cli struct {
|
var cli struct {
|
||||||
Flag int `kong:"default='foo'"`
|
Flag int `kong:"default='foo'"`
|
||||||
|
|||||||
@@ -26,9 +26,15 @@ type Tag struct {
|
|||||||
items map[string]string
|
items map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseCSV(s string) map[string]string {
|
type tagChars struct {
|
||||||
d := map[string]string{}
|
sep, quote, assign rune
|
||||||
|
}
|
||||||
|
|
||||||
|
var kongChars = tagChars{sep: ',', quote: '\'', assign: '='}
|
||||||
|
var bareChars = tagChars{sep: ' ', quote: '"', assign: ':'}
|
||||||
|
|
||||||
|
func parseCSV(s string, chr tagChars) map[string]string {
|
||||||
|
d := map[string]string{}
|
||||||
key := []rune{}
|
key := []rune{}
|
||||||
value := []rune{}
|
value := []rune{}
|
||||||
quotes := false
|
quotes := false
|
||||||
@@ -51,23 +57,23 @@ func parseCSV(s string) map[string]string {
|
|||||||
} else {
|
} else {
|
||||||
eof = true
|
eof = true
|
||||||
}
|
}
|
||||||
if !quotes && r == ',' {
|
if !quotes && r == chr.sep {
|
||||||
add()
|
add()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if r == '=' && inKey {
|
if r == chr.assign && inKey {
|
||||||
inKey = false
|
inKey = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if r == '\\' {
|
if r == '\\' {
|
||||||
if next == '\'' {
|
if next == chr.quote {
|
||||||
idx++
|
idx++
|
||||||
r = '\''
|
r = chr.quote
|
||||||
}
|
}
|
||||||
} else if r == '\'' {
|
} else if r == chr.quote {
|
||||||
if quotes {
|
if quotes {
|
||||||
quotes = false
|
quotes = false
|
||||||
if next == ',' || eof {
|
if next == chr.sep || eof {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fail("%v has an unexpected char at pos %v", s, idx)
|
fail("%v has an unexpected char at pos %v", s, idx)
|
||||||
@@ -91,7 +97,17 @@ func parseCSV(s string) map[string]string {
|
|||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTag(fv reflect.Value, s string) *Tag {
|
func getTagInfo(ft reflect.StructField) (string, tagChars) {
|
||||||
|
s, ok := ft.Tag.Lookup("kong")
|
||||||
|
if ok {
|
||||||
|
return s, kongChars
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(ft.Tag), bareChars
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTag(fv reflect.Value, ft reflect.StructField) *Tag {
|
||||||
|
s, chars := getTagInfo(ft)
|
||||||
t := &Tag{
|
t := &Tag{
|
||||||
items: map[string]string{},
|
items: map[string]string{},
|
||||||
}
|
}
|
||||||
@@ -99,7 +115,7 @@ func parseTag(fv reflect.Value, s string) *Tag {
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
t.items = parseCSV(s)
|
t.items = parseCSV(s, chars)
|
||||||
|
|
||||||
t.Cmd = t.Has("cmd")
|
t.Cmd = t.Has("cmd")
|
||||||
t.Arg = t.Has("arg")
|
t.Arg = t.Has("arg")
|
||||||
|
|||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
package kong
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDefaultValueForOptionalArg(t *testing.T) {
|
||||||
|
var cli struct {
|
||||||
|
Arg string `kong:"arg,optional,default='👌'"`
|
||||||
|
}
|
||||||
|
p := mustNew(t, &cli)
|
||||||
|
_, err := p.Parse(nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "👌", cli.Arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoValueInTag(t *testing.T) {
|
||||||
|
var cli struct {
|
||||||
|
Empty1 string `kong:"default"`
|
||||||
|
Empty2 string `kong:"default="`
|
||||||
|
}
|
||||||
|
p := mustNew(t, &cli)
|
||||||
|
_, err := p.Parse(nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "", cli.Empty1)
|
||||||
|
require.Equal(t, "", cli.Empty2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommaInQuotes(t *testing.T) {
|
||||||
|
var cli struct {
|
||||||
|
Numbers string `kong:"default='1,2'"`
|
||||||
|
}
|
||||||
|
p := mustNew(t, &cli)
|
||||||
|
_, err := p.Parse(nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "1,2", cli.Numbers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBadString(t *testing.T) {
|
||||||
|
var cli struct {
|
||||||
|
Numbers string `kong:"default='yay'n"`
|
||||||
|
}
|
||||||
|
_, err := New(&cli)
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoQuoteEnd(t *testing.T) {
|
||||||
|
var cli struct {
|
||||||
|
Numbers string `kong:"default='yay"`
|
||||||
|
}
|
||||||
|
_, err := New(&cli)
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEscapedQuote(t *testing.T) {
|
||||||
|
var cli struct {
|
||||||
|
DoYouKnow string `kong:"default='i don\\'t know'"`
|
||||||
|
}
|
||||||
|
p := mustNew(t, &cli)
|
||||||
|
_, err := p.Parse(nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "i don't know", cli.DoYouKnow)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBareTags(t *testing.T) {
|
||||||
|
var cli struct {
|
||||||
|
Cmd struct {
|
||||||
|
Arg string `arg`
|
||||||
|
Flag string `required default:"👌"`
|
||||||
|
} `cmd`
|
||||||
|
}
|
||||||
|
|
||||||
|
p := mustNew(t, &cli)
|
||||||
|
_, err := p.Parse([]string{"cmd", "arg", "--flag=hi"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "hi", cli.Cmd.Flag)
|
||||||
|
require.Equal(t, "arg", cli.Cmd.Arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBareTagsWithJsonTag(t *testing.T) {
|
||||||
|
var cli struct {
|
||||||
|
Cmd struct {
|
||||||
|
Arg string `json:"-" optional arg`
|
||||||
|
Flag string `json:"best_flag" default:"\"'👌'\""`
|
||||||
|
} `cmd json:"CMD"`
|
||||||
|
}
|
||||||
|
|
||||||
|
p := mustNew(t, &cli)
|
||||||
|
_, err := p.Parse([]string{"cmd"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "\"'👌'\"", cli.Cmd.Flag)
|
||||||
|
require.Equal(t, "", cli.Cmd.Arg)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user