-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathtesting.go
114 lines (105 loc) · 3.21 KB
/
testing.go
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
}