1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package middleware
16
17 import (
18 "math"
19 "net/url"
20 "reflect"
21 "strconv"
22 "testing"
23
24 "github.com/go-openapi/errors"
25 "github.com/go-openapi/spec"
26 "github.com/go-openapi/strfmt"
27 "github.com/stretchr/testify/assert"
28 "github.com/stretchr/testify/require"
29
30 "github.com/go-openapi/runtime"
31 )
32
33 type paramFactory func(string) *spec.Parameter
34
35 var paramFactories = []paramFactory{
36 spec.QueryParam,
37 spec.HeaderParam,
38 spec.PathParam,
39 spec.FormDataParam,
40 }
41
42 func np(param *spec.Parameter) *untypedParamBinder {
43 return newUntypedParamBinder(*param, new(spec.Swagger), strfmt.Default)
44 }
45
46 var stringItems = new(spec.Items)
47
48 func init() {
49 stringItems.Type = typeString
50 }
51
52 func testCollectionFormat(t *testing.T, param *spec.Parameter, valid bool) {
53 binder := &untypedParamBinder{
54 parameter: param,
55 }
56 _, _, _, err := binder.readValue(runtime.Values(nil), reflect.ValueOf(nil))
57 if valid {
58 require.NoError(t, err)
59 } else {
60 require.Error(t, err)
61 require.EqualError(t, err, errors.InvalidCollectionFormat(param.Name, param.In, param.CollectionFormat).Error())
62 }
63 }
64
65 func requiredError(param *spec.Parameter, data interface{}) *errors.Validation {
66 return errors.Required(param.Name, param.In, data)
67 }
68
69 func validateRequiredTest(t *testing.T, param *spec.Parameter, value reflect.Value) {
70 binder := np(param)
71
72 err := binder.bindValue([]string{}, true, value)
73 require.Error(t, err)
74 assert.NotNil(t, param)
75 require.EqualError(t, requiredError(param, value.Interface()), err.Error())
76
77 err = binder.bindValue([]string{""}, true, value)
78 require.Error(t, err)
79 require.EqualError(t, requiredError(param, value.Interface()), err.Error())
80
81
82 err = binder.bindValue([]string{"a"}, false, value)
83 require.Error(t, err)
84 require.EqualError(t, err, requiredError(param, value.Interface()).Error())
85
86 err = binder.bindValue([]string{""}, false, value)
87 require.Error(t, err)
88 require.EqualError(t, requiredError(param, value.Interface()), err.Error())
89 }
90
91 func validateRequiredAllowEmptyTest(t *testing.T, param *spec.Parameter, value reflect.Value) {
92 param.AllowEmptyValue = true
93 binder := np(param)
94 err := binder.bindValue([]string{}, true, value)
95 require.NoError(t, err)
96 require.NotNil(t, param)
97
98 err = binder.bindValue([]string{""}, true, value)
99 require.NoError(t, err)
100
101 err = binder.bindValue([]string{"1"}, false, value)
102 require.Error(t, err)
103 require.EqualError(t, requiredError(param, value.Interface()), err.Error())
104
105 err = binder.bindValue([]string{""}, false, value)
106 require.Error(t, err)
107 require.EqualError(t, requiredError(param, value.Interface()), err.Error())
108 }
109
110 func TestRequiredValidation(t *testing.T) {
111 strParam := spec.QueryParam("name").Typed(typeString, "").AsRequired()
112 validateRequiredTest(t, strParam, reflect.ValueOf(""))
113 validateRequiredAllowEmptyTest(t, strParam, reflect.ValueOf(""))
114
115 intParam := spec.QueryParam("id").Typed("integer", "int32").AsRequired()
116 validateRequiredTest(t, intParam, reflect.ValueOf(int32(0)))
117 validateRequiredAllowEmptyTest(t, intParam, reflect.ValueOf(int32(0)))
118 longParam := spec.QueryParam("id").Typed("integer", "int64").AsRequired()
119 validateRequiredTest(t, longParam, reflect.ValueOf(int64(0)))
120 validateRequiredAllowEmptyTest(t, longParam, reflect.ValueOf(int64(0)))
121
122 floatParam := spec.QueryParam("score").Typed("number", "float").AsRequired()
123 validateRequiredTest(t, floatParam, reflect.ValueOf(float32(0)))
124 validateRequiredAllowEmptyTest(t, floatParam, reflect.ValueOf(float32(0)))
125 doubleParam := spec.QueryParam("score").Typed("number", "double").AsRequired()
126 validateRequiredTest(t, doubleParam, reflect.ValueOf(float64(0)))
127 validateRequiredAllowEmptyTest(t, doubleParam, reflect.ValueOf(float64(0)))
128
129 dateTimeParam := spec.QueryParam("registered").Typed(typeString, "date-time").AsRequired()
130 validateRequiredTest(t, dateTimeParam, reflect.ValueOf(strfmt.DateTime{}))
131
132
133 dateParam := spec.QueryParam("registered").Typed(typeString, "date").AsRequired()
134 validateRequiredTest(t, dateParam, reflect.ValueOf(strfmt.Date{}))
135
136
137 sliceParam := spec.QueryParam("tags").CollectionOf(stringItems, "").AsRequired()
138 validateRequiredTest(t, sliceParam, reflect.MakeSlice(reflect.TypeOf([]string{}), 0, 0))
139 validateRequiredAllowEmptyTest(t, sliceParam, reflect.MakeSlice(reflect.TypeOf([]string{}), 0, 0))
140 }
141
142 func TestInvalidCollectionFormat(t *testing.T) {
143 validCf1 := spec.QueryParam("validFmt").CollectionOf(stringItems, "multi")
144 validCf2 := spec.FormDataParam("validFmt2").CollectionOf(stringItems, "multi")
145 invalidCf1 := spec.HeaderParam("invalidHdr").CollectionOf(stringItems, "multi")
146 invalidCf2 := spec.PathParam("invalidPath").CollectionOf(stringItems, "multi")
147
148 testCollectionFormat(t, validCf1, true)
149 testCollectionFormat(t, validCf2, true)
150 testCollectionFormat(t, invalidCf1, false)
151 testCollectionFormat(t, invalidCf2, false)
152 }
153
154 func invalidTypeError(param *spec.Parameter, data interface{}) *errors.Validation {
155 tpe := param.Type
156 if param.Format != "" {
157 tpe = param.Format
158 }
159 return errors.InvalidType(param.Name, param.In, tpe, data)
160 }
161
162 func TestTypeValidation(t *testing.T) {
163 for _, newParam := range paramFactories {
164 intParam := newParam("badInt").Typed("integer", "int32")
165 value := reflect.ValueOf(int32(0))
166 binder := np(intParam)
167 err := binder.bindValue([]string{"yada"}, true, value)
168
169 require.Error(t, err)
170 require.EqualError(t, err, invalidTypeError(intParam, "yada").Error())
171
172
173 val := int64(math.MaxInt32)
174 str := strconv.FormatInt(val, 10) + "0"
175 v := int32(0)
176 value = reflect.ValueOf(&v).Elem()
177
178 binder = np(intParam)
179 err = binder.bindValue([]string{str}, true, value)
180 require.Error(t, err)
181 require.EqualError(t, err, invalidTypeError(intParam, str).Error())
182
183
184 longParam := newParam("badLong").Typed("integer", "int64")
185 value = reflect.ValueOf(int64(0))
186
187 binder = np(longParam)
188 err = binder.bindValue([]string{"yada"}, true, value)
189 require.Error(t, err)
190 require.EqualError(t, err, invalidTypeError(longParam, "yada").Error())
191
192
193 str2 := strconv.FormatInt(math.MaxInt64, 10) + "0"
194 v2 := int64(0)
195 vv2 := reflect.ValueOf(&v2).Elem()
196 binder = np(longParam)
197 err = binder.bindValue([]string{str2}, true, vv2)
198 require.Error(t, err)
199 require.EqualError(t, err, invalidTypeError(longParam, str2).Error())
200
201
202 floatParam := newParam("badFloat").Typed("number", "float")
203 value = reflect.ValueOf(float64(0))
204 binder = np(floatParam)
205 err = binder.bindValue([]string{"yada"}, true, value)
206 require.Error(t, err)
207 require.EqualError(t, err, invalidTypeError(floatParam, "yada").Error())
208
209
210 str3 := strconv.FormatFloat(math.MaxFloat64, 'f', 5, 64)
211 v3 := reflect.TypeOf(float32(0))
212 value = reflect.New(v3).Elem()
213 binder = np(floatParam)
214 err = binder.bindValue([]string{str3}, true, value)
215 require.Error(t, err)
216 require.EqualError(t, err, invalidTypeError(floatParam, str3).Error())
217
218
219 doubleParam := newParam("badDouble").Typed("number", "double")
220 value = reflect.ValueOf(float64(0))
221 binder = np(doubleParam)
222 err = binder.bindValue([]string{"yada"}, true, value)
223 require.Error(t, err)
224 require.EqualError(t, err, invalidTypeError(doubleParam, "yada").Error())
225
226
227 str4 := "9" + strconv.FormatFloat(math.MaxFloat64, 'f', 5, 64)
228 v4 := reflect.TypeOf(float64(0))
229 value = reflect.New(v4).Elem()
230 binder = np(doubleParam)
231 err = binder.bindValue([]string{str4}, true, value)
232 require.Error(t, err)
233 require.EqualError(t, err, invalidTypeError(doubleParam, str4).Error())
234
235
236 dateParam := newParam("badDate").Typed(typeString, "date")
237 value = reflect.ValueOf(strfmt.Date{})
238 binder = np(dateParam)
239 err = binder.bindValue([]string{"yada"}, true, value)
240 require.Error(t, err)
241 require.EqualError(t, err, invalidTypeError(dateParam, "yada").Error())
242
243
244 dateTimeParam := newParam("badDateTime").Typed(typeString, "date-time")
245 value = reflect.ValueOf(strfmt.DateTime{})
246 binder = np(dateTimeParam)
247 err = binder.bindValue([]string{"yada"}, true, value)
248 require.Error(t, err)
249 require.EqualError(t, err, invalidTypeError(dateTimeParam, "yada").Error())
250
251
252 byteParam := newParam("badByte").Typed(typeString, "byte")
253 values := url.Values(map[string][]string{})
254 values.Add("badByte", "yaüda")
255 v5 := []byte{}
256 value = reflect.ValueOf(&v5).Elem()
257 binder = np(byteParam)
258 err = binder.bindValue([]string{"yaüda"}, true, value)
259 require.Error(t, err)
260 require.EqualError(t, err, invalidTypeError(byteParam, "yaüda").Error())
261 }
262 }
263
264 func TestTypeDetectionInvalidItems(t *testing.T) {
265 withoutItems := spec.QueryParam("without").CollectionOf(nil, "")
266 binder := &untypedParamBinder{
267 Name: "without",
268 parameter: withoutItems,
269 }
270 assert.Nil(t, binder.Type())
271
272 items := new(spec.Items)
273 items.Type = typeArray
274 withInvalidItems := spec.QueryParam("invalidItems").CollectionOf(items, "")
275 binder = &untypedParamBinder{
276 Name: "invalidItems",
277 parameter: withInvalidItems,
278 }
279 assert.Nil(t, binder.Type())
280
281 noType := spec.QueryParam("invalidType")
282 noType.Type = "invalid"
283 binder = &untypedParamBinder{
284 Name: "invalidType",
285 parameter: noType,
286 }
287 assert.Nil(t, binder.Type())
288 }
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
View as plain text