mirror of
https://github.com/fatedier/frp.git
synced 2024-12-14 02:09:13 +08:00
1537 lines
42 KiB
Go
1537 lines
42 KiB
Go
/*
|
|
Based of off docopt.py: https://github.com/docopt/docopt
|
|
|
|
Licensed under terms of MIT license (see LICENSE-MIT)
|
|
Copyright (c) 2013 Keith Batten, kbatten@gmail.com
|
|
*/
|
|
|
|
package docopt
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"reflect"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestPatternFlat(t *testing.T) {
|
|
q := patternList{
|
|
newArgument("N", nil),
|
|
newOption("-a", "", 0, false),
|
|
newArgument("M", nil)}
|
|
p, err := newRequired(
|
|
newOneOrMore(newArgument("N", nil)),
|
|
newOption("-a", "", 0, false),
|
|
newArgument("M", nil)).flat(patternDefault)
|
|
if reflect.DeepEqual(p, q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
q = patternList{newOptionsShortcut()}
|
|
p, err = newRequired(
|
|
newOptional(newOptionsShortcut()),
|
|
newOptional(newOption("-a", "", 0, false))).flat(patternOptionSSHORTCUT)
|
|
if reflect.DeepEqual(p, q) != true {
|
|
t.Error(err)
|
|
}
|
|
return
|
|
}
|
|
|
|
func TestOption(t *testing.T) {
|
|
if !parseOption("-h").eq(newOption("-h", "", 0, false)) {
|
|
t.Fail()
|
|
}
|
|
if !parseOption("--help").eq(newOption("", "--help", 0, false)) {
|
|
t.Fail()
|
|
}
|
|
if !parseOption("-h --help").eq(newOption("-h", "--help", 0, false)) {
|
|
t.Fail()
|
|
}
|
|
if !parseOption("-h, --help").eq(newOption("-h", "--help", 0, false)) {
|
|
t.Fail()
|
|
}
|
|
|
|
if !parseOption("-h TOPIC").eq(newOption("-h", "", 1, false)) {
|
|
t.Fail()
|
|
}
|
|
if !parseOption("--help TOPIC").eq(newOption("", "--help", 1, false)) {
|
|
t.Fail()
|
|
}
|
|
if !parseOption("-h TOPIC --help TOPIC").eq(newOption("-h", "--help", 1, false)) {
|
|
t.Fail()
|
|
}
|
|
if !parseOption("-h TOPIC, --help TOPIC").eq(newOption("-h", "--help", 1, false)) {
|
|
t.Fail()
|
|
}
|
|
if !parseOption("-h TOPIC, --help=TOPIC").eq(newOption("-h", "--help", 1, false)) {
|
|
t.Fail()
|
|
}
|
|
|
|
if !parseOption("-h Description...").eq(newOption("-h", "", 0, false)) {
|
|
t.Fail()
|
|
}
|
|
if !parseOption("-h --help Description...").eq(newOption("-h", "--help", 0, false)) {
|
|
t.Fail()
|
|
}
|
|
if !parseOption("-h TOPIC Description...").eq(newOption("-h", "", 1, false)) {
|
|
t.Fail()
|
|
}
|
|
|
|
if !parseOption(" -h").eq(newOption("-h", "", 0, false)) {
|
|
t.Fail()
|
|
}
|
|
|
|
if !parseOption("-h TOPIC Description... [default: 2]").eq(newOption("-h", "", 1, "2")) {
|
|
t.Fail()
|
|
}
|
|
if !parseOption("-h TOPIC Descripton... [default: topic-1]").eq(newOption("-h", "", 1, "topic-1")) {
|
|
t.Fail()
|
|
}
|
|
if !parseOption("--help=TOPIC ... [default: 3.14]").eq(newOption("", "--help", 1, "3.14")) {
|
|
t.Fail()
|
|
}
|
|
if !parseOption("-h, --help=DIR ... [default: ./]").eq(newOption("-h", "--help", 1, "./")) {
|
|
t.Fail()
|
|
}
|
|
if !parseOption("-h TOPIC Descripton... [dEfAuLt: 2]").eq(newOption("-h", "", 1, "2")) {
|
|
t.Fail()
|
|
}
|
|
return
|
|
}
|
|
|
|
func TestOptionName(t *testing.T) {
|
|
if newOption("-h", "", 0, false).name != "-h" {
|
|
t.Fail()
|
|
}
|
|
if newOption("-h", "--help", 0, false).name != "--help" {
|
|
t.Fail()
|
|
}
|
|
if newOption("", "--help", 0, false).name != "--help" {
|
|
t.Fail()
|
|
}
|
|
return
|
|
}
|
|
|
|
func TestCommands(t *testing.T) {
|
|
if v, err := Parse("Usage: prog add", []string{"add"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": true}) != true {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse("Usage: prog [add]", []string{}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": false}) != true {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse("Usage: prog [add]", []string{"add"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": true}) != true {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse("Usage: prog (add|rm)", []string{"add"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": true, "rm": false}) != true {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse("Usage: prog (add|rm)", []string{"rm"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": false, "rm": true}) != true {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse("Usage: prog a b", []string{"a", "b"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"a": true, "b": true}) != true {
|
|
t.Error(err)
|
|
}
|
|
_, err := Parse("Usage: prog a b", []string{"b", "a"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Error(err)
|
|
}
|
|
return
|
|
}
|
|
|
|
func TestFormalUsage(t *testing.T) {
|
|
doc := `
|
|
Usage: prog [-hv] ARG
|
|
prog N M
|
|
|
|
prog is a program`
|
|
usage := parseSection("usage:", doc)[0]
|
|
if usage != "Usage: prog [-hv] ARG\n prog N M" {
|
|
t.FailNow()
|
|
}
|
|
formal, err := formalUsage(usage)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if formal != "( [-hv] ARG ) | ( N M )" {
|
|
t.Fail()
|
|
}
|
|
return
|
|
}
|
|
|
|
func TestParseArgv(t *testing.T) {
|
|
o := patternList{
|
|
newOption("-h", "", 0, false),
|
|
newOption("-v", "--verbose", 0, false),
|
|
newOption("-f", "--file", 1, false),
|
|
}
|
|
|
|
p, err := parseArgv(tokenListFromString(""), &o, false)
|
|
q := patternList{}
|
|
if reflect.DeepEqual(p, q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parseArgv(tokenListFromString("-h"), &o, false)
|
|
q = patternList{newOption("-h", "", 0, true)}
|
|
if reflect.DeepEqual(p, q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parseArgv(tokenListFromString("-h --verbose"), &o, false)
|
|
q = patternList{
|
|
newOption("-h", "", 0, true),
|
|
newOption("-v", "--verbose", 0, true),
|
|
}
|
|
if reflect.DeepEqual(p, q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parseArgv(tokenListFromString("-h --file f.txt"), &o, false)
|
|
q = patternList{
|
|
newOption("-h", "", 0, true),
|
|
newOption("-f", "--file", 1, "f.txt"),
|
|
}
|
|
if reflect.DeepEqual(p, q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parseArgv(tokenListFromString("-h --file f.txt arg"), &o, false)
|
|
q = patternList{
|
|
newOption("-h", "", 0, true),
|
|
newOption("-f", "--file", 1, "f.txt"),
|
|
newArgument("", "arg"),
|
|
}
|
|
if reflect.DeepEqual(p, q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parseArgv(tokenListFromString("-h --file f.txt arg arg2"), &o, false)
|
|
q = patternList{
|
|
newOption("-h", "", 0, true),
|
|
newOption("-f", "--file", 1, "f.txt"),
|
|
newArgument("", "arg"),
|
|
newArgument("", "arg2"),
|
|
}
|
|
if reflect.DeepEqual(p, q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parseArgv(tokenListFromString("-h arg -- -v"), &o, false)
|
|
q = patternList{
|
|
newOption("-h", "", 0, true),
|
|
newArgument("", "arg"),
|
|
newArgument("", "--"),
|
|
newArgument("", "-v"),
|
|
}
|
|
if reflect.DeepEqual(p, q) != true {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestParsePattern(t *testing.T) {
|
|
o := patternList{
|
|
newOption("-h", "", 0, false),
|
|
newOption("-v", "--verbose", 0, false),
|
|
newOption("-f", "--file", 1, false),
|
|
}
|
|
|
|
p, err := parsePattern("[ -h ]", &o)
|
|
q := newRequired(newOptional(newOption("-h", "", 0, false)))
|
|
if p.eq(q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parsePattern("[ ARG ... ]", &o)
|
|
q = newRequired(newOptional(
|
|
newOneOrMore(
|
|
newArgument("ARG", nil))))
|
|
if p.eq(q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parsePattern("[ -h | -v ]", &o)
|
|
q = newRequired(
|
|
newOptional(
|
|
newEither(
|
|
newOption("-h", "", 0, false),
|
|
newOption("-v", "--verbose", 0, false))))
|
|
if p.eq(q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parsePattern("( -h | -v [ --file <f> ] )", &o)
|
|
q = newRequired(
|
|
newRequired(
|
|
newEither(
|
|
newOption("-h", "", 0, false),
|
|
newRequired(
|
|
newOption("-v", "--verbose", 0, false),
|
|
newOptional(
|
|
newOption("-f", "--file", 1, nil))))))
|
|
if p.eq(q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parsePattern("(-h|-v[--file=<f>]N...)", &o)
|
|
q = newRequired(
|
|
newRequired(
|
|
newEither(
|
|
newOption("-h", "", 0, false),
|
|
newRequired(
|
|
newOption("-v", "--verbose", 0, false),
|
|
newOptional(
|
|
newOption("-f", "--file", 1, nil)),
|
|
newOneOrMore(
|
|
newArgument("N", nil))))))
|
|
if p.eq(q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parsePattern("(N [M | (K | L)] | O P)", &o)
|
|
q = newRequired(
|
|
newRequired(
|
|
newEither(
|
|
newRequired(
|
|
newArgument("N", nil),
|
|
newOptional(
|
|
newEither(
|
|
newArgument("M", nil),
|
|
newRequired(
|
|
newEither(
|
|
newArgument("K", nil),
|
|
newArgument("L", nil)))))),
|
|
newRequired(
|
|
newArgument("O", nil),
|
|
newArgument("P", nil)))))
|
|
if p.eq(q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parsePattern("[ -h ] [N]", &o)
|
|
q = newRequired(
|
|
newOptional(
|
|
newOption("-h", "", 0, false)),
|
|
newOptional(
|
|
newArgument("N", nil)))
|
|
if p.eq(q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parsePattern("[options]", &o)
|
|
q = newRequired(
|
|
newOptional(
|
|
newOptionsShortcut()))
|
|
if p.eq(q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parsePattern("[options] A", &o)
|
|
q = newRequired(
|
|
newOptional(
|
|
newOptionsShortcut()),
|
|
newArgument("A", nil))
|
|
if p.eq(q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parsePattern("-v [options]", &o)
|
|
q = newRequired(
|
|
newOption("-v", "--verbose", 0, false),
|
|
newOptional(
|
|
newOptionsShortcut()))
|
|
if p.eq(q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parsePattern("ADD", &o)
|
|
q = newRequired(newArgument("ADD", nil))
|
|
if p.eq(q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parsePattern("<add>", &o)
|
|
q = newRequired(newArgument("<add>", nil))
|
|
if p.eq(q) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
p, err = parsePattern("add", &o)
|
|
q = newRequired(newCommand("add", false))
|
|
if p.eq(q) != true {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestOptionMatch(t *testing.T) {
|
|
v, w, x := newOption("-a", "", 0, false).match(
|
|
&patternList{newOption("-a", "", 0, true)}, nil)
|
|
y := patternList{newOption("-a", "", 0, true)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOption("-a", "", 0, false).match(
|
|
&patternList{newOption("-x", "", 0, false)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false)}
|
|
if v != false ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, patternList{}) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOption("-a", "", 0, false).match(
|
|
&patternList{newOption("-x", "", 0, false)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false)}
|
|
if v != false ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, patternList{}) != true {
|
|
t.Fail()
|
|
}
|
|
v, w, x = newOption("-a", "", 0, false).match(
|
|
&patternList{newArgument("N", nil)}, nil)
|
|
y = patternList{newArgument("N", nil)}
|
|
if v != false ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, patternList{}) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOption("-a", "", 0, false).match(
|
|
&patternList{
|
|
newOption("-x", "", 0, false),
|
|
newOption("-a", "", 0, false),
|
|
newArgument("N", nil)}, nil)
|
|
y = patternList{
|
|
newOption("-x", "", 0, false),
|
|
newArgument("N", nil)}
|
|
z := patternList{newOption("-a", "", 0, false)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOption("-a", "", 0, false).match(
|
|
&patternList{
|
|
newOption("-a", "", 0, true),
|
|
newOption("-a", "", 0, false)}, nil)
|
|
y = patternList{newOption("-a", "", 0, false)}
|
|
z = patternList{newOption("-a", "", 0, true)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestArgumentMatch(t *testing.T) {
|
|
v, w, x := newArgument("N", nil).match(
|
|
&patternList{newArgument("N", 9)}, nil)
|
|
y := patternList{newArgument("N", 9)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newArgument("N", nil).match(
|
|
&patternList{newOption("-x", "", 0, false)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false)}
|
|
if v != false ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, patternList{}) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newArgument("N", nil).match(
|
|
&patternList{newOption("-x", "", 0, false),
|
|
newOption("-a", "", 0, false),
|
|
newArgument("", 5)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false),
|
|
newOption("-a", "", 0, false)}
|
|
z := patternList{newArgument("N", 5)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newArgument("N", nil).match(
|
|
&patternList{newArgument("", 9),
|
|
newArgument("", 0)}, nil)
|
|
y = patternList{newArgument("", 0)}
|
|
z = patternList{newArgument("N", 9)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestCommandMatch(t *testing.T) {
|
|
v, w, x := newCommand("c", false).match(
|
|
&patternList{newArgument("", "c")}, nil)
|
|
y := patternList{newCommand("c", true)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newCommand("c", false).match(
|
|
&patternList{newOption("-x", "", 0, false)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false)}
|
|
if v != false ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, patternList{}) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newCommand("c", false).match(
|
|
&patternList{
|
|
newOption("-x", "", 0, false),
|
|
newOption("-a", "", 0, false),
|
|
newArgument("", "c")}, nil)
|
|
y = patternList{newOption("-x", "", 0, false),
|
|
newOption("-a", "", 0, false)}
|
|
z := patternList{newCommand("c", true)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newEither(
|
|
newCommand("add", false),
|
|
newCommand("rm", false)).match(
|
|
&patternList{newArgument("", "rm")}, nil)
|
|
y = patternList{newCommand("rm", true)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestOptionalMatch(t *testing.T) {
|
|
v, w, x := newOptional(newOption("-a", "", 0, false)).match(
|
|
&patternList{newOption("-a", "", 0, false)}, nil)
|
|
y := patternList{newOption("-a", "", 0, false)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOptional(newOption("-a", "", 0, false)).match(
|
|
&patternList{}, nil)
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, patternList{}) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOptional(newOption("-a", "", 0, false)).match(
|
|
&patternList{newOption("-x", "", 0, false)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, patternList{}) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOptional(newOption("-a", "", 0, false),
|
|
newOption("-b", "", 0, false)).match(
|
|
&patternList{newOption("-a", "", 0, false)}, nil)
|
|
y = patternList{newOption("-a", "", 0, false)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOptional(newOption("-a", "", 0, false),
|
|
newOption("-b", "", 0, false)).match(
|
|
&patternList{newOption("-b", "", 0, false)}, nil)
|
|
y = patternList{newOption("-b", "", 0, false)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOptional(newOption("-a", "", 0, false),
|
|
newOption("-b", "", 0, false)).match(
|
|
&patternList{newOption("-x", "", 0, false)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, patternList{}) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOptional(newArgument("N", nil)).match(
|
|
&patternList{newArgument("", 9)}, nil)
|
|
y = patternList{newArgument("N", 9)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOptional(newOption("-a", "", 0, false),
|
|
newOption("-b", "", 0, false)).match(
|
|
&patternList{newOption("-b", "", 0, false),
|
|
newOption("-x", "", 0, false),
|
|
newOption("-a", "", 0, false)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false)}
|
|
z := patternList{newOption("-a", "", 0, false),
|
|
newOption("-b", "", 0, false)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestRequiredMatch(t *testing.T) {
|
|
v, w, x := newRequired(newOption("-a", "", 0, false)).match(
|
|
&patternList{newOption("-a", "", 0, false)}, nil)
|
|
y := patternList{newOption("-a", "", 0, false)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newRequired(newOption("-a", "", 0, false)).match(&patternList{}, nil)
|
|
if v != false ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, patternList{}) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newRequired(newOption("-a", "", 0, false)).match(
|
|
&patternList{newOption("-x", "", 0, false)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false)}
|
|
if v != false ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, patternList{}) != true {
|
|
t.Fail()
|
|
}
|
|
v, w, x = newRequired(newOption("-a", "", 0, false),
|
|
newOption("-b", "", 0, false)).match(
|
|
&patternList{newOption("-a", "", 0, false)}, nil)
|
|
y = patternList{newOption("-a", "", 0, false)}
|
|
if v != false ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, patternList{}) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestEitherMatch(t *testing.T) {
|
|
v, w, x := newEither(
|
|
newOption("-a", "", 0, false),
|
|
newOption("-b", "", 0, false)).match(
|
|
&patternList{newOption("-a", "", 0, false)}, nil)
|
|
y := patternList{newOption("-a", "", 0, false)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newEither(
|
|
newOption("-a", "", 0, false),
|
|
newOption("-b", "", 0, false)).match(&patternList{
|
|
newOption("-a", "", 0, false),
|
|
newOption("-b", "", 0, false)}, nil)
|
|
y = patternList{newOption("-b", "", 0, false)}
|
|
z := patternList{newOption("-a", "", 0, false)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newEither(
|
|
newOption("-a", "", 0, false),
|
|
newOption("-b", "", 0, false)).match(&patternList{
|
|
newOption("-x", "", 0, false)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false)}
|
|
z = patternList{}
|
|
if v != false ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newEither(
|
|
newOption("-a", "", 0, false),
|
|
newOption("-b", "", 0, false),
|
|
newOption("-c", "", 0, false)).match(&patternList{
|
|
newOption("-x", "", 0, false),
|
|
newOption("-b", "", 0, false)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false)}
|
|
z = patternList{newOption("-b", "", 0, false)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
v, w, x = newEither(
|
|
newArgument("M", nil),
|
|
newRequired(newArgument("N", nil),
|
|
newArgument("M", nil))).match(&patternList{
|
|
newArgument("", 1),
|
|
newArgument("", 2)}, nil)
|
|
y = patternList{}
|
|
z = patternList{newArgument("N", 1), newArgument("M", 2)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestOneOrMoreMatch(t *testing.T) {
|
|
v, w, x := newOneOrMore(newArgument("N", nil)).match(
|
|
&patternList{newArgument("", 9)}, nil)
|
|
y := patternList{newArgument("N", 9)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOneOrMore(newArgument("N", nil)).match(
|
|
&patternList{}, nil)
|
|
y = patternList{}
|
|
z := patternList{}
|
|
if v != false ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOneOrMore(newArgument("N", nil)).match(
|
|
&patternList{newOption("-x", "", 0, false)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false)}
|
|
z = patternList{}
|
|
if v != false ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOneOrMore(newArgument("N", nil)).match(
|
|
&patternList{newArgument("", 9), newArgument("", 8)}, nil)
|
|
y = patternList{}
|
|
z = patternList{newArgument("N", 9), newArgument("N", 8)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOneOrMore(newArgument("N", nil)).match(&patternList{
|
|
newArgument("", 9),
|
|
newOption("-x", "", 0, false),
|
|
newArgument("", 8)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false)}
|
|
z = patternList{newArgument("N", 9), newArgument("N", 8)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOneOrMore(newOption("-a", "", 0, false)).match(&patternList{
|
|
newOption("-a", "", 0, false),
|
|
newArgument("", 8),
|
|
newOption("-a", "", 0, false)}, nil)
|
|
y = patternList{newArgument("", 8)}
|
|
z = patternList{newOption("-a", "", 0, false), newOption("-a", "", 0, false)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOneOrMore(newOption("-a", "", 0, false)).match(&patternList{
|
|
newArgument("", 8),
|
|
newOption("-x", "", 0, false)}, nil)
|
|
y = patternList{newArgument("", 8), newOption("-x", "", 0, false)}
|
|
z = patternList{}
|
|
if v != false ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOneOrMore(newRequired(newOption("-a", "", 0, false),
|
|
newArgument("N", nil))).match(&patternList{
|
|
newOption("-a", "", 0, false),
|
|
newArgument("", 1),
|
|
newOption("-x", "", 0, false),
|
|
newOption("-a", "", 0, false),
|
|
newArgument("", 2)}, nil)
|
|
y = patternList{newOption("-x", "", 0, false)}
|
|
z = patternList{newOption("-a", "", 0, false),
|
|
newArgument("N", 1),
|
|
newOption("-a", "", 0, false),
|
|
newArgument("N", 2)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v, w, x = newOneOrMore(newOptional(newArgument("N", nil))).match(
|
|
&patternList{newArgument("", 9)}, nil)
|
|
y = patternList{}
|
|
z = patternList{newArgument("N", 9)}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestListArgumentMatch(t *testing.T) {
|
|
p := newRequired(
|
|
newArgument("N", nil),
|
|
newArgument("N", nil))
|
|
p.fix()
|
|
v, w, x := p.match(&patternList{newArgument("", "1"),
|
|
newArgument("", "2")}, nil)
|
|
y := patternList{newArgument("N", []string{"1", "2"})}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
p = newOneOrMore(newArgument("N", nil))
|
|
p.fix()
|
|
v, w, x = p.match(&patternList{newArgument("", "1"),
|
|
newArgument("", "2"), newArgument("", "3")}, nil)
|
|
y = patternList{newArgument("N", []string{"1", "2", "3"})}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
p = newRequired(newArgument("N", nil),
|
|
newOneOrMore(newArgument("N", nil)))
|
|
p.fix()
|
|
v, w, x = p.match(&patternList{
|
|
newArgument("", "1"),
|
|
newArgument("", "2"),
|
|
newArgument("", "3")}, nil)
|
|
y = patternList{newArgument("N", []string{"1", "2", "3"})}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
p = newRequired(newArgument("N", nil),
|
|
newRequired(newArgument("N", nil)))
|
|
p.fix()
|
|
v, w, x = p.match(&patternList{
|
|
newArgument("", "1"),
|
|
newArgument("", "2")}, nil)
|
|
y = patternList{newArgument("N", []string{"1", "2"})}
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestBasicPatternMatching(t *testing.T) {
|
|
// ( -a N [ -x Z ] )
|
|
p := newRequired(
|
|
newOption("-a", "", 0, false),
|
|
newArgument("N", nil),
|
|
newOptional(
|
|
newOption("-x", "", 0, false),
|
|
newArgument("Z", nil)))
|
|
|
|
// -a N
|
|
q := patternList{newOption("-a", "", 0, false), newArgument("", 9)}
|
|
y := patternList{newOption("-a", "", 0, false), newArgument("N", 9)}
|
|
v, w, x := p.match(&q, nil)
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, patternList{}) != true ||
|
|
reflect.DeepEqual(*x, y) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
// -a -x N Z
|
|
q = patternList{newOption("-a", "", 0, false),
|
|
newOption("-x", "", 0, false),
|
|
newArgument("", 9), newArgument("", 5)}
|
|
y = patternList{}
|
|
z := patternList{newOption("-a", "", 0, false), newArgument("N", 9),
|
|
newOption("-x", "", 0, false), newArgument("Z", 5)}
|
|
v, w, x = p.match(&q, nil)
|
|
if v != true ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
// -x N Z # BZZ!
|
|
q = patternList{newOption("-x", "", 0, false),
|
|
newArgument("", 9), newArgument("", 5)}
|
|
y = patternList{newOption("-x", "", 0, false),
|
|
newArgument("", 9), newArgument("", 5)}
|
|
z = patternList{}
|
|
v, w, x = p.match(&q, nil)
|
|
if v != false ||
|
|
reflect.DeepEqual(*w, y) != true ||
|
|
reflect.DeepEqual(*x, z) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestPatternEither(t *testing.T) {
|
|
p := newOption("-a", "", 0, false).transform()
|
|
q := newEither(newRequired(
|
|
newOption("-a", "", 0, false)))
|
|
if p.eq(q) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
p = newArgument("A", nil).transform()
|
|
q = newEither(newRequired(
|
|
newArgument("A", nil)))
|
|
if p.eq(q) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
p = newRequired(
|
|
newEither(
|
|
newOption("-a", "", 0, false),
|
|
newOption("-b", "", 0, false)),
|
|
newOption("-c", "", 0, false)).transform()
|
|
q = newEither(
|
|
newRequired(
|
|
newOption("-a", "", 0, false),
|
|
newOption("-c", "", 0, false)),
|
|
newRequired(
|
|
newOption("-b", "", 0, false),
|
|
newOption("-c", "", 0, false)))
|
|
if p.eq(q) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
p = newOptional(newOption("-a", "", 0, false),
|
|
newEither(newOption("-b", "", 0, false),
|
|
newOption("-c", "", 0, false))).transform()
|
|
q = newEither(
|
|
newRequired(
|
|
newOption("-b", "", 0, false), newOption("-a", "", 0, false)),
|
|
newRequired(
|
|
newOption("-c", "", 0, false), newOption("-a", "", 0, false)))
|
|
if p.eq(q) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
p = newEither(newOption("-x", "", 0, false),
|
|
newEither(newOption("-y", "", 0, false),
|
|
newOption("-z", "", 0, false))).transform()
|
|
q = newEither(
|
|
newRequired(newOption("-x", "", 0, false)),
|
|
newRequired(newOption("-y", "", 0, false)),
|
|
newRequired(newOption("-z", "", 0, false)))
|
|
if p.eq(q) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
p = newOneOrMore(newArgument("N", nil),
|
|
newArgument("M", nil)).transform()
|
|
q = newEither(
|
|
newRequired(newArgument("N", nil), newArgument("M", nil),
|
|
newArgument("N", nil), newArgument("M", nil)))
|
|
if p.eq(q) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestPatternFixRepeatingArguments(t *testing.T) {
|
|
p := newOption("-a", "", 0, false)
|
|
p.fixRepeatingArguments()
|
|
if p.eq(newOption("-a", "", 0, false)) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
p = newArgument("N", nil)
|
|
p.fixRepeatingArguments()
|
|
if p.eq(newArgument("N", nil)) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
p = newRequired(
|
|
newArgument("N", nil),
|
|
newArgument("N", nil))
|
|
q := newRequired(
|
|
newArgument("N", []string{}),
|
|
newArgument("N", []string{}))
|
|
p.fixRepeatingArguments()
|
|
if p.eq(q) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
p = newEither(
|
|
newArgument("N", nil),
|
|
newOneOrMore(newArgument("N", nil)))
|
|
q = newEither(
|
|
newArgument("N", []string{}),
|
|
newOneOrMore(newArgument("N", []string{})))
|
|
p.fix()
|
|
if p.eq(q) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestSet(t *testing.T) {
|
|
p := newArgument("N", nil)
|
|
q := newArgument("N", nil)
|
|
if reflect.DeepEqual(p, q) != true {
|
|
t.Fail()
|
|
}
|
|
pl := patternList{newArgument("N", nil), newArgument("N", nil)}
|
|
ql := patternList{newArgument("N", nil)}
|
|
if reflect.DeepEqual(pl.unique(), ql.unique()) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestPatternFixIdentities1(t *testing.T) {
|
|
p := newRequired(
|
|
newArgument("N", nil),
|
|
newArgument("N", nil))
|
|
if len(p.children) < 2 {
|
|
t.FailNow()
|
|
}
|
|
if p.children[0].eq(p.children[1]) != true {
|
|
t.Fail()
|
|
}
|
|
if p.children[0] == p.children[1] {
|
|
t.Fail()
|
|
}
|
|
p.fixIdentities(nil)
|
|
if p.children[0] != p.children[1] {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestPatternFixIdentities2(t *testing.T) {
|
|
p := newRequired(
|
|
newOptional(
|
|
newArgument("X", nil),
|
|
newArgument("N", nil)),
|
|
newArgument("N", nil))
|
|
if len(p.children) < 2 {
|
|
t.FailNow()
|
|
}
|
|
if len(p.children[0].children) < 2 {
|
|
t.FailNow()
|
|
}
|
|
if p.children[0].children[1].eq(p.children[1]) != true {
|
|
t.Fail()
|
|
}
|
|
if p.children[0].children[1] == p.children[1] {
|
|
t.Fail()
|
|
}
|
|
p.fixIdentities(nil)
|
|
if p.children[0].children[1] != p.children[1] {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestLongOptionsErrorHandling(t *testing.T) {
|
|
_, err := Parse("Usage: prog", []string{"--non-existent"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err))
|
|
}
|
|
_, err = Parse("Usage: prog [--version --verbose]\nOptions: --version\n --verbose",
|
|
[]string{"--ver"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Error(err)
|
|
}
|
|
_, err = Parse("Usage: prog --long\nOptions: --long ARG", []string{}, true, "", false, false)
|
|
if _, ok := err.(*LanguageError); !ok {
|
|
t.Error(err)
|
|
}
|
|
_, err = Parse("Usage: prog --long ARG\nOptions: --long ARG",
|
|
[]string{"--long"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err))
|
|
}
|
|
_, err = Parse("Usage: prog --long=ARG\nOptions: --long", []string{}, true, "", false, false)
|
|
if _, ok := err.(*LanguageError); !ok {
|
|
t.Error(err)
|
|
}
|
|
_, err = Parse("Usage: prog --long\nOptions: --long",
|
|
[]string{}, true, "--long=ARG", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestShortOptionsErrorHandling(t *testing.T) {
|
|
_, err := Parse("Usage: prog -x\nOptions: -x this\n -x that", []string{}, true, "", false, false)
|
|
if _, ok := err.(*LanguageError); !ok {
|
|
t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err))
|
|
}
|
|
_, err = Parse("Usage: prog", []string{"-x"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Error(err)
|
|
}
|
|
_, err = Parse("Usage: prog -o\nOptions: -o ARG", []string{}, true, "", false, false)
|
|
if _, ok := err.(*LanguageError); !ok {
|
|
t.Error(err)
|
|
}
|
|
_, err = Parse("Usage: prog -o ARG\nOptions: -o ARG", []string{"-o"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestMatchingParen(t *testing.T) {
|
|
_, err := Parse("Usage: prog [a [b]", []string{}, true, "", false, false)
|
|
if _, ok := err.(*LanguageError); !ok {
|
|
t.Error(err)
|
|
}
|
|
_, err = Parse("Usage: prog [a [b] ] c )", []string{}, true, "", false, false)
|
|
if _, ok := err.(*LanguageError); !ok {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestAllowDoubleDash(t *testing.T) {
|
|
if v, err := Parse("usage: prog [-o] [--] <arg>\noptions: -o", []string{"--", "-o"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-o": false, "<arg>": "-o", "--": true}) != true {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse("usage: prog [-o] [--] <arg>\noptions: -o", []string{"-o", "1"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-o": true, "<arg>": "1", "--": false}) != true {
|
|
t.Error(err)
|
|
}
|
|
_, err := Parse("usage: prog [-o] <arg>\noptions:-o", []string{"-o"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok { //"--" is not allowed; FIXME?
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestDocopt(t *testing.T) {
|
|
doc := `Usage: prog [-v] A
|
|
|
|
Options: -v Be verbose.`
|
|
if v, err := Parse(doc, []string{"arg"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": false, "A": "arg"}) != true {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse(doc, []string{"-v", "arg"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": true, "A": "arg"}) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
doc = `Usage: prog [-vqr] [FILE]
|
|
prog INPUT OUTPUT
|
|
prog --help
|
|
|
|
Options:
|
|
-v print status messages
|
|
-q report only file names
|
|
-r show all occurrences of the same error
|
|
--help
|
|
|
|
`
|
|
if v, err := Parse(doc, []string{"-v", "file.py"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": true, "-q": false, "-r": false, "--help": false, "FILE": "file.py", "INPUT": nil, "OUTPUT": nil}) != true {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse(doc, []string{"-v"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": true, "-q": false, "-r": false, "--help": false, "FILE": nil, "INPUT": nil, "OUTPUT": nil}) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
_, err := Parse(doc, []string{"-v", "input.py", "output.py"}, true, "", false, false) // does not match
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Error(err)
|
|
}
|
|
_, err = Parse(doc, []string{"--fake"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Error(err)
|
|
}
|
|
_, output, err := parseOutput(doc, []string{"--hel"}, true, "", false)
|
|
if err != nil || len(output) == 0 {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestLanguageErrors(t *testing.T) {
|
|
_, err := Parse("no usage with colon here", []string{}, true, "", false, false)
|
|
if _, ok := err.(*LanguageError); !ok {
|
|
t.Error(err)
|
|
}
|
|
_, err = Parse("usage: here \n\n and again usage: here", []string{}, true, "", false, false)
|
|
if _, ok := err.(*LanguageError); !ok {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestIssue40(t *testing.T) {
|
|
_, output, err := parseOutput("usage: prog --help-commands | --help", []string{"--help"}, true, "", false)
|
|
if err != nil || len(output) == 0 {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse("usage: prog --aabb | --aa", []string{"--aa"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--aabb": false, "--aa": true}) != true {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestIssue34UnicodeStrings(t *testing.T) {
|
|
// TODO: see if applicable
|
|
}
|
|
|
|
func TestCountMultipleFlags(t *testing.T) {
|
|
if v, err := Parse("usage: prog [-v]", []string{"-v"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": true}) != true {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse("usage: prog [-vv]", []string{}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 0}) != true {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse("usage: prog [-vv]", []string{"-v"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 1}) != true {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse("usage: prog [-vv]", []string{"-vv"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 2}) != true {
|
|
t.Error(err)
|
|
}
|
|
_, err := Parse("usage: prog [-vv]", []string{"-vvv"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse("usage: prog [-v | -vv | -vvv]", []string{"-vvv"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 3}) != true {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse("usage: prog [-v...]", []string{"-vvvvvv"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 6}) != true {
|
|
t.Error(err)
|
|
}
|
|
if v, err := Parse("usage: prog [--ver --ver]", []string{"--ver", "--ver"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--ver": 2}) != true {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestAnyOptionsParameter(t *testing.T) {
|
|
_, err := Parse("usage: prog [options]",
|
|
[]string{"-foo", "--bar", "--spam=eggs"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Fail()
|
|
}
|
|
|
|
_, err = Parse("usage: prog [options]",
|
|
[]string{"--foo", "--bar", "--bar"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Fail()
|
|
}
|
|
_, err = Parse("usage: prog [options]",
|
|
[]string{"--bar", "--bar", "--bar", "-ffff"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Fail()
|
|
}
|
|
_, err = Parse("usage: prog [options]",
|
|
[]string{"--long=arg", "--long=another"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestDefaultValueForPositionalArguments(t *testing.T) {
|
|
doc := "Usage: prog [--data=<data>...]\nOptions:\n\t-d --data=<arg> Input data [default: x]"
|
|
if v, err := Parse(doc, []string{}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--data": []string{"x"}}) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
doc = "Usage: prog [--data=<data>...]\nOptions:\n\t-d --data=<arg> Input data [default: x y]"
|
|
if v, err := Parse(doc, []string{}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--data": []string{"x", "y"}}) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
doc = "Usage: prog [--data=<data>...]\nOptions:\n\t-d --data=<arg> Input data [default: x y]"
|
|
if v, err := Parse(doc, []string{"--data=this"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--data": []string{"this"}}) != true {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestIssue59(t *testing.T) {
|
|
if v, err := Parse("usage: prog --long=<a>", []string{"--long="}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--long": ""}) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
if v, err := Parse("usage: prog -l <a>\noptions: -l <a>", []string{"-l", ""}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-l": ""}) != true {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestOptionsFirst(t *testing.T) {
|
|
if v, err := Parse("usage: prog [--opt] [<args>...]", []string{"--opt", "this", "that"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--opt": true, "<args>": []string{"this", "that"}}) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
if v, err := Parse("usage: prog [--opt] [<args>...]", []string{"this", "that", "--opt"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--opt": true, "<args>": []string{"this", "that"}}) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
if v, err := Parse("usage: prog [--opt] [<args>...]", []string{"this", "that", "--opt"}, true, "", true, false); reflect.DeepEqual(v, map[string]interface{}{"--opt": false, "<args>": []string{"this", "that", "--opt"}}) != true {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestIssue68OptionsShortcutDoesNotIncludeOptionsInUsagePattern(t *testing.T) {
|
|
args, err := Parse("usage: prog [-ab] [options]\noptions: -x\n -y", []string{"-ax"}, true, "", false, false)
|
|
|
|
if args["-a"] != true {
|
|
t.Error(err)
|
|
}
|
|
if args["-b"] != false {
|
|
t.Error(err)
|
|
}
|
|
if args["-x"] != true {
|
|
t.Error(err)
|
|
}
|
|
if args["-y"] != false {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestIssue65EvaluateArgvWhenCalledNotWhenImported(t *testing.T) {
|
|
os.Args = strings.Fields("prog -a")
|
|
v, err := Parse("usage: prog [-ab]", nil, true, "", false, false)
|
|
w := map[string]interface{}{"-a": true, "-b": false}
|
|
if reflect.DeepEqual(v, w) != true {
|
|
t.Error(err)
|
|
}
|
|
|
|
os.Args = strings.Fields("prog -b")
|
|
v, err = Parse("usage: prog [-ab]", nil, true, "", false, false)
|
|
w = map[string]interface{}{"-a": false, "-b": true}
|
|
if reflect.DeepEqual(v, w) != true {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestIssue71DoubleDashIsNotAValidOptionArgument(t *testing.T) {
|
|
_, err := Parse("usage: prog [--log=LEVEL] [--] <args>...",
|
|
[]string{"--log", "--", "1", "2"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Fail()
|
|
}
|
|
|
|
_, err = Parse(`usage: prog [-l LEVEL] [--] <args>...
|
|
options: -l LEVEL`, []string{"-l", "--", "1", "2"}, true, "", false, false)
|
|
if _, ok := err.(*UserError); !ok {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestParseSection(t *testing.T) {
|
|
v := parseSection("usage:", "foo bar fizz buzz")
|
|
w := []string{}
|
|
if reflect.DeepEqual(v, w) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v = parseSection("usage:", "usage: prog")
|
|
w = []string{"usage: prog"}
|
|
if reflect.DeepEqual(v, w) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
v = parseSection("usage:", "usage: -x\n -y")
|
|
w = []string{"usage: -x\n -y"}
|
|
if reflect.DeepEqual(v, w) != true {
|
|
t.Fail()
|
|
}
|
|
|
|
usage := `usage: this
|
|
|
|
usage:hai
|
|
usage: this that
|
|
|
|
usage: foo
|
|
bar
|
|
|
|
PROGRAM USAGE:
|
|
foo
|
|
bar
|
|
usage:
|
|
` + "\t" + `too
|
|
` + "\t" + `tar
|
|
Usage: eggs spam
|
|
BAZZ
|
|
usage: pit stop`
|
|
|
|
v = parseSection("usage:", usage)
|
|
w = []string{"usage: this",
|
|
"usage:hai",
|
|
"usage: this that",
|
|
"usage: foo\n bar",
|
|
"PROGRAM USAGE:\n foo\n bar",
|
|
"usage:\n\ttoo\n\ttar",
|
|
"Usage: eggs spam",
|
|
"usage: pit stop",
|
|
}
|
|
if reflect.DeepEqual(v, w) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestIssue126DefaultsNotParsedCorrectlyWhenTabs(t *testing.T) {
|
|
section := "Options:\n\t--foo=<arg> [default: bar]"
|
|
v := patternList{newOption("", "--foo", 1, "bar")}
|
|
if reflect.DeepEqual(parseDefaults(section), v) != true {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
// conf file based test cases
|
|
func TestFileTestcases(t *testing.T) {
|
|
filenames := []string{"testcases.docopt", "test_golang.docopt"}
|
|
for _, filename := range filenames {
|
|
raw, err := ioutil.ReadFile(filename)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tests, err := parseTest(raw)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, c := range tests {
|
|
result, err := Parse(c.doc, c.argv, true, "", false, false)
|
|
if _, ok := err.(*UserError); c.userError && !ok {
|
|
// expected a user-error
|
|
t.Error("testcase:", c.id, "result:", result)
|
|
} else if _, ok := err.(*UserError); !c.userError && ok {
|
|
// unexpected user-error
|
|
t.Error("testcase:", c.id, "error:", err, "result:", result)
|
|
} else if reflect.DeepEqual(c.expect, result) != true {
|
|
t.Error("testcase:", c.id, "result:", result, "expect:", c.expect)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
type testcase struct {
|
|
id int
|
|
doc string
|
|
prog string
|
|
argv []string
|
|
expect map[string]interface{}
|
|
userError bool
|
|
}
|
|
|
|
func parseTest(raw []byte) ([]testcase, error) {
|
|
var res []testcase
|
|
commentPattern := regexp.MustCompile("#.*")
|
|
raw = commentPattern.ReplaceAll(raw, []byte(""))
|
|
raw = bytes.TrimSpace(raw)
|
|
if bytes.HasPrefix(raw, []byte(`"""`)) {
|
|
raw = raw[3:]
|
|
}
|
|
|
|
id := 0
|
|
for _, fixture := range bytes.Split(raw, []byte(`r"""`)) {
|
|
doc, _, body := stringPartition(string(fixture), `"""`)
|
|
for _, cas := range strings.Split(body, "$")[1:] {
|
|
argvString, _, expectString := stringPartition(strings.TrimSpace(cas), "\n")
|
|
prog, _, argvString := stringPartition(strings.TrimSpace(argvString), " ")
|
|
argv := []string{}
|
|
if len(argvString) > 0 {
|
|
argv = strings.Fields(argvString)
|
|
}
|
|
var expectUntyped interface{}
|
|
err := json.Unmarshal([]byte(expectString), &expectUntyped)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
switch expect := expectUntyped.(type) {
|
|
case string: // user-error
|
|
res = append(res, testcase{id, doc, prog, argv, nil, true})
|
|
case map[string]interface{}:
|
|
// convert []interface{} values to []string
|
|
// convert float64 values to int
|
|
for k, vUntyped := range expect {
|
|
switch v := vUntyped.(type) {
|
|
case []interface{}:
|
|
itemList := make([]string, len(v))
|
|
for i, itemUntyped := range v {
|
|
if item, ok := itemUntyped.(string); ok {
|
|
itemList[i] = item
|
|
}
|
|
}
|
|
expect[k] = itemList
|
|
case float64:
|
|
expect[k] = int(v)
|
|
}
|
|
}
|
|
res = append(res, testcase{id, doc, prog, argv, expect, false})
|
|
default:
|
|
return nil, fmt.Errorf("unhandled json data type")
|
|
}
|
|
id++
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
// parseOutput wraps the Parse() function to also return stdout
|
|
func parseOutput(doc string, argv []string, help bool, version string,
|
|
optionsFirst bool) (map[string]interface{}, string, error) {
|
|
stdout := os.Stdout
|
|
r, w, _ := os.Pipe()
|
|
os.Stdout = w
|
|
|
|
args, err := Parse(doc, argv, help, version, optionsFirst, false)
|
|
|
|
outChan := make(chan string)
|
|
go func() {
|
|
var buf bytes.Buffer
|
|
io.Copy(&buf, r)
|
|
outChan <- buf.String()
|
|
}()
|
|
|
|
w.Close()
|
|
os.Stdout = stdout
|
|
output := <-outChan
|
|
|
|
return args, output, err
|
|
}
|
|
|
|
var debugEnabled = false
|
|
|
|
func debugOn(l ...interface{}) {
|
|
debugEnabled = true
|
|
debug(l...)
|
|
}
|
|
func debugOff(l ...interface{}) {
|
|
debug(l...)
|
|
debugEnabled = false
|
|
}
|
|
|
|
func debug(l ...interface{}) {
|
|
if debugEnabled {
|
|
fmt.Println(l...)
|
|
}
|
|
}
|