1 package validator_test
2
3 import (
4 "io/ioutil"
5 "testing"
6
7 "encoding/json"
8
9 "github.com/stretchr/testify/require"
10 "github.com/vektah/gqlparser"
11 "github.com/vektah/gqlparser/ast"
12 "github.com/vektah/gqlparser/validator"
13 )
14
15 func TestValidateVars(t *testing.T) {
16 schema := gqlparser.MustLoadSchema(&ast.Source{
17 Name: "vars.graphql",
18 Input: mustReadFile("./testdata/vars.graphql"),
19 })
20
21 t.Run("undefined variable", func(t *testing.T) {
22 t.Run("without default", func(t *testing.T) {
23 q := gqlparser.MustLoadQuery(schema, `query($id: Int!) { intArg(i: $id) }`)
24 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
25 require.EqualError(t, gerr, "input: variable.id must be defined")
26 })
27
28 t.Run("nil in required value", func(t *testing.T) {
29 q := gqlparser.MustLoadQuery(schema, `query($id: Int!) { intArg(i: $id) }`)
30 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
31 "id": nil,
32 })
33 require.EqualError(t, gerr, "input: variable.id cannot be null")
34 })
35
36 t.Run("with default", func(t *testing.T) {
37 q := gqlparser.MustLoadQuery(schema, `query($id: Int! = 1) { intArg(i: $id) }`)
38 vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
39 require.Nil(t, gerr)
40 require.EqualValues(t, 1, vars["id"])
41 })
42
43 t.Run("with union", func(t *testing.T) {
44 q := gqlparser.MustLoadQuery(schema, `query($id: Int! = 1) { intArg(i: $id) }`)
45 vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
46 require.Nil(t, gerr)
47 require.EqualValues(t, 1, vars["id"])
48 })
49 })
50
51 t.Run("input object", func(t *testing.T) {
52 t.Run("non object", func(t *testing.T) {
53 q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
54 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
55 "var": "hello",
56 })
57 require.EqualError(t, gerr, "input: variable.var must be a InputType")
58 })
59
60 t.Run("defaults", func(t *testing.T) {
61 q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType! = {name: "foo"}) { structArg(i: $var) }`)
62 vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
63 require.Nil(t, gerr)
64 require.EqualValues(t, map[string]interface{}{"name": "foo"}, vars["var"])
65 })
66
67 t.Run("valid value", func(t *testing.T) {
68 q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
69 vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
70 "var": map[string]interface{}{
71 "name": "foobar",
72 },
73 })
74 require.Nil(t, gerr)
75 require.EqualValues(t, map[string]interface{}{"name": "foobar"}, vars["var"])
76 })
77
78 t.Run("null object field", func(t *testing.T) {
79 q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
80 vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
81 "var": map[string]interface{}{
82 "name": "foobar",
83 "nullName": nil,
84 },
85 })
86 require.Nil(t, gerr)
87 require.EqualValues(t, map[string]interface{}{"name": "foobar", "nullName": nil}, vars["var"])
88 })
89
90 t.Run("missing required values", func(t *testing.T) {
91 q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
92 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
93 "var": map[string]interface{}{},
94 })
95 require.EqualError(t, gerr, "input: variable.var.name must be defined")
96 })
97
98 t.Run("null required field", func(t *testing.T) {
99 q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
100 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
101 "var": map[string]interface{}{
102 "name": nil,
103 },
104 })
105 require.EqualError(t, gerr, "input: variable.var.name cannot be null")
106 })
107
108 t.Run("null embedded input object", func(t *testing.T) {
109 q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
110 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
111 "var": map[string]interface{}{
112 "name": "foo",
113 "nullEmbedded": nil,
114 },
115 })
116 require.Nil(t, gerr)
117 })
118
119 t.Run("unknown field", func(t *testing.T) {
120 q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
121 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
122 "var": map[string]interface{}{
123 "name": "foobar",
124 "foobard": true,
125 },
126 })
127 require.EqualError(t, gerr, "input: variable.var.foobard unknown field")
128 })
129
130 t.Run("enum input object", func(t *testing.T) {
131 q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
132 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
133 "var": map[string]interface{}{
134 "name": "foobar",
135 "enum": "A",
136 },
137 })
138 require.Nil(t, gerr)
139 })
140
141 t.Run("unknown enum value input object", func(t *testing.T) {
142 q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
143 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
144 "var": map[string]interface{}{
145 "name": "foobar",
146 "enum": "B",
147 },
148 })
149 require.EqualError(t, gerr, "input: variable.var.enum B is not a valid Enum")
150 })
151 })
152
153 t.Run("array", func(t *testing.T) {
154 t.Run("non array", func(t *testing.T) {
155 q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`)
156 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
157 "var": "hello",
158 })
159 require.EqualError(t, gerr, "input: variable.var must be an array")
160 })
161
162 t.Run("defaults", func(t *testing.T) {
163 q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!] = [{name: "foo"}]) { arrayArg(i: $var) }`)
164 vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
165 require.Nil(t, gerr)
166 require.EqualValues(t, []interface{}{map[string]interface{}{
167 "name": "foo",
168 }}, vars["var"])
169 })
170
171 t.Run("valid value", func(t *testing.T) {
172 q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`)
173 vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
174 "var": []interface{}{map[string]interface{}{
175 "name": "foo",
176 }},
177 })
178 require.Nil(t, gerr)
179 require.EqualValues(t, []interface{}{map[string]interface{}{
180 "name": "foo",
181 }}, vars["var"])
182 })
183
184 t.Run("null element value", func(t *testing.T) {
185 q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`)
186 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
187 "var": []interface{}{nil},
188 })
189 require.EqualError(t, gerr, "input: variable.var[0] cannot be null")
190 })
191
192 t.Run("missing required values", func(t *testing.T) {
193 q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`)
194 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
195 "var": []interface{}{map[string]interface{}{}},
196 })
197 require.EqualError(t, gerr, "input: variable.var[0].name must be defined")
198 })
199 t.Run("invalid variable paths", func(t *testing.T) {
200 q := gqlparser.MustLoadQuery(schema, `query foo($var1: InputType!, $var2: InputType!) { a:structArg(i: $var1) b:structArg(i: $var2) }`)
201 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
202 "var1": map[string]interface{}{
203 "name": "foobar",
204 },
205 "var2": map[string]interface{}{
206 "nullName": "foobar",
207 },
208 })
209 require.EqualError(t, gerr, "input: variable.var2.name must be defined")
210 })
211 })
212
213 t.Run("Scalars", func(t *testing.T) {
214 t.Run("String -> String", func(t *testing.T) {
215 q := gqlparser.MustLoadQuery(schema, `query foo($var: String!) { stringArg(i: $var) }`)
216 vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
217 "var": "asdf",
218 })
219 require.Nil(t, gerr)
220 require.EqualValues(t, "asdf", vars["var"])
221 })
222
223 t.Run("Int -> String", func(t *testing.T) {
224 q := gqlparser.MustLoadQuery(schema, `query foo($var: String!) { stringArg(i: $var) }`)
225 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
226 "var": 1,
227 })
228 require.EqualError(t, gerr, "input: variable.var cannot use int as String")
229 })
230
231 t.Run("Nil -> String", func(t *testing.T) {
232 q := gqlparser.MustLoadQuery(schema, `query foo($var: String!) { stringArg(i: $var) }`)
233 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
234 "var": nil,
235 })
236 require.EqualError(t, gerr, "input: variable.var cannot be null")
237 })
238
239 t.Run("Undefined -> String!", func(t *testing.T) {
240 q := gqlparser.MustLoadQuery(schema, `query foo($var: String!) { stringArg(i: $var) }`)
241 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
242 require.EqualError(t, gerr, "input: variable.var must be defined")
243 })
244
245 t.Run("Undefined -> Int", func(t *testing.T) {
246 q := gqlparser.MustLoadQuery(schema, `query foo($var: Int) { optionalIntArg(i: $var) }`)
247 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
248 require.Nil(t, gerr)
249 })
250
251 t.Run("Json Number -> Int", func(t *testing.T) {
252 q := gqlparser.MustLoadQuery(schema, `query foo($var: Int) { optionalIntArg(i: $var) }`)
253 vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
254 "var": json.Number("10"),
255 })
256 require.Nil(t, gerr)
257 require.Equal(t, json.Number("10"), vars["var"])
258 })
259
260 t.Run("Nil -> Int", func(t *testing.T) {
261 q := gqlparser.MustLoadQuery(schema, `query foo($var: Int) { optionalIntArg(i: $var) }`)
262 vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
263 "var": nil,
264 })
265 require.Nil(t, gerr)
266 require.Equal(t, nil, vars["var"])
267 })
268
269 t.Run("Bool -> Int", func(t *testing.T) {
270 q := gqlparser.MustLoadQuery(schema, `query foo($var: Int!) { intArg(i: $var) }`)
271 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
272 "var": true,
273 })
274 require.EqualError(t, gerr, "input: variable.var cannot use bool as Int")
275 })
276 })
277
278 t.Run("Int Array", func(t *testing.T) {
279 t.Run("Array with null", func(t *testing.T) {
280 q := gqlparser.MustLoadQuery(schema, `query foo($var: [Int]) { intArrayArg(i: $var) }`)
281 a := 1
282 b := 2
283
284 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
285 "var": []*int{&a, &b, nil},
286 })
287 require.Nil(t, gerr)
288 })
289 })
290
291 t.Run("String Array", func(t *testing.T) {
292 t.Run("Array with null", func(t *testing.T) {
293 q := gqlparser.MustLoadQuery(schema, `query foo($var: [String]) { stringArrayArg(i: $var) }`)
294 a := "1"
295 b := "2"
296
297 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
298 "var": []*string{&a, &b, nil},
299 })
300 require.Nil(t, gerr)
301 })
302 })
303
304 t.Run("Boolean Array", func(t *testing.T) {
305 t.Run("Array with null", func(t *testing.T) {
306 q := gqlparser.MustLoadQuery(schema, `query foo($var: [Boolean]) { boolArrayArg(i: $var) }`)
307 a := true
308 b := false
309
310 _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
311 "var": []*bool{&a, &b, nil},
312 })
313 require.Nil(t, gerr)
314 })
315 })
316 }
317
318 func mustReadFile(name string) string {
319 src, err := ioutil.ReadFile(name)
320 if err != nil {
321 panic(err)
322 }
323
324 return string(src)
325 }
326
View as plain text