1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
package mybase
import (
"bytes"
"testing"
"unicode"
)
// This file contains exported methods and types that may be useful in testing
// applications using MyBase, as well as testing MyBase itself.
// AssertFileSetsOptions verifies that the file sets all of the supplied option
// names in at least one of its currently-selected sections. The test fails if
// not.
func AssertFileSetsOptions(t *testing.T, file *File, options ...string) {
t.Helper()
for _, option := range options {
if _, setsOption := file.OptionValue(option); !setsOption {
t.Errorf("Expected %s to set option %s, but it does not", file, option)
}
}
}
// AssertFileMissingOptions verifies that the file does NOT set any of the
// supplied option names in any of its currently-selected sections. The test
// fails otherwise.
func AssertFileMissingOptions(t *testing.T, file *File, options ...string) {
t.Helper()
for _, option := range options {
if _, setsOption := file.OptionValue(option); setsOption {
t.Errorf("Expected %s to NOT contain %s, but it does", file, option)
}
}
}
// SimpleSource is the most trivial possible implementation of the OptionValuer
// interface: it just maps option name strings to option value strings.
type SimpleSource = StringMapValues
// SimpleConfig returns a stub config based on a single map of key->value string
// pairs. All keys in the map will automatically be considered valid options.
func SimpleConfig(values map[string]string) *Config {
cmd := NewCommand("test", "1.0", "this is for testing", nil)
for key := range values {
cmd.AddOption(StringOption(key, 0, "", key))
}
cli := &CommandLine{
Command: cmd,
}
return NewConfig(cli, SimpleSource(values))
}
// ParseFakeCLI splits a single command-line string into a slice of arg
// token strings, and then calls ParseCLI using those args. It understands
// simple quoting and escaping rules, but does not attempt to replicate more
// advanced bash tokenization, wildcards, etc.
func ParseFakeCLI(t *testing.T, cmd *Command, commandLine string, sources ...OptionValuer) *Config {
t.Helper()
args := tokenizeCommandLine(t, commandLine)
cfg, err := ParseCLI(cmd, args)
if err != nil {
t.Fatalf("ParseCLI returned unexpected error: %s", err)
}
for _, src := range sources {
cfg.AddSource(src)
}
cfg.IsTest = true
return cfg
}
func tokenizeCommandLine(t *testing.T, commandLine string) []string {
t.Helper()
var b bytes.Buffer
var inQuote, escapeNext bool
var curQuote rune
var args []string
for _, c := range commandLine {
if escapeNext {
b.WriteRune(c)
escapeNext = false
continue
}
switch {
case c == '\\':
escapeNext = true
case c == '\'' || c == '"':
if !inQuote {
inQuote = true
curQuote = c
} else if curQuote == c {
inQuote = false
} else { // in a quote, but a different type
b.WriteRune(c)
}
case unicode.IsSpace(c):
if inQuote {
b.WriteRune(c)
} else if b.Len() > 0 {
args = append(args, b.String())
b.Reset()
}
default:
b.WriteRune(c)
}
}
if inQuote || escapeNext {
t.Fatalf("Invalid command-line passed to tokenizeCommandLine(\"%s\"): final inQuote=%t, escapeNext=%t", commandLine, inQuote, escapeNext)
}
if b.Len() > 0 {
args = append(args, b.String())
}
return args
}
|