55package query
66
77import (
8+ "errors"
89 "fmt"
910 "net/url"
1011 "reflect"
@@ -230,12 +231,12 @@ func TestValues_NestedTypes(t *testing.T) {
230231 }{
231232 Nested {
232233 A : SubNested {
233- Value : "that " ,
234+ Value : "v " ,
234235 },
235236 },
236237 },
237238 url.Values {
238- "nest[a][value]" : {"that " },
239+ "nest[a][value]" : {"v " },
239240 "nest[b]" : {"" },
240241 },
241242 },
@@ -245,14 +246,14 @@ func TestValues_NestedTypes(t *testing.T) {
245246 }{
246247 Nested {
247248 Ptr : & SubNested {
248- Value : "that " ,
249+ Value : "v " ,
249250 },
250251 },
251252 },
252253 url.Values {
253254 "nest[a][value]" : {"" },
254255 "nest[b]" : {"" },
255- "nest[ptr][value]" : {"that " },
256+ "nest[ptr][value]" : {"v " },
256257 },
257258 },
258259 {
@@ -266,132 +267,178 @@ func TestValues_NestedTypes(t *testing.T) {
266267 }
267268}
268269
269- func TestValues_omitEmpty (t * testing.T ) {
270+ func TestValues_OmitEmpty (t * testing.T ) {
270271 str := ""
271- s := struct {
272- a string
273- A string
274- B string `url:",omitempty"`
275- C string `url:"-"`
276- D string `url:"omitempty"` // actually named omitempty, not an option
277- E * string `url:",omitempty"`
278- }{E : & str }
279-
280- v , err := Values (s )
281- if err != nil {
282- t .Errorf ("Values(%v) returned error: %v" , s , err )
283- }
284272
285- want := url.Values {
286- "A" : {"" },
287- "omitempty" : {"" },
288- "E" : {"" }, // E is included because the pointer is not empty, even though the string being pointed to is
289- }
290- if ! reflect .DeepEqual (want , v ) {
291- t .Errorf ("Values(%v) returned %v, want %v" , s , v , want )
273+ tests := []struct {
274+ input interface {}
275+ want url.Values
276+ }{
277+ {struct { v string }{}, url.Values {}}, // non-exported field
278+ {
279+ struct {
280+ V string `url:",omitempty"`
281+ }{},
282+ url.Values {},
283+ },
284+ {
285+ struct {
286+ V string `url:"-"`
287+ }{},
288+ url.Values {},
289+ },
290+ {
291+ struct {
292+ V string `url:"omitempty"` // actually named omitempty
293+ }{},
294+ url.Values {"omitempty" : {"" }},
295+ },
296+ {
297+ // include value for a non-nil pointer to an empty value
298+ struct {
299+ V * string `url:",omitempty"`
300+ }{& str },
301+ url.Values {"V" : {"" }},
302+ },
292303 }
293- }
294-
295- type A struct {
296- B
297- }
298304
299- type B struct {
300- C string
301- }
302-
303- type D struct {
304- B
305- C string
306- }
307-
308- type e struct {
309- B
310- C string
305+ for _ , tt := range tests {
306+ testValue (t , tt .input , tt .want )
307+ }
311308}
312309
313- type F struct {
314- e
315- }
310+ func TestValues_EmbeddedStructs (t * testing.T ) {
311+ type Inner struct {
312+ V string
313+ }
314+ type Outer struct {
315+ Inner
316+ }
317+ type Mixed struct {
318+ Inner
319+ V string
320+ }
321+ type unexported struct {
322+ Inner
323+ V string
324+ }
325+ type Exported struct {
326+ unexported
327+ }
316328
317- func TestValues_embeddedStructs (t * testing.T ) {
318329 tests := []struct {
319- in interface {}
320- want url.Values
330+ input interface {}
331+ want url.Values
321332 }{
322333 {
323- A { B { C : "foo " }},
324- url.Values {"C " : {"foo " }},
334+ Outer { Inner { V : "a " }},
335+ url.Values {"V " : {"a " }},
325336 },
326337 {
327- D { B : B { C : "bar " }, C : "foo " },
328- url.Values {"C " : {"foo " , "bar " }},
338+ Mixed { Inner : Inner { V : "a " }, V : "b " },
339+ url.Values {"V " : {"b " , "a " }},
329340 },
330341 {
331- F {e {B : B {C : "bar" }, C : "foo" }}, // With unexported embed
332- url.Values {"C" : {"foo" , "bar" }},
342+ // values from unexported embed are still included
343+ Exported {
344+ unexported {
345+ Inner : Inner {V : "bar" },
346+ V : "foo" ,
347+ },
348+ },
349+ url.Values {"V" : {"foo" , "bar" }},
333350 },
334351 }
335352
336- for i , tt := range tests {
337- v , err := Values (tt .in )
338- if err != nil {
339- t .Errorf ("%d. Values(%q) returned error: %v" , i , tt .in , err )
340- }
341-
342- if ! reflect .DeepEqual (tt .want , v ) {
343- t .Errorf ("%d. Values(%q) returned %v, want %v" , i , tt .in , v , tt .want )
344- }
353+ for _ , tt := range tests {
354+ testValue (t , tt .input , tt .want )
345355 }
346356}
347357
348- func TestValues_invalidInput (t * testing.T ) {
358+ func TestValues_InvalidInput (t * testing.T ) {
349359 _ , err := Values ("" )
350360 if err == nil {
351361 t .Errorf ("expected Values() to return an error on invalid input" )
352362 }
353363}
354364
355- type EncodedArgs []string
365+ // customEncodedStrings is a slice of strings with a custom URL encoding
366+ type customEncodedStrings []string
356367
357- func (m EncodedArgs ) EncodeValues (key string , v * url.Values ) error {
368+ // EncodeValues using key name of the form "{key}.N" where N increments with
369+ // each value. A value of "err" will return an error.
370+ func (m customEncodedStrings ) EncodeValues (key string , v * url.Values ) error {
358371 for i , arg := range m {
372+ if arg == "err" {
373+ return errors .New ("encoding error" )
374+ }
359375 v .Set (fmt .Sprintf ("%s.%d" , key , i ), arg )
360376 }
361377 return nil
362378}
363379
364- func TestValues_Marshaler (t * testing.T ) {
365- s := struct {
366- Args EncodedArgs `url:"arg"`
367- }{[]string {"a" , "b" , "c" }}
368- v , err := Values (s )
369- if err != nil {
370- t .Errorf ("Values(%q) returned error: %v" , s , err )
371- }
380+ func TestValues_CustomEncoding (t * testing.T ) {
381+ tests := []struct {
382+ input interface {}
383+ want url.Values
384+ }{
385+ {
386+ struct {
387+ V customEncodedStrings `url:"v"`
388+ }{},
389+ url.Values {},
390+ },
391+ {
392+ struct {
393+ V customEncodedStrings `url:"v"`
394+ }{[]string {"a" , "b" }},
395+ url.Values {"v.0" : {"a" }, "v.1" : {"b" }},
396+ },
372397
373- want := url.Values {
374- "arg.0" : {"a" },
375- "arg.1" : {"b" },
376- "arg.2" : {"c" },
398+ // pointers to custom encoded types
399+ {
400+ struct {
401+ V * customEncodedStrings `url:"v"`
402+ }{},
403+ url.Values {},
404+ },
405+ {
406+ struct {
407+ V * customEncodedStrings `url:"v"`
408+ }{(* customEncodedStrings )(& []string {"a" , "b" })},
409+ url.Values {"v.0" : {"a" }, "v.1" : {"b" }},
410+ },
377411 }
378- if ! reflect .DeepEqual (want , v ) {
379- t .Errorf ("Values(%q) returned %v, want %v" , s , v , want )
412+
413+ for _ , tt := range tests {
414+ testValue (t , tt .input , tt .want )
380415 }
381416}
382417
383- func TestValues_MarshalerWithNilPointer (t * testing.T ) {
384- s := struct {
385- Args * EncodedArgs `url:"arg"`
386- }{}
387- v , err := Values (s )
388- if err != nil {
389- t .Errorf ("Values(%v) returned error: %v" , s , err )
418+ // One of the few ways reflectValues will return an error is if a custom
419+ // encoder returns an error. Test all of the various ways that can happen.
420+ func TestValues_CustomEncoding_Error (t * testing.T ) {
421+ type st struct {
422+ V customEncodedStrings
390423 }
391-
392- want := url.Values {}
393- if ! reflect .DeepEqual (want , v ) {
394- t .Errorf ("Values(%v) returned %v, want %v" , s , v , want )
424+ tests := []struct {
425+ input interface {}
426+ }{
427+ {
428+ st {[]string {"err" }},
429+ },
430+ { // struct field
431+ struct { S st }{st {[]string {"err" }}},
432+ },
433+ { // embedded struct
434+ struct { st }{st {[]string {"err" }}},
435+ },
436+ }
437+ for _ , tt := range tests {
438+ _ , err := Values (tt .input )
439+ if err == nil {
440+ t .Errorf ("Values(%q) did not return expected encoding error" , tt .input )
441+ }
395442 }
396443}
397444
0 commit comments