1
2
3
4
5 package gensupport
6
7 import (
8 "encoding/json"
9 "reflect"
10 "testing"
11
12 "google.golang.org/api/googleapi"
13 )
14
15 type CustomType struct {
16 Foo string `json:"foo,omitempty"`
17 }
18
19 type schema struct {
20
21 B bool `json:"b,omitempty"`
22 F float64 `json:"f,omitempty"`
23 I int64 `json:"i,omitempty"`
24 Istr int64 `json:"istr,omitempty,string"`
25 Str string `json:"str,omitempty"`
26
27
28 PB *bool `json:"pb,omitempty"`
29 PF *float64 `json:"pf,omitempty"`
30 PI *int64 `json:"pi,omitempty"`
31 PIStr *int64 `json:"pistr,omitempty,string"`
32 PStr *string `json:"pstr,omitempty"`
33
34
35 Int64s googleapi.Int64s `json:"i64s,omitempty"`
36 S []int `json:"s,omitempty"`
37 M map[string]string `json:"m,omitempty"`
38 Any interface{} `json:"any,omitempty"`
39 Child *child `json:"child,omitempty"`
40 MapToAnyArray map[string][]interface{} `json:"maptoanyarray,omitempty"`
41 MapToCustomType map[string]CustomType `json:"maptocustomtype,omitempty"`
42
43 ForceSendFields []string `json:"-"`
44 NullFields []string `json:"-"`
45 }
46
47 type child struct {
48 B bool `json:"childbool,omitempty"`
49 }
50
51 type testCase struct {
52 s schema
53 want string
54 }
55
56 func TestBasics(t *testing.T) {
57 for _, tc := range []testCase{
58 {
59 s: schema{},
60 want: `{}`,
61 },
62 {
63 s: schema{
64 ForceSendFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"},
65 },
66 want: `{"b":false,"f":0.0,"i":0,"istr":"0","str":""}`,
67 },
68 {
69 s: schema{
70 NullFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"},
71 },
72 want: `{"b":null,"f":null,"i":null,"istr":null,"str":null,"pb":null,"pf":null,"pi":null,"pistr":null,"pstr":null}`,
73 },
74 {
75 s: schema{
76 B: true,
77 F: 1.2,
78 I: 1,
79 Istr: 2,
80 Str: "a",
81 PB: googleapi.Bool(true),
82 PF: googleapi.Float64(1.2),
83 PI: googleapi.Int64(int64(1)),
84 PIStr: googleapi.Int64(int64(2)),
85 PStr: googleapi.String("a"),
86 },
87 want: `{"b":true,"f":1.2,"i":1,"istr":"2","str":"a","pb":true,"pf":1.2,"pi":1,"pistr":"2","pstr":"a"}`,
88 },
89 {
90 s: schema{
91 B: false,
92 F: 0.0,
93 I: 0,
94 Istr: 0,
95 Str: "",
96 PB: googleapi.Bool(false),
97 PF: googleapi.Float64(0.0),
98 PI: googleapi.Int64(int64(0)),
99 PIStr: googleapi.Int64(int64(0)),
100 PStr: googleapi.String(""),
101 },
102 want: `{"pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`,
103 },
104 {
105 s: schema{
106 B: false,
107 F: 0.0,
108 I: 0,
109 Istr: 0,
110 Str: "",
111 PB: googleapi.Bool(false),
112 PF: googleapi.Float64(0.0),
113 PI: googleapi.Int64(int64(0)),
114 PIStr: googleapi.Int64(int64(0)),
115 PStr: googleapi.String(""),
116 ForceSendFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"},
117 },
118 want: `{"b":false,"f":0.0,"i":0,"istr":"0","str":"","pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`,
119 },
120 {
121 s: schema{
122 B: false,
123 F: 0.0,
124 I: 0,
125 Istr: 0,
126 Str: "",
127 PB: googleapi.Bool(false),
128 PF: googleapi.Float64(0.0),
129 PI: googleapi.Int64(int64(0)),
130 PIStr: googleapi.Int64(int64(0)),
131 PStr: googleapi.String(""),
132 NullFields: []string{"B", "F", "I", "Istr", "Str"},
133 },
134 want: `{"b":null,"f":null,"i":null,"istr":null,"str":null,"pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`,
135 },
136 } {
137 checkMarshalJSON(t, tc)
138 }
139 }
140
141 func TestSliceFields(t *testing.T) {
142 for _, tc := range []testCase{
143 {
144 s: schema{},
145 want: `{}`,
146 },
147 {
148 s: schema{S: []int{}, Int64s: googleapi.Int64s{}},
149 want: `{}`,
150 },
151 {
152 s: schema{S: []int{1}, Int64s: googleapi.Int64s{1}},
153 want: `{"s":[1],"i64s":["1"]}`,
154 },
155 {
156 s: schema{
157 ForceSendFields: []string{"S", "Int64s"},
158 },
159 want: `{"s":[],"i64s":[]}`,
160 },
161 {
162 s: schema{
163 S: []int{},
164 Int64s: googleapi.Int64s{},
165 ForceSendFields: []string{"S", "Int64s"},
166 },
167 want: `{"s":[],"i64s":[]}`,
168 },
169 {
170 s: schema{
171 S: []int{1},
172 Int64s: googleapi.Int64s{1},
173 ForceSendFields: []string{"S", "Int64s"},
174 },
175 want: `{"s":[1],"i64s":["1"]}`,
176 },
177 {
178 s: schema{
179 NullFields: []string{"S", "Int64s"},
180 },
181 want: `{"s":null,"i64s":null}`,
182 },
183 } {
184 checkMarshalJSON(t, tc)
185 }
186 }
187
188 func TestMapField(t *testing.T) {
189 for _, tc := range []testCase{
190 {
191 s: schema{},
192 want: `{}`,
193 },
194 {
195 s: schema{M: make(map[string]string)},
196 want: `{}`,
197 },
198 {
199 s: schema{M: map[string]string{"a": "b"}},
200 want: `{"m":{"a":"b"}}`,
201 },
202 {
203 s: schema{
204 ForceSendFields: []string{"M"},
205 },
206 want: `{"m":{}}`,
207 },
208 {
209 s: schema{
210 NullFields: []string{"M"},
211 },
212 want: `{"m":null}`,
213 },
214 {
215 s: schema{
216 M: make(map[string]string),
217 ForceSendFields: []string{"M"},
218 },
219 want: `{"m":{}}`,
220 },
221 {
222 s: schema{
223 M: make(map[string]string),
224 NullFields: []string{"M"},
225 },
226 want: `{"m":null}`,
227 },
228 {
229 s: schema{
230 M: map[string]string{"a": "b"},
231 ForceSendFields: []string{"M"},
232 },
233 want: `{"m":{"a":"b"}}`,
234 },
235 {
236 s: schema{
237 M: map[string]string{"a": "b"},
238 NullFields: []string{"M.a", "M."},
239 },
240 want: `{"m": {"a": null, "":null}}`,
241 },
242 {
243 s: schema{
244 M: map[string]string{"a": "b"},
245 NullFields: []string{"M.c"},
246 },
247 want: `{"m": {"a": "b", "c": null}}`,
248 },
249 {
250 s: schema{
251 NullFields: []string{"M.a"},
252 ForceSendFields: []string{"M"},
253 },
254 want: `{"m": {"a": null}}`,
255 },
256 {
257 s: schema{
258 NullFields: []string{"M.a"},
259 },
260 want: `{}`,
261 },
262 {
263 s: schema{
264 MapToCustomType: map[string]CustomType{
265 "a": {Foo: "foo"},
266 },
267 NullFields: []string{"MapToCustomType.b"},
268 },
269 want: `{"maptocustomtype": {"a": {"foo": "foo"}, "b": null}}`,
270 },
271 } {
272 checkMarshalJSON(t, tc)
273 }
274 }
275
276 func TestMapToAnyArray(t *testing.T) {
277 for _, tc := range []testCase{
278 {
279 s: schema{},
280 want: `{}`,
281 },
282 {
283 s: schema{MapToAnyArray: make(map[string][]interface{})},
284 want: `{}`,
285 },
286 {
287 s: schema{
288 MapToAnyArray: map[string][]interface{}{
289 "a": {2, "b"},
290 },
291 },
292 want: `{"maptoanyarray":{"a":[2, "b"]}}`,
293 },
294 {
295 s: schema{
296 MapToAnyArray: map[string][]interface{}{
297 "a": nil,
298 },
299 },
300 want: `{"maptoanyarray":{"a": null}}`,
301 },
302 {
303 s: schema{
304 MapToAnyArray: map[string][]interface{}{
305 "a": {nil},
306 },
307 },
308 want: `{"maptoanyarray":{"a":[null]}}`,
309 },
310 {
311 s: schema{
312 ForceSendFields: []string{"MapToAnyArray"},
313 },
314 want: `{"maptoanyarray":{}}`,
315 },
316 {
317 s: schema{
318 NullFields: []string{"MapToAnyArray"},
319 },
320 want: `{"maptoanyarray":null}`,
321 },
322 {
323 s: schema{
324 MapToAnyArray: make(map[string][]interface{}),
325 ForceSendFields: []string{"MapToAnyArray"},
326 },
327 want: `{"maptoanyarray":{}}`,
328 },
329 {
330 s: schema{
331 MapToAnyArray: map[string][]interface{}{
332 "a": {2, "b"},
333 },
334 ForceSendFields: []string{"MapToAnyArray"},
335 },
336 want: `{"maptoanyarray":{"a":[2, "b"]}}`,
337 },
338 } {
339 checkMarshalJSON(t, tc)
340 }
341 }
342
343 type anyType struct {
344 Field int
345 }
346
347 func (a anyType) MarshalJSON() ([]byte, error) {
348 return []byte(`"anyType value"`), nil
349 }
350
351 func TestAnyField(t *testing.T) {
352
353 var nilAny *anyType
354 for _, tc := range []testCase{
355 {
356 s: schema{},
357 want: `{}`,
358 },
359 {
360 s: schema{Any: nilAny},
361 want: `{"any": null}`,
362 },
363 {
364 s: schema{Any: &anyType{}},
365 want: `{"any":"anyType value"}`,
366 },
367 {
368 s: schema{Any: anyType{}},
369 want: `{"any":"anyType value"}`,
370 },
371 {
372 s: schema{
373 ForceSendFields: []string{"Any"},
374 },
375 want: `{}`,
376 },
377 {
378 s: schema{
379 NullFields: []string{"Any"},
380 },
381 want: `{"any":null}`,
382 },
383 {
384 s: schema{
385 Any: nilAny,
386 ForceSendFields: []string{"Any"},
387 },
388 want: `{"any": null}`,
389 },
390 {
391 s: schema{
392 Any: &anyType{},
393 ForceSendFields: []string{"Any"},
394 },
395 want: `{"any":"anyType value"}`,
396 },
397 {
398 s: schema{
399 Any: anyType{},
400 ForceSendFields: []string{"Any"},
401 },
402 want: `{"any":"anyType value"}`,
403 },
404 } {
405 checkMarshalJSON(t, tc)
406 }
407 }
408
409 func TestSubschema(t *testing.T) {
410
411 for _, tc := range []testCase{
412 {
413 s: schema{},
414 want: `{}`,
415 },
416 {
417 s: schema{
418 ForceSendFields: []string{"Child"},
419 },
420 want: `{}`,
421 },
422 {
423 s: schema{
424 NullFields: []string{"Child"},
425 },
426 want: `{"child":null}`,
427 },
428 {
429 s: schema{Child: &child{}},
430 want: `{"child":{}}`,
431 },
432 {
433 s: schema{
434 Child: &child{},
435 ForceSendFields: []string{"Child"},
436 },
437 want: `{"child":{}}`,
438 },
439 {
440 s: schema{Child: &child{B: true}},
441 want: `{"child":{"childbool":true}}`,
442 },
443
444 {
445 s: schema{
446 Child: &child{B: true},
447 ForceSendFields: []string{"Child"},
448 },
449 want: `{"child":{"childbool":true}}`,
450 },
451 } {
452 checkMarshalJSON(t, tc)
453 }
454 }
455
456
457 func checkMarshalJSON(t *testing.T, tc testCase) {
458 doCheckMarshalJSON(t, tc.s, tc.s.ForceSendFields, tc.s.NullFields, tc.want)
459 if len(tc.s.ForceSendFields) == 0 && len(tc.s.NullFields) == 0 {
460
461
462
463 doCheckMarshalJSON(t, tc.s, []string{"dummy"}, []string{"dummy"}, tc.want)
464 }
465 }
466
467 func doCheckMarshalJSON(t *testing.T, s schema, forceSendFields, nullFields []string, wantJSON string) {
468 encoded, err := MarshalJSON(s, forceSendFields, nullFields)
469 if err != nil {
470 t.Fatalf("encoding json:\n got err: %v", err)
471 }
472
473
474 var got interface{}
475 var want interface{}
476 err = json.Unmarshal(encoded, &got)
477 if err != nil {
478 t.Fatalf("decoding json:\n got err: %v", err)
479 }
480 err = json.Unmarshal([]byte(wantJSON), &want)
481 if err != nil {
482 t.Fatalf("decoding json:\n got err: %v", err)
483 }
484 if !reflect.DeepEqual(got, want) {
485 t.Errorf("schemaToMap:\ngot :%v\nwant: %v", got, want)
486 }
487 }
488
489 func TestParseJSONTag(t *testing.T) {
490 for _, tc := range []struct {
491 tag string
492 want jsonTag
493 }{
494 {
495 tag: "-",
496 want: jsonTag{ignore: true},
497 }, {
498 tag: "name,omitempty",
499 want: jsonTag{apiName: "name"},
500 }, {
501 tag: "name,omitempty,string",
502 want: jsonTag{apiName: "name", stringFormat: true},
503 },
504 } {
505 got, err := parseJSONTag(tc.tag)
506 if err != nil {
507 t.Fatalf("parsing json:\n got err: %v\ntag: %q", err, tc.tag)
508 }
509 if !reflect.DeepEqual(got, tc.want) {
510 t.Errorf("parseJSONTage:\ngot :%v\nwant:%v", got, tc.want)
511 }
512 }
513 }
514 func TestParseMalformedJSONTag(t *testing.T) {
515 for _, tag := range []string{
516 "",
517 "name",
518 "name,",
519 "name,blah",
520 "name,blah,string",
521 ",omitempty",
522 ",omitempty,string",
523 "name,omitempty,string,blah",
524 } {
525 _, err := parseJSONTag(tag)
526 if err == nil {
527 t.Fatalf("parsing json: expected err, got nil for tag: %v", tag)
528 }
529 }
530 }
531
View as plain text