kevinschoon-pomo/vendor/github.com/jawher/mow.cli/matchers_test.go

228 lines
7.2 KiB
Go

package cli
import (
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestShortcut(t *testing.T) {
pc := &parseContext{}
args := []string{"a", "b"}
ok, nargs := shortcut.match(args, pc)
require.True(t, ok, "shortcut always matches")
require.Equal(t, args, nargs, "shortcut doesn't touch the passed args")
}
func TestOptsEnd(t *testing.T) {
pc := &parseContext{}
args := []string{"a", "b"}
ok, nargs := optsEnd.match(args, pc)
require.True(t, ok, "optsEnd always matches")
require.Equal(t, args, nargs, "optsEnd doesn't touch the passed args")
require.True(t, pc.rejectOptions, "optsEnd sets the rejectOptions flag")
}
func TestArgMatcher(t *testing.T) {
arg := &arg{name: "X"}
{
pc := newParseContext()
args := []string{"a", "b"}
ok, nargs := arg.match(args, &pc)
require.True(t, ok, "arg should match")
require.Equal(t, []string{"b"}, nargs, "arg should consume the matched value")
require.Equal(t, []string{"a"}, pc.args[arg], "arg should stored the matched value")
}
{
pc := newParseContext()
ok, _ := arg.match([]string{"-v"}, &pc)
require.False(t, ok, "arg should not match options")
}
{
pc := newParseContext()
pc.rejectOptions = true
ok, _ := arg.match([]string{"-v"}, &pc)
require.True(t, ok, "arg should match options when the reject flag is set")
}
}
func TestBoolOptMatcher(t *testing.T) {
forceOpt := &opt{names: []string{"-f", "--force"}, value: newBoolValue(new(bool), false)}
optMatcher := &optMatcher{
theOne: forceOpt,
optionsIdx: map[string]*opt{
"-f": forceOpt,
"--force": forceOpt,
"-g": {names: []string{"-g"}, value: newBoolValue(new(bool), false)},
"-x": {names: []string{"-x"}, value: newBoolValue(new(bool), false)},
"-y": {names: []string{"-y"}, value: newBoolValue(new(bool), false)},
},
}
cases := []struct {
args []string
nargs []string
val []string
}{
{[]string{"-f", "x"}, []string{"x"}, []string{"true"}},
{[]string{"-f=true", "x"}, []string{"x"}, []string{"true"}},
{[]string{"-f=false", "x"}, []string{"x"}, []string{"false"}},
{[]string{"--force", "x"}, []string{"x"}, []string{"true"}},
{[]string{"--force=true", "x"}, []string{"x"}, []string{"true"}},
{[]string{"--force=false", "x"}, []string{"x"}, []string{"false"}},
{[]string{"-fgxy", "x"}, []string{"-gxy", "x"}, []string{"true"}},
{[]string{"-gfxy", "x"}, []string{"-gxy", "x"}, []string{"true"}},
{[]string{"-gxfy", "x"}, []string{"-gxy", "x"}, []string{"true"}},
{[]string{"-gxyf", "x"}, []string{"-gxy", "x"}, []string{"true"}},
}
for _, cas := range cases {
t.Logf("Testing case: %#v", cas)
pc := newParseContext()
ok, nargs := optMatcher.match(cas.args, &pc)
require.True(t, ok, "opt should match")
require.Equal(t, cas.nargs, nargs, "opt should consume the option name")
require.Equal(t, cas.val, pc.opts[forceOpt], "true should stored as the option's value")
pc = newParseContext()
pc.rejectOptions = true
nok, _ := optMatcher.match(cas.args, &pc)
require.False(t, nok, "opt shouldn't match when rejectOptions flag is set")
}
}
func TestOptMatcher(t *testing.T) {
names := []string{"-f", "--force"}
opts := []*opt{
{names: names, value: newStringValue(new(string), "")},
{names: names, value: newIntValue(new(int), 0)},
{names: names, value: newStringsValue(new([]string), nil)},
{names: names, value: newIntsValue(new([]int), nil)},
}
cases := []struct {
args []string
nargs []string
val []string
}{
{[]string{"-f", "x"}, []string{}, []string{"x"}},
{[]string{"-f=x", "y"}, []string{"y"}, []string{"x"}},
{[]string{"-fx", "y"}, []string{"y"}, []string{"x"}},
{[]string{"-afx", "y"}, []string{"-a", "y"}, []string{"x"}},
{[]string{"-af", "x", "y"}, []string{"-a", "y"}, []string{"x"}},
{[]string{"--force", "x"}, []string{}, []string{"x"}},
{[]string{"--force=x", "y"}, []string{"y"}, []string{"x"}},
}
for _, cas := range cases {
for _, forceOpt := range opts {
t.Logf("Testing case: %#v with opt: %#v", cas, forceOpt)
optMatcher := &optMatcher{
theOne: forceOpt,
optionsIdx: map[string]*opt{
"-f": forceOpt,
"--force": forceOpt,
"-a": {names: []string{"-a"}, value: newBoolValue(new(bool), false)},
},
}
pc := newParseContext()
ok, nargs := optMatcher.match(cas.args, &pc)
require.True(t, ok, "opt %#v should match args %v, %v", forceOpt, cas.args, forceOpt.isBool())
require.Equal(t, cas.nargs, nargs, "opt should consume the option name")
require.Equal(t, cas.val, pc.opts[forceOpt], "true should stored as the option's value")
pc = newParseContext()
pc.rejectOptions = true
nok, _ := optMatcher.match(cas.args, &pc)
require.False(t, nok, "opt shouldn't match when rejectOptions flag is set")
}
}
}
func TestOptsMatcher(t *testing.T) {
opts := optsMatcher{
options: []*opt{
{names: []string{"-f", "--force"}, value: newBoolValue(new(bool), false)},
{names: []string{"-g", "--green"}, value: newStringValue(new(string), "")},
},
optionsIndex: map[string]*opt{},
}
for _, o := range opts.options {
for _, n := range o.names {
opts.optionsIndex[n] = o
}
}
cases := []struct {
args []string
nargs []string
val [][]string
}{
{[]string{"-f", "x"}, []string{"x"}, [][]string{{"true"}, nil}},
{[]string{"-f=false", "y"}, []string{"y"}, [][]string{{"false"}, nil}},
{[]string{"--force", "x"}, []string{"x"}, [][]string{{"true"}, nil}},
{[]string{"--force=false", "y"}, []string{"y"}, [][]string{{"false"}, nil}},
{[]string{"-g", "x"}, []string{}, [][]string{nil, {"x"}}},
{[]string{"-g=x", "y"}, []string{"y"}, [][]string{nil, {"x"}}},
{[]string{"-gx", "y"}, []string{"y"}, [][]string{nil, {"x"}}},
{[]string{"--green", "x"}, []string{}, [][]string{nil, {"x"}}},
{[]string{"--green=x", "y"}, []string{"y"}, [][]string{nil, {"x"}}},
{[]string{"-f", "-g", "x", "y"}, []string{"y"}, [][]string{{"true"}, {"x"}}},
{[]string{"-g", "x", "-f", "y"}, []string{"y"}, [][]string{{"true"}, {"x"}}},
{[]string{"-fg", "x", "y"}, []string{"y"}, [][]string{{"true"}, {"x"}}},
{[]string{"-fgxxx", "y"}, []string{"y"}, [][]string{{"true"}, {"xxx"}}},
}
for _, cas := range cases {
t.Logf("testing with args %v", cas.args)
pc := newParseContext()
ok, nargs := opts.match(cas.args, &pc)
require.True(t, ok, "opts should match")
require.Equal(t, cas.nargs, nargs, "opts should consume the option name")
for i, opt := range opts.options {
require.Equal(t, cas.val[i], pc.opts[opt], "the option value for %v should be stored", opt)
}
pc = newParseContext()
pc.rejectOptions = true
nok, _ := opts.match(cas.args, &pc)
require.False(t, nok, "opts shouldn't match when rejectOptions flag is set")
}
}
// Issue 55
func TestOptsMatcherInfiniteLoop(t *testing.T) {
opts := optsMatcher{
options: []*opt{
{names: []string{"-g"}, value: newStringValue(new(string), ""), valueSetFromEnv: true},
},
optionsIndex: map[string]*opt{},
}
for _, o := range opts.options {
for _, n := range o.names {
opts.optionsIndex[n] = o
}
}
done := make(chan struct{}, 1)
pc := newParseContext()
go func() {
opts.match([]string{"-x"}, &pc)
done <- struct{}{}
}()
select {
case <-done:
// nop, everything is good
case <-time.After(5 * time.Second):
t.Fatalf("Timed out after 5 seconds. Infinite loop in optsMatcher.")
}
}