You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
argh/parser_test.go

1059 lines
26 KiB

package argh_test
import (
"testing"
"git.meatballhat.com/x/argh"
"github.com/davecgh/go-spew/spew"
"github.com/stretchr/testify/assert"
)
func TestParser(t *testing.T) {
traceOnCommandFlag := func(cmd argh.CommandFlag) {
t.Logf("CommandFlag.On: %+#[1]v", cmd)
}
for _, tc := range []struct {
name string
args []string
cfg *argh.ParserConfig
expErr error
expPT []argh.Node
expAST []argh.Node
skip bool
}{
{
name: "basic",
args: []string{
"pies", "-eat", "--wat", "hello", "mario",
},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"e": {On: traceOnCommandFlag},
"a": {On: traceOnCommandFlag},
"t": {On: traceOnCommandFlag},
"wat": {On: traceOnCommandFlag},
},
},
Commands: &argh.Commands{
Map: map[string]argh.CommandConfig{
"hello": argh.CommandConfig{
NValue: 1,
ValueNames: []string{"name"},
On: traceOnCommandFlag,
},
},
},
On: traceOnCommandFlag,
},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pies",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CompoundShortFlag{
Nodes: []argh.Node{
&argh.CommandFlag{Name: "e"},
&argh.CommandFlag{Name: "a"},
&argh.CommandFlag{Name: "t"},
},
},
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "wat"},
&argh.ArgDelimiter{},
&argh.CommandFlag{
Name: "hello",
Values: map[string]string{
"name": "mario",
},
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.Ident{Literal: "mario"},
},
},
},
},
},
expAST: []argh.Node{
&argh.CommandFlag{
Name: "pies",
Nodes: []argh.Node{
&argh.CommandFlag{Name: "e"},
&argh.CommandFlag{Name: "a"},
&argh.CommandFlag{Name: "t"},
&argh.CommandFlag{Name: "wat"},
&argh.CommandFlag{
Name: "hello",
Values: map[string]string{
"name": "mario",
},
Nodes: []argh.Node{
&argh.Ident{Literal: "mario"},
},
},
},
},
},
},
{
name: "persistent flags",
args: []string{
"pies", "--wat", "hello", "mario", "-eat",
},
cfg: &argh.ParserConfig{
Prog: func() *argh.CommandConfig {
cmdCfg := &argh.CommandConfig{
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"e": {Persist: true, On: traceOnCommandFlag},
"a": {Persist: true, On: traceOnCommandFlag},
"t": {Persist: true, On: traceOnCommandFlag},
"wat": {On: traceOnCommandFlag},
},
},
On: traceOnCommandFlag,
}
cmdCfg.Commands = &argh.Commands{
Map: map[string]argh.CommandConfig{
"hello": argh.CommandConfig{
NValue: 1,
ValueNames: []string{"name"},
Flags: &argh.Flags{
Parent: cmdCfg.Flags,
Map: map[string]argh.FlagConfig{},
},
On: traceOnCommandFlag,
},
},
}
return cmdCfg
}(),
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pies",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "wat"},
&argh.ArgDelimiter{},
&argh.CommandFlag{
Name: "hello",
Values: map[string]string{
"name": "mario",
},
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.Ident{Literal: "mario"},
&argh.ArgDelimiter{},
&argh.CompoundShortFlag{
Nodes: []argh.Node{
&argh.CommandFlag{Name: "e"},
&argh.CommandFlag{Name: "a"},
&argh.CommandFlag{Name: "t"},
},
},
},
},
},
},
},
expAST: []argh.Node{
&argh.CommandFlag{
Name: "pies",
Nodes: []argh.Node{
&argh.CommandFlag{Name: "wat"},
&argh.CommandFlag{
Name: "hello",
Values: map[string]string{
"name": "mario",
},
Nodes: []argh.Node{
&argh.Ident{Literal: "mario"},
&argh.CommandFlag{Name: "e"},
&argh.CommandFlag{Name: "a"},
&argh.CommandFlag{Name: "t"},
},
},
},
},
},
},
{
name: "bare",
args: []string{"pizzas"},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
},
},
expAST: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
},
},
},
{
name: "one positional arg",
args: []string{"pizzas", "excel"},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{NValue: 1, On: traceOnCommandFlag},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Values: map[string]string{"0": "excel"},
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.Ident{Literal: "excel"},
},
},
},
expAST: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Values: map[string]string{"0": "excel"},
Nodes: []argh.Node{
&argh.Ident{Literal: "excel"},
},
},
},
},
{
name: "many positional args",
args: []string{"pizzas", "excel", "wildly", "when", "feral"},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{
NValue: argh.OneOrMoreValue,
ValueNames: []string{"word"},
On: traceOnCommandFlag,
},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Values: map[string]string{
"word": "excel",
"word.1": "wildly",
"word.2": "when",
"word.3": "feral",
},
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.Ident{Literal: "excel"},
&argh.ArgDelimiter{},
&argh.Ident{Literal: "wildly"},
&argh.ArgDelimiter{},
&argh.Ident{Literal: "when"},
&argh.ArgDelimiter{},
&argh.Ident{Literal: "feral"},
},
},
},
expAST: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Values: map[string]string{
"word": "excel",
"word.1": "wildly",
"word.2": "when",
"word.3": "feral",
},
Nodes: []argh.Node{
&argh.Ident{Literal: "excel"},
&argh.Ident{Literal: "wildly"},
&argh.Ident{Literal: "when"},
&argh.Ident{Literal: "feral"},
},
},
},
},
{
name: "long value-less flags",
args: []string{"pizzas", "--tasty", "--fresh", "--super-hot-right-now"},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"tasty": {On: traceOnCommandFlag},
"fresh": {On: traceOnCommandFlag},
"super-hot-right-now": {On: traceOnCommandFlag},
},
},
On: traceOnCommandFlag,
},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "tasty"},
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "fresh"},
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "super-hot-right-now"},
},
},
},
expAST: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.CommandFlag{Name: "tasty"},
&argh.CommandFlag{Name: "fresh"},
&argh.CommandFlag{Name: "super-hot-right-now"},
},
},
},
},
{
name: "long flags mixed",
args: []string{
"pizzas",
"--tasty",
"--fresh", "soon",
"--super-hot-right-now",
"--box", "square", "shaped", "hot",
"--please",
},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{
Commands: &argh.Commands{Map: map[string]argh.CommandConfig{}},
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"tasty": {On: traceOnCommandFlag},
"fresh": argh.FlagConfig{NValue: 1, On: traceOnCommandFlag},
"super-hot-right-now": {On: traceOnCommandFlag},
"box": argh.FlagConfig{NValue: argh.OneOrMoreValue, On: traceOnCommandFlag},
"please": {On: traceOnCommandFlag},
},
},
On: traceOnCommandFlag,
},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "tasty"},
&argh.ArgDelimiter{},
&argh.CommandFlag{
Name: "fresh",
Values: map[string]string{"0": "soon"},
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.Ident{Literal: "soon"},
},
},
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "super-hot-right-now"},
&argh.ArgDelimiter{},
&argh.CommandFlag{
Name: "box",
Values: map[string]string{"0": "square", "1": "shaped", "2": "hot"},
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.Ident{Literal: "square"},
&argh.ArgDelimiter{},
&argh.Ident{Literal: "shaped"},
&argh.ArgDelimiter{},
&argh.Ident{Literal: "hot"},
&argh.ArgDelimiter{},
},
},
&argh.CommandFlag{Name: "please"},
},
},
},
expAST: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.CommandFlag{Name: "tasty"},
&argh.CommandFlag{
Name: "fresh",
Values: map[string]string{"0": "soon"},
Nodes: []argh.Node{
&argh.Ident{Literal: "soon"},
},
},
&argh.CommandFlag{Name: "super-hot-right-now"},
&argh.CommandFlag{
Name: "box",
Values: map[string]string{"0": "square", "1": "shaped", "2": "hot"},
Nodes: []argh.Node{
&argh.Ident{Literal: "square"},
&argh.Ident{Literal: "shaped"},
&argh.Ident{Literal: "hot"},
},
},
&argh.CommandFlag{Name: "please"},
},
},
},
},
{
name: "short value-less flags",
args: []string{"pizzas", "-t", "-f", "-s"},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"t": {On: traceOnCommandFlag},
"f": {On: traceOnCommandFlag},
"s": {On: traceOnCommandFlag},
},
},
On: traceOnCommandFlag,
},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "t"},
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "f"},
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "s"},
},
},
},
expAST: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.CommandFlag{Name: "t"},
&argh.CommandFlag{Name: "f"},
&argh.CommandFlag{Name: "s"},
},
},
},
},
{
name: "compound short flags",
args: []string{"pizzas", "-aca", "-blol"},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"a": {On: traceOnCommandFlag},
"b": {On: traceOnCommandFlag},
"c": {On: traceOnCommandFlag},
"l": {On: traceOnCommandFlag},
"o": {On: traceOnCommandFlag},
},
},
On: traceOnCommandFlag,
},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CompoundShortFlag{
Nodes: []argh.Node{
&argh.CommandFlag{Name: "a"},
&argh.CommandFlag{Name: "c"},
&argh.CommandFlag{Name: "a"},
},
},
&argh.ArgDelimiter{},
&argh.CompoundShortFlag{
Nodes: []argh.Node{
&argh.CommandFlag{Name: "b"},
&argh.CommandFlag{Name: "l"},
&argh.CommandFlag{Name: "o"},
&argh.CommandFlag{Name: "l"},
},
},
},
},
},
expAST: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.CommandFlag{Name: "a"},
&argh.CommandFlag{Name: "c"},
&argh.CommandFlag{Name: "a"},
&argh.CommandFlag{Name: "b"},
&argh.CommandFlag{Name: "l"},
&argh.CommandFlag{Name: "o"},
&argh.CommandFlag{Name: "l"},
},
},
},
},
{
name: "mixed long short value flags",
args: []string{"pizzas", "-a", "--ca", "-b", "1312", "-lol"},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{
Commands: &argh.Commands{Map: map[string]argh.CommandConfig{}},
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"a": {On: traceOnCommandFlag},
"b": argh.FlagConfig{NValue: 1, On: traceOnCommandFlag},
"ca": {On: traceOnCommandFlag},
"l": {On: traceOnCommandFlag},
"o": {On: traceOnCommandFlag},
},
},
On: traceOnCommandFlag,
},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "a"},
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "ca"},
&argh.ArgDelimiter{},
&argh.CommandFlag{
Name: "b",
Values: map[string]string{"0": "1312"},
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.Ident{Literal: "1312"},
},
},
&argh.ArgDelimiter{},
&argh.CompoundShortFlag{
Nodes: []argh.Node{
&argh.CommandFlag{Name: "l"},
&argh.CommandFlag{Name: "o"},
&argh.CommandFlag{Name: "l"},
},
},
},
},
},
expAST: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.CommandFlag{Name: "a"},
&argh.CommandFlag{Name: "ca"},
&argh.CommandFlag{
Name: "b",
Values: map[string]string{"0": "1312"},
Nodes: []argh.Node{
&argh.Ident{Literal: "1312"},
},
},
&argh.CommandFlag{Name: "l"},
&argh.CommandFlag{Name: "o"},
&argh.CommandFlag{Name: "l"},
},
},
},
},
{
name: "nested commands with positional args",
args: []string{"pizzas", "fly", "freely", "sometimes", "and", "other", "times", "fry", "deeply", "--forever"},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{
Commands: &argh.Commands{
Map: map[string]argh.CommandConfig{
"fly": argh.CommandConfig{
Commands: &argh.Commands{
Map: map[string]argh.CommandConfig{
"fry": argh.CommandConfig{
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"forever": {On: traceOnCommandFlag},
},
},
},
},
},
},
},
},
Flags: &argh.Flags{Map: map[string]argh.FlagConfig{}},
On: traceOnCommandFlag,
},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CommandFlag{
Name: "fly",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.Ident{Literal: "freely"},
&argh.ArgDelimiter{},
&argh.Ident{Literal: "sometimes"},
&argh.ArgDelimiter{},
&argh.Ident{Literal: "and"},
&argh.ArgDelimiter{},
&argh.Ident{Literal: "other"},
&argh.ArgDelimiter{},
&argh.Ident{Literal: "times"},
&argh.ArgDelimiter{},
&argh.CommandFlag{
Name: "fry",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.Ident{Literal: "deeply"},
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "forever"},
},
},
},
},
},
},
},
expAST: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.CommandFlag{
Name: "fly",
Nodes: []argh.Node{
&argh.Ident{Literal: "freely"},
&argh.Ident{Literal: "sometimes"},
&argh.Ident{Literal: "and"},
&argh.Ident{Literal: "other"},
&argh.Ident{Literal: "times"},
&argh.CommandFlag{
Name: "fry",
Nodes: []argh.Node{
&argh.Ident{Literal: "deeply"},
&argh.CommandFlag{Name: "forever"},
},
},
},
},
},
},
},
},
{
name: "compound flags with values",
args: []string{"pizzas", "-need", "sauce", "heat", "love", "-also", "over9000"},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"a": {NValue: argh.ZeroOrMoreValue, On: traceOnCommandFlag},
"d": {NValue: argh.OneOrMoreValue, On: traceOnCommandFlag},
"e": {On: traceOnCommandFlag},
"l": {On: traceOnCommandFlag},
"n": {On: traceOnCommandFlag},
"o": {NValue: 1, ValueNames: []string{"level"}, On: traceOnCommandFlag},
"s": {NValue: argh.ZeroOrMoreValue, On: traceOnCommandFlag},
},
},
On: traceOnCommandFlag,
},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CompoundShortFlag{
Nodes: []argh.Node{
&argh.CommandFlag{Name: "n"},
&argh.CommandFlag{Name: "e"},
&argh.CommandFlag{Name: "e"},
&argh.CommandFlag{
Name: "d",
Values: map[string]string{
"0": "sauce",
"1": "heat",
"2": "love",
},
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.Ident{Literal: "sauce"},
&argh.ArgDelimiter{},
&argh.Ident{Literal: "heat"},
&argh.ArgDelimiter{},
&argh.Ident{Literal: "love"},
&argh.ArgDelimiter{},
},
},
},
},
&argh.CompoundShortFlag{
Nodes: []argh.Node{
&argh.CommandFlag{Name: "a"},
&argh.CommandFlag{Name: "l"},
&argh.CommandFlag{Name: "s"},
&argh.CommandFlag{
Name: "o",
Values: map[string]string{
"level": "over9000",
},
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.Ident{Literal: "over9000"},
},
},
},
},
},
},
},
expAST: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.CommandFlag{Name: "n"},
&argh.CommandFlag{Name: "e"},
&argh.CommandFlag{Name: "e"},
&argh.CommandFlag{
Name: "d",
Values: map[string]string{
"0": "sauce",
"1": "heat",
"2": "love",
},
Nodes: []argh.Node{
&argh.Ident{Literal: "sauce"},
&argh.Ident{Literal: "heat"},
&argh.Ident{Literal: "love"},
},
},
&argh.CommandFlag{Name: "a"},
&argh.CommandFlag{Name: "l"},
&argh.CommandFlag{Name: "s"},
&argh.CommandFlag{
Name: "o",
Values: map[string]string{
"level": "over9000",
},
Nodes: []argh.Node{
&argh.Ident{Literal: "over9000"},
},
},
},
},
},
},
{
name: "command specific flags",
args: []string{"pizzas", "fly", "--freely", "fry", "--deeply", "-wAt", "hugs"},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{
Commands: &argh.Commands{
Map: map[string]argh.CommandConfig{
"fly": argh.CommandConfig{
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"freely": {On: traceOnCommandFlag},
},
},
Commands: &argh.Commands{
Map: map[string]argh.CommandConfig{
"fry": argh.CommandConfig{
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"deeply": {On: traceOnCommandFlag},
"w": {On: traceOnCommandFlag},
"A": {On: traceOnCommandFlag},
"t": argh.FlagConfig{NValue: 1, On: traceOnCommandFlag},
},
},
},
},
},
},
},
},
Flags: &argh.Flags{Map: map[string]argh.FlagConfig{}},
On: traceOnCommandFlag,
},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CommandFlag{
Name: "fly",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "freely"},
&argh.ArgDelimiter{},
&argh.CommandFlag{
Name: "fry",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "deeply"},
&argh.ArgDelimiter{},
&argh.CompoundShortFlag{
Nodes: []argh.Node{
&argh.CommandFlag{Name: "w"},
&argh.CommandFlag{Name: "A"},
&argh.CommandFlag{
Name: "t",
Values: map[string]string{"0": "hugs"},
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.Ident{Literal: "hugs"},
},
},
},
},
},
},
},
},
},
},
},
expAST: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.CommandFlag{
Name: "fly",
Nodes: []argh.Node{
&argh.CommandFlag{Name: "freely"},
&argh.CommandFlag{
Name: "fry",
Nodes: []argh.Node{
&argh.CommandFlag{Name: "deeply"},
&argh.CommandFlag{Name: "w"},
&argh.CommandFlag{Name: "A"},
&argh.CommandFlag{
Name: "t",
Values: map[string]string{"0": "hugs"},
Nodes: []argh.Node{
&argh.Ident{Literal: "hugs"},
},
},
},
},
},
},
},
},
},
},
{
name: "total weirdo",
args: []string{"PIZZAs", "^wAT@golf", "^^hecKing", "goose", "bonk", "^^FIERCENESS@-2"},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{
Commands: &argh.Commands{
Map: map[string]argh.CommandConfig{
"goose": argh.CommandConfig{
NValue: 1,
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"FIERCENESS": argh.FlagConfig{NValue: 1, On: traceOnCommandFlag},
},
},
},
},
},
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"w": {On: traceOnCommandFlag},
"A": {On: traceOnCommandFlag},
"T": {NValue: 1, On: traceOnCommandFlag},
"hecKing": {On: traceOnCommandFlag},
},
},
On: traceOnCommandFlag,
},
ScannerConfig: &argh.ScannerConfig{
AssignmentOperator: '@',
FlagPrefix: '^',
MultiValueDelim: ',',
},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "PIZZAs",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CompoundShortFlag{
Nodes: []argh.Node{
&argh.CommandFlag{Name: "w"},
&argh.CommandFlag{Name: "A"},
&argh.CommandFlag{
Name: "T",
Values: map[string]string{"0": "golf"},
Nodes: []argh.Node{
&argh.Assign{},
&argh.Ident{Literal: "golf"},
},
},
},
},
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "hecKing"},
&argh.ArgDelimiter{},
&argh.CommandFlag{
Name: "goose",
Values: map[string]string{"0": "bonk"},
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.Ident{Literal: "bonk"},
&argh.ArgDelimiter{},
&argh.CommandFlag{
Name: "FIERCENESS",
Values: map[string]string{"0": "-2"},
Nodes: []argh.Node{
&argh.Assign{},
&argh.Ident{Literal: "-2"},
},
},
},
},
},
},
},
},
{
name: "windows like",
args: []string{"hotdog", "/f", "/L", "/o:ppy", "hats"},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"f": {On: traceOnCommandFlag},
"L": {On: traceOnCommandFlag},
"o": argh.FlagConfig{NValue: 1, On: traceOnCommandFlag},
},
},
Commands: &argh.Commands{
Map: map[string]argh.CommandConfig{
"hats": {},
},
},
On: traceOnCommandFlag,
},
ScannerConfig: &argh.ScannerConfig{
AssignmentOperator: ':',
FlagPrefix: '/',
MultiValueDelim: ',',
},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "hotdog",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "f"},
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "L"},
&argh.ArgDelimiter{},
&argh.CommandFlag{
Name: "o",
Values: map[string]string{"0": "ppy"},
Nodes: []argh.Node{
&argh.Assign{},
&argh.Ident{Literal: "ppy"},
},
},
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "hats"},
},
},
},
},
{
name: "invalid bare assignment",
args: []string{"pizzas", "=", "--wat"},
cfg: &argh.ParserConfig{
Prog: &argh.CommandConfig{
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"wat": {On: traceOnCommandFlag},
},
},
On: traceOnCommandFlag,
},
},
expErr: argh.ParserErrorList{
&argh.ParserError{Pos: argh.Position{Column: 8}, Msg: "invalid bare assignment"},
},
expPT: []argh.Node{
&argh.CommandFlag{
Name: "pizzas",
Nodes: []argh.Node{
&argh.ArgDelimiter{},
&argh.ArgDelimiter{},
&argh.CommandFlag{Name: "wat"},
},
},
},
},
} {
if tc.expPT != nil {
t.Run(tc.name+" parse tree", func(ct *testing.T) {
if tc.skip {
ct.SkipNow()
return
}
pCfg := tc.cfg
if pCfg == nil {
pCfg = argh.NewParserConfig()
}
pt, err := argh.ParseArgs(tc.args, pCfg)
if err != nil || tc.expErr != nil {
if !assert.ErrorIs(ct, err, tc.expErr) {
spew.Dump(err, tc.expErr)
spew.Dump(pt)
}
return
}
if !assert.Equal(ct, tc.expPT, pt.Nodes) {
spew.Dump(pt)
}
})
}
if tc.expAST != nil {
t.Run(tc.name+" ast", func(ct *testing.T) {
if tc.skip {
ct.SkipNow()
return
}
pCfg := tc.cfg
if pCfg == nil {
pCfg = argh.NewParserConfig()
}
pt, err := argh.ParseArgs(tc.args, pCfg)
if err != nil || tc.expErr != nil {
if !assert.ErrorIs(ct, err, tc.expErr) {
spew.Dump(pt)
}
return
}
ast := argh.ToAST(pt.Nodes)
if !assert.Equal(ct, tc.expAST, ast) {
spew.Dump(ast)
}
})
}
}
}