1 package commontest
2
3 import (
4 "fmt"
5 "strings"
6 )
7
8
9
10
11 type testFactory struct {
12 valueTestFactory ValueTestFactory
13 readErrorTestFactory ReadErrorTestFactory
14 encodingBehavior encodingBehavior
15 }
16
17
18 type testDef struct {
19
20 name string
21
22
23
24
25 encoding []string
26
27
28 action Action
29 }
30
31 type testDefs []testDef
32
33 func (td testDef) then(next testDef) testDef {
34 return testDef{
35 name: td.name + ", " + next.name,
36 encoding: append(td.encoding, next.encoding...),
37 action: func(ctx TestContext) error {
38 if err := td.action(ctx); err != nil {
39 return err
40 }
41 return next.action(ctx)
42 },
43 }
44 }
45
46 func (tds testDefs) then(next testDef) testDefs {
47 ret := make(testDefs, 0, len(tds))
48 for _, td := range tds {
49 ret = append(ret, td.then(next))
50 }
51 return ret
52 }
53
54 func (f testFactory) MakeAllValueTests() testDefs {
55 ret := testDefs{}
56 eofTest := testDef{name: "EOF", action: f.valueTestFactory.EOF()}
57 ret = append(ret, f.makeScalarValueTests(true).then(eofTest)...)
58 ret = append(ret, f.makeArrayTests().then(eofTest)...)
59 ret = append(ret, f.makeObjectTests().then(eofTest)...)
60 return ret
61 }
62
63 func maybeVariants(vs []ValueVariant) []ValueVariant {
64 if len(vs) == 0 {
65 return []ValueVariant{""}
66 }
67 return vs
68 }
69
70 func (f testFactory) MakeAllReadErrorTests() testDefs {
71 ret := testDefs{}
72 addErrors := func(tds testDefs) {
73 for _, td := range tds {
74 for i, enc := range td.encoding {
75 if enc == "" {
76 td.encoding = td.encoding[0:i]
77 break
78 }
79 }
80 ret = append(ret, td)
81 }
82 }
83 addErrors(f.makeScalarValueReadErrorTests())
84 return ret
85 }
86
87 func (f testFactory) makeScalarValueTests(allPermutations bool) testDefs {
88 ret := testDefs{}
89 values := f.makeScalarValues(allPermutations)
90 for _, tv := range values {
91 variants := maybeVariants(f.valueTestFactory.Variants(tv.value))
92 for _, variant := range variants {
93 name := tv.name
94 if variant != "" {
95 name = string(variant) + " " + name
96 }
97 td := testDef{
98 name: name,
99 encoding: []string{tv.encoding},
100 action: f.valueTestFactory.Value(tv.value, variant),
101 }
102 ret = append(ret, td)
103 }
104 }
105 return ret
106 }
107
108 func (f testFactory) makeScalarValueReadErrorTests() testDefs {
109 ret := testDefs{}
110 values := f.makeScalarValues(false)
111 oneVariant := []ValueVariant{""}
112 for _, testValue := range values {
113 tv := testValue
114 variants := f.valueTestFactory.Variants(tv.value)
115 if variants == nil {
116 variants = oneVariant
117 }
118 for _, variant := range variants {
119 v := variant
120 name := tv.name
121 if v != "" {
122 name = string(v) + " " + name
123 }
124 testAction := f.valueTestFactory.Value(tv.value, variant)
125
126
127 if v != UntypedVariant && v != SkipValueVariant {
128 for _, wrongValue := range f.makeScalarValues(false) {
129 wv := wrongValue
130 if wv.value.Kind == tv.value.Kind {
131 continue
132 }
133 ret = append(ret, testDef{
134 name: fmt.Sprintf("%s (but got %s)", name, wv.name),
135 encoding: []string{wv.encoding},
136 action: func(c TestContext) error {
137 return f.readErrorTestFactory.ExpectWrongTypeError(testAction(c), tv.value.Kind, v, wv.value.Kind)
138 },
139 })
140 }
141 if tv.value.Kind != NullValue {
142 ret = append(ret, testDef{
143 name: fmt.Sprintf("%s (but got array)", name),
144 encoding: []string{"[]"},
145 action: func(c TestContext) error {
146 return f.readErrorTestFactory.ExpectWrongTypeError(testAction(c), tv.value.Kind, v, ArrayValue)
147 },
148 })
149 ret = append(ret, testDef{
150 name: fmt.Sprintf("%s (but got object)", name),
151 encoding: []string{"{}"},
152 action: func(c TestContext) error {
153 return f.readErrorTestFactory.ExpectWrongTypeError(testAction(c), tv.value.Kind, v, ObjectValue)
154 },
155 })
156 }
157 }
158
159
160 for _, badThing := range []struct {
161 name string
162 encoding string
163 }{
164 {"invalid identifier", "bad"},
165 {"unknown delimiter", "+"},
166 {"unexpected end array", "]"},
167 {"unexpected object", "}"},
168 } {
169 ret = append(ret, testDef{
170 name: fmt.Sprintf("%s (but got %s)", name, badThing.name),
171 encoding: []string{badThing.encoding},
172 action: func(c TestContext) error {
173 return f.readErrorTestFactory.ExpectSyntaxError(testAction(c))
174 },
175 })
176 }
177 ret = append(ret, testDef{
178 name: fmt.Sprintf("%s (but got unexpected EOF)", name),
179 encoding: []string{""},
180 action: func(c TestContext) error {
181 return f.readErrorTestFactory.ExpectEOFError(testAction(c))
182 },
183 })
184 }
185 }
186 return ret
187 }
188
189 func (f testFactory) makeScalarValues(allPermutations bool) []testValue {
190 var values []testValue
191 values = append(values, testValue{
192 name: "null",
193 encoding: "null",
194 value: AnyValue{Kind: NullValue},
195 })
196 values = append(values, makeBoolTestValues()...)
197 values = append(values, makeNumberTestValues(f.encodingBehavior)...)
198 values = append(values, makeStringTestValues(f.encodingBehavior, allPermutations)...)
199 return values
200 }
201
202 func (f testFactory) makeArrayTests() testDefs {
203 ret := testDefs{}
204 for elementCount := 0; elementCount <= 2; elementCount++ {
205 for _, contents := range f.makeValueListsOfLength(elementCount) {
206 var names []string
207 var encoding = []string{"["}
208 var actions []Action
209 for i, td := range contents {
210 names = append(names, td.name)
211 if i > 0 {
212 encoding = append(encoding, ",")
213 }
214 encoding = append(encoding, td.encoding...)
215 actions = append(actions, td.action)
216 }
217 encoding = append(encoding, "]")
218 value := AnyValue{Kind: ArrayValue, Array: actions}
219 for _, variant := range maybeVariants(f.valueTestFactory.Variants(value)) {
220 arrayTest := testDef{
221 name: "array(" + strings.Join(names, ", ") + ")",
222 encoding: encoding,
223 action: f.valueTestFactory.Value(value, variant),
224 }
225 ret = append(ret, arrayTest)
226 }
227 }
228 }
229 return ret
230 }
231
232 func (f testFactory) makeObjectTests() testDefs {
233 ret := testDefs{}
234 for propertyCount := 0; propertyCount <= 2; propertyCount++ {
235 for _, contents := range f.makeValueListsOfLength(propertyCount) {
236 var names []string
237 var encoding = []string{"{"}
238 var propActions []PropertyAction
239 for i, td := range contents {
240 propName := fmt.Sprintf("prop%d", i)
241 names = append(names, fmt.Sprintf("%s: %s", propName, td.name))
242 if i > 0 {
243 encoding = append(encoding, ",")
244 }
245 encoding = append(encoding, fmt.Sprintf(`"%s"`, propName))
246 encoding = append(encoding, ":")
247 encoding = append(encoding, td.encoding...)
248 propActions = append(propActions, PropertyAction{Name: propName, Action: td.action})
249 }
250 encoding = append(encoding, "}")
251 value := AnyValue{Kind: ObjectValue, Object: propActions}
252 for _, variant := range maybeVariants(f.valueTestFactory.Variants(value)) {
253 objectTest := testDef{
254 name: "object(" + strings.Join(names, ", ") + ")",
255 encoding: encoding,
256 action: f.valueTestFactory.Value(value, variant),
257 }
258 ret = append(ret, objectTest)
259 }
260 }
261 }
262 return ret
263 }
264
265 func (f testFactory) makeValueListsOfLength(count int) []testDefs {
266 if count == 0 {
267 return []testDefs{testDefs{}}
268 }
269 previousLists := f.makeValueListsOfLength(count - 1)
270 ret := []testDefs{}
271 for _, previous := range previousLists {
272 for _, elementTest := range f.makeScalarValueTests(false) {
273 ret = append(ret, append(previous, elementTest))
274 }
275 }
276 return ret
277 }
278
View as plain text