wand/commandline_test.go

242 lines
9.5 KiB
Go
Raw Normal View History

2025-08-18 14:24:31 +02:00
package wand
2025-08-24 01:45:25 +02:00
/*
2025-08-18 14:24:31 +02:00
import (
"fmt"
"strings"
"testing"
)
func TestCommand(t *testing.T) {
type f struct {
One string
SecondField int
}
ff := func(f f) string {
return f.One + fmt.Sprint(f.SecondField)
}
type b struct{ One, Two, Three, Four bool }
fb := func(b b) string {
return fmt.Sprintf("%t;%t;%t;%t", b.One, b.Two, b.Three, b.Four)
}
fbp := func(b b, p ...string) string {
o := fb(b)
if len(p) == 0 {
return o
}
s := []string{o}
for _, pi := range p {
s = append(s, pi)
}
return strings.Join(s, ";")
}
type m struct {
One, Two bool
Three string
}
fm := func(m m) string {
return fmt.Sprintf("%t;%t;%s", m.One, m.Two, m.Three)
}
type l struct {
One []bool
Two []string
}
fl := func(l l) string {
var sb []string
for _, b := range l.One {
sb = append(sb, fmt.Sprint(b))
}
return strings.Join([]string{strings.Join(sb, ","), strings.Join(l.Two, ",")}, ";")
}
type lb struct{ One, Two, Three []bool }
flb := func(lb lb) string {
var s []string
for _, b := range [][]bool{lb.One, lb.Two, lb.Three} {
var sb []string
for _, bi := range b {
sb = append(sb, fmt.Sprint(bi))
}
s = append(s, strings.Join(sb, ","))
}
return strings.Join(s, ";")
}
fp := func(f f, a ...string) string {
o := ff(f)
return fmt.Sprintf("%s;%s", o, strings.Join(a, ","))
}
type d struct{ One2 bool }
fd := func(d d) string {
return fmt.Sprint(d.One2)
}
t.Run("no args", testExec(t, ff, "", "foo", "", "0"))
t.Run("basic options", func(t *testing.T) {
t.Run("space", testExec(t, ff, "", "foo --one baz --second-field 42", "", "baz42"))
t.Run("eq", testExec(t, ff, "", "foo --one=baz --second-field=42", "", "baz42"))
})
t.Run("short options combined, explicit last", func(t *testing.T) {
t.Run("bool last", testExec(t, ShortForm(fb, "one", "a", "two", "b", "three", "c"), "", "foo -abc true", "", "true;true;true;false"))
t.Run("string last", testExec(t, ShortForm(fm, "one", "a", "two", "b", "three", "c"), "", "foo -abc bar", "", "true;true;bar"))
})
t.Run("multiple values", func(t *testing.T) {
t.Run("bools, short", testExec(t, ShortForm(fl, "one", "a"), "", "foo -a -a -a", "", "true,true,true;"))
t.Run("bools, short, combined", testExec(t, ShortForm(fl, "one", "a"), "", "foo -aaa", "", "true,true,true;"))
t.Run("bools, short, explicit", testExec(t, ShortForm(fl, "one", "a"), "", "foo -a true -a true -a true", "", "true,true,true;"))
t.Run("bools, short, combined, last explicit", testExec(t, ShortForm(fl, "one", "a"), "", "foo -aaa true", "", "true,true,true;"))
t.Run("bools, long", testExec(t, fl, "", "foo --one --one --one", "", "true,true,true;"))
t.Run("bools, long, explicit", testExec(t, fl, "", "foo --one true --one true --one true", "", "true,true,true;"))
t.Run("mixd, short", testExec(t, ShortForm(fl, "one", "a", "two", "b"), "", "foo -a -b bar", "", "true;bar"))
t.Run("mixed, short, combined", testExec(t, ShortForm(fl, "one", "a", "two", "b"), "", "foo -ab bar", "", "true;bar"))
t.Run("mixed, long", testExec(t, fl, "", "foo --one --two bar", "", "true;bar"))
t.Run("mixed, long, explicit", testExec(t, fl, "", "foo --one true --two bar", "", "true;bar"))
})
t.Run("implicit bool option", func(t *testing.T) {
t.Run("short", testExec(t, ShortForm(fb, "one", "a"), "", "foo -a", "", "true;false;false;false"))
t.Run(
"short, multiple",
testExec(t, ShortForm(fb, "one", "a", "two", "b", "three", "c"), "", "foo -a -b -c", "", "true;true;true;false"),
)
t.Run(
"short, combined",
testExec(t, ShortForm(fb, "one", "a", "two", "b", "three", "c"), "", "foo -abc", "", "true;true;true;false"),
)
t.Run(
"short, combined, multiple",
testExec(t, ShortForm(fb, "one", "a", "two", "b", "three", "c", "four", "d"), "", "foo -ab -cd", "", "true;true;true;true"),
)
t.Run(
"short, multiple values",
testExec(t, ShortForm(flb, "one", "a", "two", "b", "three", "c"), "", "foo -aba -cab", "", "true,true,true;true,true;true"),
)
t.Run("long", testExec(t, fb, "", "foo --one", "", "true;false;false;false"))
t.Run("long, multiple", testExec(t, fb, "", "foo --one --two --three", "", "true;true;true;false"))
t.Run("long, multiple values", testExec(t, flb, "", "foo --one --two --one", "", "true,true;true;"))
})
t.Run("explicit bool option", func(t *testing.T) {
t.Run("short, true", testExec(t, ShortForm(fb, "one", "a"), "", "foo -a true", "", "true;false;false;false"))
t.Run("short, false", testExec(t, ShortForm(fb, "one", "a"), "", "foo -a false", "", "false;false;false;false"))
t.Run("short, with eq", testExec(t, ShortForm(fb, "one", "a"), "", "foo -a=true", "", "true;false;false;false"))
t.Run("short, true variant, capital", testExec(t, ShortForm(fb, "one", "a"), "", "foo -a True", "", "true;false;false;false"))
t.Run("short, true variant, 1", testExec(t, ShortForm(fb, "one", "a"), "", "foo -a 1", "", "true;false;false;false"))
t.Run("short, false variant, 0", testExec(t, ShortForm(fb, "one", "a"), "", "foo -a 0", "", "false;false;false;false"))
t.Run("short, combined", testExec(t, ShortForm(fb, "one", "a", "two", "b"), "", "foo -ab true", "", "true;true;false;false"))
t.Run(
"short, combined, multiple",
testExec(
t,
ShortForm(fb, "one", "a", "two", "b", "three", "c", "four", "d"),
"", "foo -ab true -cd true",
"", "true;true;true;true",
),
)
t.Run("long", testExec(t, fb, "", "foo --one true", "", "true;false;false;false"))
t.Run("long, false", testExec(t, fb, "", "foo --one false", "", "false;false;false;false"))
t.Run("logn, with eq", testExec(t, fb, "", "foo --one=true", "", "true;false;false;false"))
t.Run("long, mixed, first", testExec(t, fb, "", "foo --one false --two", "", "false;true;false;false"))
t.Run("long, mixed, last", testExec(t, fb, "", "foo --one --two false", "", "true;false;false;false"))
})
t.Run("expected bool option", func(t *testing.T) {
t.Run("short, implicit", testExec(t, ShortForm(fb, "one", "a"), "", "foo -a", "", "true;false;false;false"))
t.Run("short, explicit", testExec(t, ShortForm(fb, "one", "a"), "", "foo -a true", "", "true;false;false;false"))
t.Run("short, automatic positional", testExec(t, ShortForm(fbp, "one", "a"), "", "foo -a bar", "", "true;false;false;false;bar"))
t.Run("short, combined", testExec(t, ShortForm(fb, "one", "a", "two", "b"), "", "foo -ab true", "", "true;true;false;false"))
t.Run(
"short, combined, automatic positional",
testExec(t, ShortForm(fbp, "one", "a", "two", "b"), "", "foo -ab bar", "", "true;true;false;false;bar"),
)
t.Run("long, implicit", testExec(t, fb, "", "foo --one", "", "true;false;false;false"))
t.Run("long, explicit", testExec(t, fb, "", "foo --one true", "", "true;false;false;false"))
t.Run("long, automatic positional", testExec(t, fbp, "", "foo --one bar", "", "true;false;false;false;bar"))
})
t.Run("positional", func(t *testing.T) {
t.Run("basic", testExec(t, fp, "", "foo bar baz", "", "0;bar,baz"))
t.Run("explicit", testExec(t, fp, "", "foo -- bar baz", "", "0;bar,baz"))
t.Run("mixed", testExec(t, fp, "", "foo bar -- baz", "", "0;bar,baz"))
t.Run("with option", testExec(t, fp, "", "foo bar --second-field 42 baz", "", "42;bar,baz"))
t.Run("with bool option at the end", testExec(t, fbp, "", "foo bar baz --one", "", "true;false;false;false;bar;baz"))
t.Run("with expected bool, implicit", testExec(t, fbp, "", "foo bar --one baz", "", "true;false;false;false;bar;baz"))
t.Run("with expected bool, explicit", testExec(t, fbp, "", "foo bar --one true baz", "", "true;false;false;false;bar;baz"))
t.Run("option format", testExec(t, fbp, "", "foo -- --one", "", "false;false;false;false;--one"))
})
t.Run("example", func(t *testing.T) {
type s struct {
Foo bool
Bar []bool
Qux bool
Quux string
}
fs := func(s s, a1, a2 string) string {
var sbar []string
for _, b := range s.Bar {
sbar = append(sbar, fmt.Sprint(b))
}
return fmt.Sprintf("%t;%s;%t;%s;%s;%s", s.Foo, strings.Join(sbar, ","), s.Qux, s.Quux, a1, a2)
}
t.Run(
"full",
testExec(
t,
ShortForm(fs, "foo", "a", "bar", "b"),
"",
"foo -ab --bar baz -b --qux --quux corge -- grault",
"",
"true;true,true,true;true;corge;baz;grault",
),
)
})
t.Run("expected or unexpected", func(t *testing.T) {
t.Run("capital letters", testExec(t, fp, "", "foo --One bar", "", "0;--One,bar"))
t.Run("digit in option name", testExec(t, fd, "", "foo --one-2", "", "true"))
t.Run("dash in option name", testExec(t, ff, "", "foo --second-field 42", "", "42"))
t.Run("unpexpected character", testExec(t, fp, "", "foo --one#", "", "0;--one#"))
t.Run(
"invalid short option set",
testExec(t, ShortForm(fp, "one", "a", "one", "b", "second-field", "c"), "", "foo -aBc", "", "0;-aBc"),
)
t.Run("positional separator, no value", testExec(t, fp, "", "foo --one bar --", "", "bar0;"))
t.Run("positional separator, expecting value", testExec(t, fp, "", "foo --one --", "--one", ""))
t.Run("shot flag set, expecting value", testExec(t, ShortForm(fp, "second-field", "b"), "", "foo --one -b", "--one", ""))
})
t.Run("preserve order", func(t *testing.T) {
t.Run("bools", testExec(t, fl, "", "foo --one --one false --one", "", "true,false,true;"))
t.Run("strings", testExec(t, fl, "", "foo --two 1 --two 2 --two 3", "", ";1,2,3"))
})
t.Run("select subcommand", func(t *testing.T) {
t.Run("named", testExec(t, Command("", nil, Command("bar", ff), Command("baz", ff)), "", "foo baz", "", "0"))
t.Run("default", testExec(t, Command("", nil, Command("bar", ff), Default(Command("baz", ff))), "", "foo", "", "0"))
})
}
2025-08-24 01:45:25 +02:00
*/