2018-01-11 22:19:25 +00:00
|
|
|
package mcfg
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2018-08-13 18:17:53 +00:00
|
|
|
"fmt"
|
|
|
|
"strings"
|
2018-01-11 22:19:25 +00:00
|
|
|
. "testing"
|
2018-08-13 18:17:53 +00:00
|
|
|
"time"
|
2018-01-11 22:19:25 +00:00
|
|
|
|
2018-07-03 00:20:00 +00:00
|
|
|
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
2018-08-13 18:17:53 +00:00
|
|
|
"github.com/mediocregopher/mediocre-go-lib/mtest/massert"
|
2018-08-13 19:03:30 +00:00
|
|
|
"github.com/mediocregopher/mediocre-go-lib/mtest/mchk"
|
2018-01-11 22:19:25 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestSourceCLIHelp(t *T) {
|
|
|
|
cfg := New()
|
|
|
|
cfg.ParamInt("foo", 5, "Test int param")
|
|
|
|
cfg.ParamBool("bar", "Test bool param")
|
|
|
|
cfg.ParamString("baz", "baz", "Test string param")
|
|
|
|
cfg.ParamString("baz2", "", "")
|
|
|
|
src := SourceCLI{}
|
|
|
|
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
pvM, err := src.cliParamVals(cfg)
|
|
|
|
require.NoError(t, err)
|
|
|
|
SourceCLI{}.printHelp(buf, pvM)
|
|
|
|
|
|
|
|
exp := `
|
|
|
|
--bar (Flag)
|
|
|
|
Test bool param
|
|
|
|
|
|
|
|
--baz (Default: "baz")
|
|
|
|
Test string param
|
|
|
|
|
|
|
|
--baz2
|
|
|
|
|
|
|
|
--foo (Default: 5)
|
|
|
|
Test int param
|
|
|
|
|
|
|
|
`
|
|
|
|
assert.Equal(t, exp, buf.String())
|
|
|
|
}
|
2018-08-13 18:17:53 +00:00
|
|
|
|
2018-08-13 19:03:30 +00:00
|
|
|
func TestSourceCLI(t *T) {
|
|
|
|
type state struct {
|
|
|
|
cfg *Cfg
|
|
|
|
availCfgs []*Cfg
|
2018-08-13 18:17:53 +00:00
|
|
|
|
2018-08-13 19:03:30 +00:00
|
|
|
SourceCLI
|
|
|
|
expPVs []ParamValue
|
2018-08-13 18:17:53 +00:00
|
|
|
}
|
|
|
|
|
2018-08-13 19:03:30 +00:00
|
|
|
type params struct {
|
|
|
|
name string
|
|
|
|
availCfgI int // not technically needed, but makes subsequent steps easier
|
|
|
|
path []string
|
|
|
|
isBool bool
|
|
|
|
nonBoolType string // "int", "str", "duration", "json"
|
|
|
|
unset bool
|
|
|
|
nonBoolWEq bool // use equal sign when setting value
|
|
|
|
nonBoolVal string
|
2018-08-13 18:17:53 +00:00
|
|
|
}
|
|
|
|
|
2018-08-13 19:03:30 +00:00
|
|
|
chk := mchk.Checker{
|
|
|
|
Init: func() mchk.State {
|
|
|
|
var s state
|
2018-08-13 18:17:53 +00:00
|
|
|
s.cfg = New()
|
|
|
|
{
|
|
|
|
a := s.cfg.Child("a")
|
|
|
|
b := s.cfg.Child("b")
|
|
|
|
c := s.cfg.Child("c")
|
|
|
|
ab := a.Child("b")
|
|
|
|
bc := b.Child("c")
|
|
|
|
abc := ab.Child("c")
|
|
|
|
s.availCfgs = []*Cfg{s.cfg, a, b, c, ab, bc, abc}
|
|
|
|
}
|
|
|
|
s.SourceCLI.Args = make([]string, 0, 16)
|
|
|
|
return s
|
|
|
|
},
|
2018-08-13 19:03:30 +00:00
|
|
|
Next: func(ss mchk.State) mchk.Action {
|
|
|
|
s := ss.(state)
|
|
|
|
var p params
|
2018-08-13 18:17:53 +00:00
|
|
|
if i := mrand.Intn(8); i == 0 {
|
2018-08-13 19:03:30 +00:00
|
|
|
p.name = mrand.Hex(1) + "-" + mrand.Hex(8)
|
2018-08-13 18:17:53 +00:00
|
|
|
} else if i == 1 {
|
2018-08-13 19:03:30 +00:00
|
|
|
p.name = mrand.Hex(1) + "=" + mrand.Hex(8)
|
2018-08-13 18:17:53 +00:00
|
|
|
} else {
|
2018-08-13 19:03:30 +00:00
|
|
|
p.name = mrand.Hex(8)
|
2018-08-13 18:17:53 +00:00
|
|
|
}
|
|
|
|
|
2018-08-13 19:03:30 +00:00
|
|
|
p.availCfgI = mrand.Intn(len(s.availCfgs))
|
|
|
|
thisCfg := s.availCfgs[p.availCfgI]
|
|
|
|
p.path = thisCfg.Path
|
2018-08-13 18:17:53 +00:00
|
|
|
|
2018-08-13 19:03:30 +00:00
|
|
|
p.isBool = mrand.Intn(2) == 0
|
|
|
|
if !p.isBool {
|
|
|
|
p.nonBoolType = mrand.Element([]string{
|
2018-08-13 18:17:53 +00:00
|
|
|
"int",
|
|
|
|
"str",
|
|
|
|
"duration",
|
|
|
|
"json",
|
|
|
|
}, nil).(string)
|
|
|
|
}
|
2018-08-13 19:03:30 +00:00
|
|
|
p.unset = mrand.Intn(10) == 0
|
2018-08-13 18:17:53 +00:00
|
|
|
|
2018-08-13 19:03:30 +00:00
|
|
|
if p.isBool || p.unset {
|
|
|
|
return mchk.Action{Params: p}
|
2018-08-13 18:17:53 +00:00
|
|
|
}
|
|
|
|
|
2018-08-13 19:03:30 +00:00
|
|
|
p.nonBoolWEq = mrand.Intn(2) == 0
|
|
|
|
switch p.nonBoolType {
|
2018-08-13 18:17:53 +00:00
|
|
|
case "int":
|
2018-08-13 19:03:30 +00:00
|
|
|
p.nonBoolVal = fmt.Sprint(mrand.Int())
|
2018-08-13 18:17:53 +00:00
|
|
|
case "str":
|
2018-08-13 19:03:30 +00:00
|
|
|
p.nonBoolVal = mrand.Hex(16)
|
2018-08-13 18:17:53 +00:00
|
|
|
case "duration":
|
|
|
|
dur := time.Duration(mrand.Intn(86400)) * time.Second
|
2018-08-13 19:03:30 +00:00
|
|
|
p.nonBoolVal = dur.String()
|
2018-08-13 18:17:53 +00:00
|
|
|
case "json":
|
|
|
|
b, _ := json.Marshal(map[string]int{
|
|
|
|
mrand.Hex(4): mrand.Int(),
|
|
|
|
mrand.Hex(4): mrand.Int(),
|
|
|
|
mrand.Hex(4): mrand.Int(),
|
|
|
|
})
|
2018-08-13 19:03:30 +00:00
|
|
|
p.nonBoolVal = string(b)
|
|
|
|
}
|
|
|
|
return mchk.Action{Params: p}
|
|
|
|
},
|
|
|
|
Apply: func(ss mchk.State, a mchk.Action) (mchk.State, error) {
|
|
|
|
s := ss.(state)
|
|
|
|
p := a.Params.(params)
|
|
|
|
|
|
|
|
// the param needs to get added to its cfg as a Param
|
|
|
|
thisCfg := s.availCfgs[p.availCfgI]
|
|
|
|
cfgP := Param{
|
|
|
|
Name: p.name,
|
|
|
|
IsString: p.nonBoolType == "str" || p.nonBoolType == "duration",
|
|
|
|
IsBool: p.isBool,
|
|
|
|
// the cli parser doesn't actually care about the other fields of Param,
|
|
|
|
// those are only used by Cfg once it has all ParamValues together
|
|
|
|
}
|
|
|
|
thisCfg.ParamAdd(cfgP)
|
|
|
|
|
|
|
|
// if the arg is set then add it to the cli args and the expected output pvs
|
|
|
|
if !p.unset {
|
|
|
|
arg := cliKeyPrefix
|
|
|
|
if len(p.path) > 0 {
|
|
|
|
arg += strings.Join(p.path, cliKeyJoin) + cliKeyJoin
|
|
|
|
}
|
|
|
|
arg += p.name
|
|
|
|
if !p.isBool {
|
|
|
|
if p.nonBoolWEq {
|
|
|
|
arg += "="
|
|
|
|
} else {
|
|
|
|
s.SourceCLI.Args = append(s.SourceCLI.Args, arg)
|
|
|
|
arg = ""
|
|
|
|
}
|
|
|
|
arg += p.nonBoolVal
|
|
|
|
}
|
|
|
|
s.SourceCLI.Args = append(s.SourceCLI.Args, arg)
|
|
|
|
|
|
|
|
pv := ParamValue{
|
|
|
|
Param: cfgP,
|
|
|
|
Path: p.path,
|
|
|
|
}
|
|
|
|
if p.isBool {
|
|
|
|
pv.Value = json.RawMessage("true")
|
|
|
|
} else {
|
|
|
|
switch p.nonBoolType {
|
|
|
|
case "str", "duration":
|
|
|
|
pv.Value = json.RawMessage(fmt.Sprintf("%q", p.nonBoolVal))
|
|
|
|
case "int", "json":
|
|
|
|
pv.Value = json.RawMessage(p.nonBoolVal)
|
|
|
|
default:
|
|
|
|
panic("shouldn't get here")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s.expPVs = append(s.expPVs, pv)
|
|
|
|
}
|
|
|
|
|
|
|
|
// and finally the state needs to be checked
|
|
|
|
gotPVs, err := s.SourceCLI.Parse(s.cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2018-08-13 18:17:53 +00:00
|
|
|
}
|
2018-08-13 19:03:30 +00:00
|
|
|
return s, massert.All(
|
|
|
|
massert.Len(gotPVs, len(s.expPVs)),
|
|
|
|
massert.Subset(s.expPVs, gotPVs),
|
|
|
|
).Assert()
|
2018-08-13 18:17:53 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2018-08-13 19:03:30 +00:00
|
|
|
if err := chk.RunFor(5 * time.Second); err != nil {
|
2018-08-13 18:17:53 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|