1
2
3
4
5 package json_test
6
7 import (
8 "errors"
9 "math"
10 "path"
11 "reflect"
12 "strings"
13 "testing"
14 "time"
15
16 jsonv1 "encoding/json"
17
18 jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
19 )
20
21
22
23
24
25 var jsonPackages = []struct {
26 Version string
27 Marshal func(any) ([]byte, error)
28 Unmarshal func([]byte, any) error
29 }{
30 {"v1", jsonv1.Marshal, jsonv1.Unmarshal},
31 {"v2", jsonv2.Marshal, jsonv2.Unmarshal},
32 }
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 func TestCaseSensitivity(t *testing.T) {
49 type Fields struct {
50 FieldA bool
51 FieldB bool `json:"fooBar"`
52 FieldC bool `json:"fizzBuzz,nocase"`
53 }
54
55 for _, json := range jsonPackages {
56 t.Run(path.Join("Unmarshal", json.Version), func(t *testing.T) {
57
58
59 type goName = string
60 type jsonName = string
61 onlyV1 := json.Version == "v1"
62 onlyV2 := json.Version == "v2"
63 allMatches := map[goName]map[jsonName]bool{
64 "FieldA": {
65 "FieldA": true,
66 "fielda": onlyV1,
67 "fieldA": onlyV1,
68 "FIELDA": onlyV1,
69 "FieldB": false,
70 "FieldC": false,
71 },
72 "FieldB": {
73 "fooBar": true,
74 "FooBar": onlyV1,
75 "foobar": onlyV1,
76 "FOOBAR": onlyV1,
77 "fizzBuzz": false,
78 "FieldA": false,
79 "FieldB": false,
80 "FieldC": false,
81 },
82 "FieldC": {
83 "fizzBuzz": true,
84 "fizzbuzz": true,
85 "FIZZBUZZ": true,
86 "fizz_buzz": onlyV2,
87 "fizz-buzz": onlyV2,
88 "fooBar": false,
89 "FieldA": false,
90 "FieldC": false,
91 "FieldB": false,
92 },
93 }
94
95 for goFieldName, matches := range allMatches {
96 for jsonMemberName, wantMatch := range matches {
97 in := `{"` + jsonMemberName + `":true}`
98 var s Fields
99 if err := json.Unmarshal([]byte(in), &s); err != nil {
100 t.Fatalf("json.Unmarshal error: %v", err)
101 }
102 gotMatch := reflect.ValueOf(s).FieldByName(goFieldName).Bool()
103 if gotMatch != wantMatch {
104 t.Fatalf("%T.%s = %v, want %v", s, goFieldName, gotMatch, wantMatch)
105 }
106 }
107 }
108 })
109 }
110 }
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 func TestOmitEmptyOption(t *testing.T) {
139 type Struct struct {
140 Foo string `json:",omitempty"`
141 Bar []int `json:",omitempty"`
142 Baz *Struct `json:",omitempty"`
143 }
144 type Types struct {
145 Bool bool `json:",omitempty"`
146 StringA string `json:",omitempty"`
147 StringB string `json:",omitempty"`
148 BytesA []byte `json:",omitempty"`
149 BytesB []byte `json:",omitempty"`
150 BytesC []byte `json:",omitempty"`
151 Int int `json:",omitempty"`
152 MapA map[string]string `json:",omitempty"`
153 MapB map[string]string `json:",omitempty"`
154 MapC map[string]string `json:",omitempty"`
155 StructA Struct `json:",omitempty"`
156 StructB Struct `json:",omitempty"`
157 StructC Struct `json:",omitempty"`
158 SliceA []string `json:",omitempty"`
159 SliceB []string `json:",omitempty"`
160 SliceC []string `json:",omitempty"`
161 Array [1]string `json:",omitempty"`
162 PointerA *string `json:",omitempty"`
163 PointerB *string `json:",omitempty"`
164 PointerC *string `json:",omitempty"`
165 InterfaceA any `json:",omitempty"`
166 InterfaceB any `json:",omitempty"`
167 InterfaceC any `json:",omitempty"`
168 InterfaceD any `json:",omitempty"`
169 }
170
171 something := "something"
172 for _, json := range jsonPackages {
173 t.Run(path.Join("Marshal", json.Version), func(t *testing.T) {
174 in := Types{
175 Bool: false,
176 StringA: "",
177 StringB: something,
178 BytesA: nil,
179 BytesB: []byte{},
180 BytesC: []byte(something),
181 Int: 0,
182 MapA: nil,
183 MapB: map[string]string{},
184 MapC: map[string]string{something: something},
185 StructA: Struct{},
186 StructB: Struct{Bar: []int{}, Baz: new(Struct)},
187 StructC: Struct{Foo: something},
188 SliceA: nil,
189 SliceB: []string{},
190 SliceC: []string{something},
191 Array: [1]string{something},
192 PointerA: nil,
193 PointerB: new(string),
194 PointerC: &something,
195 InterfaceA: nil,
196 InterfaceB: (*string)(nil),
197 InterfaceC: new(string),
198 InterfaceD: &something,
199 }
200 b, err := json.Marshal(in)
201 if err != nil {
202 t.Fatalf("json.Marshal error: %v", err)
203 }
204 var out map[string]any
205 if err := json.Unmarshal(b, &out); err != nil {
206 t.Fatalf("json.Unmarshal error: %v", err)
207 }
208
209 onlyV1 := json.Version == "v1"
210 onlyV2 := json.Version == "v2"
211 wantPresent := map[string]bool{
212 "Bool": onlyV2,
213 "StringA": false,
214 "StringB": true,
215 "BytesA": false,
216 "BytesB": false,
217 "BytesC": true,
218 "Int": onlyV2,
219 "MapA": false,
220 "MapB": false,
221 "MapC": true,
222 "StructA": onlyV1,
223 "StructB": onlyV1,
224 "StructC": true,
225 "SliceA": false,
226 "SliceB": false,
227 "SliceC": true,
228 "Array": true,
229 "PointerA": false,
230 "PointerB": onlyV1,
231 "PointerC": true,
232 "InterfaceA": false,
233 "InterfaceB": onlyV1,
234 "InterfaceC": onlyV1,
235 "InterfaceD": true,
236 }
237 for field, want := range wantPresent {
238 _, got := out[field]
239 if got != want {
240 t.Fatalf("%T.%s = %v, want %v", in, field, got, want)
241 }
242 }
243 })
244 }
245 }
246
247 func addr[T any](v T) *T {
248 return &v
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296 func TestStringOption(t *testing.T) {
297 type Types struct {
298 Bool bool `json:",string"`
299 Int int `json:",string"`
300 Float float64 `json:",string"`
301 Map map[string]int `json:",string"`
302 Struct struct{ Field int } `json:",string"`
303 Slice []int `json:",string"`
304 Array [1]int `json:",string"`
305 PointerA *int `json:",string"`
306 PointerB *int `json:",string"`
307 PointerC **int `json:",string"`
308 InterfaceA any `json:",string"`
309 InterfaceB any `json:",string"`
310 }
311
312 for _, json := range jsonPackages {
313 t.Run(path.Join("Marshal", json.Version), func(t *testing.T) {
314 in := Types{
315 Bool: true,
316 Int: 1,
317 Float: 1,
318 Map: map[string]int{"Name": 1},
319 Struct: struct{ Field int }{1},
320 Slice: []int{1},
321 Array: [1]int{1},
322 PointerA: nil,
323 PointerB: addr(1),
324 PointerC: addr(addr(1)),
325 InterfaceA: nil,
326 InterfaceB: 1,
327 }
328 quote := func(s string) string { return `"` + s + `"` }
329 quoteOnlyV1 := func(s string) string {
330 if json.Version == "v1" {
331 s = quote(s)
332 }
333 return s
334 }
335 quoteOnlyV2 := func(s string) string {
336 if json.Version == "v2" {
337 s = quote(s)
338 }
339 return s
340 }
341 want := strings.Join([]string{
342 `{`,
343 `"Bool":` + quoteOnlyV1("true") + `,`,
344 `"Int":` + quote("1") + `,`,
345 `"Float":` + quote("1") + `,`,
346 `"Map":{"Name":` + quoteOnlyV2("1") + `},`,
347 `"Struct":{"Field":` + quoteOnlyV2("1") + `},`,
348 `"Slice":[` + quoteOnlyV2("1") + `],`,
349 `"Array":[` + quoteOnlyV2("1") + `],`,
350 `"PointerA":null,`,
351 `"PointerB":` + quote("1") + `,`,
352 `"PointerC":` + quoteOnlyV2("1") + `,`,
353 `"InterfaceA":null,`,
354 `"InterfaceB":` + quoteOnlyV2("1") + ``,
355 `}`}, "")
356 got, err := json.Marshal(in)
357 if err != nil {
358 t.Fatalf("json.Marshal error: %v", err)
359 }
360 if string(got) != want {
361 t.Fatalf("json.Marshal = %s, want %s", got, want)
362 }
363 })
364 }
365
366 for _, json := range jsonPackages {
367 t.Run(path.Join("Unmarshal/Null", json.Version), func(t *testing.T) {
368 var got Types
369 err := json.Unmarshal([]byte(`{
370 "Bool": "null",
371 "Int": "null",
372 "PointerA": "null"
373 }`), &got)
374 switch {
375 case !reflect.DeepEqual(got, Types{}):
376 t.Fatalf("json.Unmarshal = %v, want %v", got, Types{})
377 case json.Version == "v1" && err != nil:
378 t.Fatalf("json.Unmarshal error: %v", err)
379 case json.Version == "v2" && err == nil:
380 t.Fatal("json.Unmarshal error is nil, want non-nil")
381 }
382 })
383
384 t.Run(path.Join("Unmarshal/Bool", json.Version), func(t *testing.T) {
385 var got Types
386 want := map[string]Types{
387 "v1": {Bool: true},
388 "v2": {Bool: false},
389 }[json.Version]
390 err := json.Unmarshal([]byte(`{"Bool": "true"}`), &got)
391 switch {
392 case !reflect.DeepEqual(got, want):
393 t.Fatalf("json.Unmarshal = %v, want %v", got, want)
394 case json.Version == "v1" && err != nil:
395 t.Fatalf("json.Unmarshal error: %v", err)
396 case json.Version == "v2" && err == nil:
397 t.Fatal("json.Unmarshal error is nil, want non-nil")
398 }
399 })
400
401 t.Run(path.Join("Unmarshal/Shallow", json.Version), func(t *testing.T) {
402 var got Types
403 want := Types{Int: 1, PointerB: addr(1)}
404 err := json.Unmarshal([]byte(`{
405 "Int": "1",
406 "PointerB": "1"
407 }`), &got)
408 switch {
409 case !reflect.DeepEqual(got, want):
410 t.Fatalf("json.Unmarshal = %v, want %v", got, want)
411 case err != nil:
412 t.Fatalf("json.Unmarshal error: %v", err)
413 }
414 })
415
416 t.Run(path.Join("Unmarshal/Deep", json.Version), func(t *testing.T) {
417 var got Types
418 want := map[string]Types{
419 "v1": {
420 Map: map[string]int{"Name": 0},
421 Slice: []int{0},
422 PointerC: addr(addr(0)),
423 },
424 "v2": {
425 Map: map[string]int{"Name": 1},
426 Struct: struct{ Field int }{1},
427 Slice: []int{1},
428 Array: [1]int{1},
429 PointerC: addr(addr(1)),
430 },
431 }[json.Version]
432 err := json.Unmarshal([]byte(`{
433 "Map": {"Name":"1"},
434 "Struct": {"Field":"1"},
435 "Slice": ["1"],
436 "Array": ["1"],
437 "PointerC": "1"
438 }`), &got)
439 switch {
440 case !reflect.DeepEqual(got, want):
441 t.Fatalf("json.Unmarshal =\n%v, want\n%v", got, want)
442 case json.Version == "v1" && err == nil:
443 t.Fatal("json.Unmarshal error is nil, want non-nil")
444 case json.Version == "v2" && err != nil:
445 t.Fatalf("json.Unmarshal error: %v", err)
446 }
447 })
448 }
449 }
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477 func TestNilSlicesAndMaps(t *testing.T) {
478 type Composites struct {
479 B []byte
480 S []string
481 M map[string]string
482 }
483
484 for _, json := range jsonPackages {
485 t.Run(path.Join("Marshal", json.Version), func(t *testing.T) {
486 in := []Composites{
487 {B: []byte(nil), S: []string(nil), M: map[string]string(nil)},
488 {B: []byte{}, S: []string{}, M: map[string]string{}},
489 }
490 want := map[string]string{
491 "v1": `[{"B":null,"S":null,"M":null},{"B":"","S":[],"M":{}}]`,
492 "v2": `[{"B":"","S":[],"M":{}},{"B":"","S":[],"M":{}}]`,
493 }[json.Version]
494 got, err := json.Marshal(in)
495 if err != nil {
496 t.Fatalf("json.Marshal error: %v", err)
497 }
498 if string(got) != want {
499 t.Fatalf("json.Marshal = %s, want %s", got, want)
500 }
501 })
502 }
503 }
504
505
506
507
508
509
510
511
512 func TestArrays(t *testing.T) {
513 for _, json := range jsonPackages {
514 t.Run(path.Join("Unmarshal/TooFew", json.Version), func(t *testing.T) {
515 var got [2]int
516 err := json.Unmarshal([]byte(`[1]`), &got)
517 switch {
518 case got != [2]int{1, 0}:
519 t.Fatalf(`json.Unmarshal = %v, want [1 0]`, got)
520 case json.Version == "v1" && err != nil:
521 t.Fatalf("json.Unmarshal error: %v", err)
522 case json.Version == "v2" && err == nil:
523 t.Fatal("json.Unmarshal error is nil, want non-nil")
524 }
525 })
526 }
527
528 for _, json := range jsonPackages {
529 t.Run(path.Join("Unmarshal/TooMany", json.Version), func(t *testing.T) {
530 var got [2]int
531 err := json.Unmarshal([]byte(`[1,2,3]`), &got)
532 switch {
533 case got != [2]int{1, 2}:
534 t.Fatalf(`json.Unmarshal = %v, want [1 2]`, got)
535 case json.Version == "v1" && err != nil:
536 t.Fatalf("json.Unmarshal error: %v", err)
537 case json.Version == "v2" && err == nil:
538 t.Fatal("json.Unmarshal error is nil, want non-nil")
539 }
540 })
541 }
542 }
543
544
545
546
547
548
549
550
551
552
553
554 func TestByteArrays(t *testing.T) {
555 for _, json := range jsonPackages {
556 t.Run(path.Join("Marshal", json.Version), func(t *testing.T) {
557 in := [4]byte{1, 2, 3, 4}
558 got, err := json.Marshal(in)
559 if err != nil {
560 t.Fatalf("json.Marshal error: %v", err)
561 }
562 want := map[string]string{
563 "v1": `[1,2,3,4]`,
564 "v2": `"AQIDBA=="`,
565 }[json.Version]
566 if string(got) != want {
567 t.Fatalf("json.Marshal = %s, want %s", got, want)
568 }
569 })
570 }
571
572 for _, json := range jsonPackages {
573 t.Run(path.Join("Unmarshal", json.Version), func(t *testing.T) {
574 in := map[string]string{
575 "v1": `[1,2,3,4]`,
576 "v2": `"AQIDBA=="`,
577 }[json.Version]
578 var got [4]byte
579 err := json.Unmarshal([]byte(in), &got)
580 switch {
581 case err != nil:
582 t.Fatalf("json.Unmarshal error: %v", err)
583 case got != [4]byte{1, 2, 3, 4}:
584 t.Fatalf("json.Unmarshal = %v, want [1 2 3 4]", got)
585 }
586 })
587 }
588 }
589
590
591 type CallCheck string
592
593
594 func (*CallCheck) MarshalJSON() ([]byte, error) {
595 return []byte(`"CALLED"`), nil
596 }
597
598
599 func (v *CallCheck) UnmarshalJSON([]byte) error {
600 *v = `CALLED`
601 return nil
602 }
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621 func TestPointerReceiver(t *testing.T) {
622 type Values struct {
623 S []CallCheck
624 A [1]CallCheck
625 M map[string]CallCheck
626 V CallCheck
627 I any
628 }
629
630 for _, json := range jsonPackages {
631 t.Run(path.Join("Marshal", json.Version), func(t *testing.T) {
632 var cc CallCheck
633 in := Values{
634 S: []CallCheck{cc},
635 A: [1]CallCheck{cc},
636 M: map[string]CallCheck{"": cc},
637 V: cc,
638 I: cc,
639 }
640 want := map[string]string{
641 "v1": `{"S":["CALLED"],"A":[""],"M":{"":""},"V":"","I":""}`,
642 "v2": `{"S":["CALLED"],"A":["CALLED"],"M":{"":"CALLED"},"V":"CALLED","I":"CALLED"}`,
643 }[json.Version]
644 got, err := json.Marshal(in)
645 if err != nil {
646 t.Fatalf("json.Marshal error: %v", err)
647 }
648 if string(got) != want {
649 t.Fatalf("json.Marshal = %s, want %s", got, want)
650 }
651 })
652 }
653
654 for _, json := range jsonPackages {
655 t.Run(path.Join("Unmarshal", json.Version), func(t *testing.T) {
656 in := `{"S":[""],"A":[""],"M":{"":""},"V":"","I":""}`
657 called := CallCheck("CALLED")
658 want := map[string]Values{
659 "v1": {
660 S: []CallCheck{called},
661 A: [1]CallCheck{called},
662 M: map[string]CallCheck{"": called},
663 V: called,
664 I: "",
665 },
666 "v2": {
667 S: []CallCheck{called},
668 A: [1]CallCheck{called},
669 M: map[string]CallCheck{"": called},
670 V: called,
671 I: called,
672 },
673 }[json.Version]
674 got := Values{
675 A: [1]CallCheck{CallCheck("")},
676 S: []CallCheck{CallCheck("")},
677 M: map[string]CallCheck{"": CallCheck("")},
678 V: CallCheck(""),
679 I: CallCheck(""),
680 }
681 if err := json.Unmarshal([]byte(in), &got); err != nil {
682 t.Fatalf("json.Unmarshal error: %v", err)
683 }
684 if !reflect.DeepEqual(got, want) {
685 t.Fatalf("json.Unmarshal = %v, want %v", got, want)
686 }
687 })
688 }
689 }
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705 func TestMapDeterminism(t *testing.T) {
706 const iterations = 10
707 in := map[int]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}
708
709 for _, json := range jsonPackages {
710 t.Run(path.Join("Marshal", json.Version), func(t *testing.T) {
711 outs := make(map[string]bool)
712 for i := 0; i < iterations; i++ {
713 b, err := json.Marshal(in)
714 if err != nil {
715 t.Fatalf("json.Marshal error: %v", err)
716 }
717 outs[string(b)] = true
718 }
719 switch {
720 case json.Version == "v1" && len(outs) != 1:
721 t.Fatalf("json.Marshal encoded to %d unique forms, expected 1", len(outs))
722 case json.Version == "v2" && len(outs) == 1:
723 t.Logf("json.Marshal encoded to 1 unique form by chance; are you feeling lucky?")
724 }
725 })
726 }
727 }
728
729
730
731
732
733
734
735
736
737
738
739
740
741 func TestEscapeHTML(t *testing.T) {
742 for _, json := range jsonPackages {
743 t.Run(path.Join("Marshal", json.Version), func(t *testing.T) {
744 const in = `<script> console.log("Hello, world!"); </script>`
745 got, err := json.Marshal(in)
746 if err != nil {
747 t.Fatalf("json.Marshal error: %v", err)
748 }
749 want := map[string]string{
750 "v1": `"\u003cscript\u003e console.log(\"Hello, world!\"); \u003c/script\u003e"`,
751 "v2": `"<script> console.log(\"Hello, world!\"); </script>"`,
752 }[json.Version]
753 if string(got) != want {
754 t.Fatalf("json.Marshal = %s, want %s", got, want)
755 }
756 })
757 }
758 }
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780 func TestInvalidUTF8(t *testing.T) {
781 for _, json := range jsonPackages {
782 t.Run(path.Join("Marshal", json.Version), func(t *testing.T) {
783 got, err := json.Marshal("\xff")
784 switch {
785 case json.Version == "v1" && err != nil:
786 t.Fatalf("json.Marshal error: %v", err)
787 case json.Version == "v1" && string(got) != `"\ufffd"`:
788 t.Fatalf(`json.Marshal = %s, want "\ufffd"`, got)
789 case json.Version == "v2" && err == nil:
790 t.Fatal("json.Marshal error is nil, want non-nil")
791 }
792 })
793 }
794
795 for _, json := range jsonPackages {
796 t.Run(path.Join("Unmarshal", json.Version), func(t *testing.T) {
797 const in = "\"\xff\""
798 var got string
799 err := json.Unmarshal([]byte(in), &got)
800 switch {
801 case json.Version == "v1" && err != nil:
802 t.Fatalf("json.Unmarshal error: %v", err)
803 case json.Version == "v1" && got != "\ufffd":
804 t.Fatalf(`json.Unmarshal = %q, want "\ufffd"`, got)
805 case json.Version == "v2" && err == nil:
806 t.Fatal("json.Unmarshal error is nil, want non-nil")
807 }
808 })
809 }
810 }
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844 func TestDuplicateNames(t *testing.T) {
845 for _, json := range jsonPackages {
846 t.Run(path.Join("Unmarshal", json.Version), func(t *testing.T) {
847 const in = `{"Name":1,"Name":2}`
848 var got struct{ Name int }
849 err := json.Unmarshal([]byte(in), &got)
850 switch {
851 case json.Version == "v1" && err != nil:
852 t.Fatalf("json.Unmarshal error: %v", err)
853 case json.Version == "v1" && got != struct{ Name int }{2}:
854 t.Fatalf(`json.Unmarshal = %v, want {2}`, got)
855 case json.Version == "v2" && err == nil:
856 t.Fatal("json.Unmarshal error is nil, want non-nil")
857 }
858 })
859 }
860 }
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875 func TestMergeNull(t *testing.T) {
876 type Types struct {
877 Bool bool
878 String string
879 Bytes []byte
880 Int int
881 Map map[string]string
882 Struct struct{ Field string }
883 Slice []string
884 Array [1]string
885 Pointer *string
886 Interface any
887 }
888
889 for _, json := range jsonPackages {
890 t.Run(path.Join("Unmarshal", json.Version), func(t *testing.T) {
891
892 in := Types{
893 Bool: true,
894 String: "old",
895 Bytes: []byte("old"),
896 Int: 1234,
897 Map: map[string]string{"old": "old"},
898 Struct: struct{ Field string }{"old"},
899 Slice: []string{"old"},
900 Array: [1]string{"old"},
901 Pointer: new(string),
902 Interface: "old",
903 }
904
905
906 if err := json.Unmarshal([]byte(`{
907 "Bool": null,
908 "String": null,
909 "Bytes": null,
910 "Int": null,
911 "Map": null,
912 "Struct": null,
913 "Slice": null,
914 "Array": null,
915 "Pointer": null,
916 "Interface": null
917 }`), &in); err != nil {
918 t.Fatalf("json.Unmarshal error: %v", err)
919 }
920
921 want := map[string]Types{
922 "v1": {
923 Bool: true,
924 String: "old",
925 Int: 1234,
926 Struct: struct{ Field string }{"old"},
927 Array: [1]string{"old"},
928 },
929 "v2": {},
930 }[json.Version]
931 if !reflect.DeepEqual(in, want) {
932 t.Fatalf("json.Unmarshal = %+v, want %+v", in, want)
933 }
934 })
935 }
936 }
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955 func TestMergeComposite(t *testing.T) {
956 type Tuple struct{ Old, New bool }
957 type Composites struct {
958 Slice []Tuple
959 Array [1]Tuple
960 Map map[string]Tuple
961 MapPointer map[string]*Tuple
962 Struct struct{ Tuple Tuple }
963 StructPointer *struct{ Tuple Tuple }
964 Interface any
965 InterfacePointer any
966 }
967
968 for _, json := range jsonPackages {
969 t.Run(path.Join("Unmarshal", json.Version), func(t *testing.T) {
970
971 in := Composites{
972 Slice: []Tuple{{Old: true}, {Old: true}}[:1],
973 Array: [1]Tuple{{Old: true}},
974 Map: map[string]Tuple{"Tuple": {Old: true}},
975 MapPointer: map[string]*Tuple{"Tuple": {Old: true}},
976 Struct: struct{ Tuple Tuple }{Tuple{Old: true}},
977 StructPointer: &struct{ Tuple Tuple }{Tuple{Old: true}},
978 Interface: Tuple{Old: true},
979 InterfacePointer: &Tuple{Old: true},
980 }
981
982
983 if err := json.Unmarshal([]byte(`{
984 "Slice": [{"New":true}, {"New":true}],
985 "Array": [{"New":true}],
986 "Map": {"Tuple": {"New":true}},
987 "MapPointer": {"Tuple": {"New":true}},
988 "Struct": {"Tuple": {"New":true}},
989 "StructPointer": {"Tuple": {"New":true}},
990 "Interface": {"New":true},
991 "InterfacePointer": {"New":true}
992 }`), &in); err != nil {
993 t.Fatalf("json.Unmarshal error: %v", err)
994 }
995
996 merged := Tuple{Old: true, New: true}
997 replaced := Tuple{Old: false, New: true}
998 want := map[string]Composites{
999 "v1": {
1000 Slice: []Tuple{merged, merged},
1001 Array: [1]Tuple{merged},
1002 Map: map[string]Tuple{"Tuple": replaced},
1003 MapPointer: map[string]*Tuple{"Tuple": &replaced},
1004 Struct: struct{ Tuple Tuple }{merged},
1005 StructPointer: &struct{ Tuple Tuple }{merged},
1006 Interface: map[string]any{"New": true},
1007 InterfacePointer: &merged,
1008 },
1009 "v2": {
1010 Slice: []Tuple{replaced, replaced},
1011 Array: [1]Tuple{replaced},
1012 Map: map[string]Tuple{"Tuple": merged},
1013 MapPointer: map[string]*Tuple{"Tuple": &merged},
1014 Struct: struct{ Tuple Tuple }{merged},
1015 StructPointer: &struct{ Tuple Tuple }{merged},
1016 Interface: merged,
1017 InterfacePointer: &merged,
1018 },
1019 }[json.Version]
1020 if !reflect.DeepEqual(in, want) {
1021 t.Fatalf("json.Unmarshal = %+v, want %+v", in, want)
1022 }
1023 })
1024 }
1025 }
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042 func TestTimeDurations(t *testing.T) {
1043 for _, json := range jsonPackages {
1044 t.Run(path.Join("Marshal", json.Version), func(t *testing.T) {
1045 got, err := json.Marshal(time.Minute)
1046 switch {
1047 case err != nil:
1048 t.Fatalf("json.Marshal error: %v", err)
1049 case json.Version == "v1" && string(got) != "60000000000":
1050 t.Fatalf("json.Marshal = %s, want 60000000000", got)
1051 case json.Version == "v2" && string(got) != `"1m0s"`:
1052 t.Fatalf(`json.Marshal = %s, want "1m0s"`, got)
1053 }
1054 })
1055 }
1056
1057 for _, json := range jsonPackages {
1058 t.Run(path.Join("Unmarshal", json.Version), func(t *testing.T) {
1059 in := map[string]string{
1060 "v1": "60000000000",
1061 "v2": `"1m0s"`,
1062 }[json.Version]
1063 var got time.Duration
1064 err := json.Unmarshal([]byte(in), &got)
1065 switch {
1066 case err != nil:
1067 t.Fatalf("json.Unmarshal error: %v", err)
1068 case got != time.Minute:
1069 t.Fatalf("json.Unmarshal = %v, want 1m0s", got)
1070 }
1071 })
1072 }
1073 }
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083 func TestMaxFloats(t *testing.T) {
1084 for _, json := range jsonPackages {
1085 t.Run(path.Join("Unmarshal", json.Version), func(t *testing.T) {
1086 const in = `1e1000`
1087 var got any
1088 err := json.Unmarshal([]byte(in), &got)
1089 switch {
1090 case json.Version == "v1" && err == nil:
1091 t.Fatal("json.Unmarshal error is nil, want non-nil")
1092 case json.Version == "v2" && got != any(math.MaxFloat64):
1093 t.Fatalf("json.Unmarshal = %v, want %v", got, math.MaxFloat64)
1094 case json.Version == "v2" && err != nil:
1095 t.Fatalf("json.Unmarshal error: %v", err)
1096 }
1097 })
1098 }
1099 }
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110 func TestEmptyStructs(t *testing.T) {
1111 never := func(string) bool { return false }
1112 onlyV2 := func(v string) bool { return v == "v2" }
1113 values := []struct {
1114 in any
1115 wantError func(string) bool
1116 }{
1117
1118 {in: addr(struct{}{}), wantError: never},
1119
1120
1121
1122 {in: errors.New("error"), wantError: onlyV2},
1123
1124 {in: addr(struct{ Exported, unexported int }{}), wantError: never},
1125 }
1126
1127 for _, json := range jsonPackages {
1128 t.Run("Marshal", func(t *testing.T) {
1129 for _, value := range values {
1130 wantError := value.wantError(json.Version)
1131 _, err := json.Marshal(value.in)
1132 switch {
1133 case (err == nil) && wantError:
1134 t.Fatalf("json.Marshal error is nil, want non-nil")
1135 case (err != nil) && !wantError:
1136 t.Fatalf("json.Marshal error: %v", err)
1137 }
1138 }
1139 })
1140 }
1141
1142 for _, json := range jsonPackages {
1143 t.Run("Unmarshal", func(t *testing.T) {
1144 for _, value := range values {
1145 wantError := value.wantError(json.Version)
1146 out := reflect.New(reflect.TypeOf(value.in).Elem()).Interface()
1147 err := json.Unmarshal([]byte("{}"), out)
1148 switch {
1149 case (err == nil) && wantError:
1150 t.Fatalf("json.Unmarshal error is nil, want non-nil")
1151 case (err != nil) && !wantError:
1152 t.Fatalf("json.Unmarshal error: %v", err)
1153 }
1154 }
1155 })
1156 }
1157 }
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185 func TestEmbedUnexported(t *testing.T) {
1186 never := func(string) bool { return false }
1187 onlyV2 := func(v string) bool { return v == "v2" }
1188 always := func(string) bool { return true }
1189 type Exported struct{ Field string }
1190 type unexported struct{ Field string }
1191 values := []struct {
1192 in any
1193 wantMarshalError func(string) bool
1194 wantUnmarshalError func(string) bool
1195 }{
1196
1197 {in: struct{ Exported }{}, wantMarshalError: never, wantUnmarshalError: never},
1198 {in: struct{ *Exported }{}, wantMarshalError: never, wantUnmarshalError: never},
1199
1200 {in: struct{ unexported }{}, wantMarshalError: onlyV2, wantUnmarshalError: onlyV2},
1201 {in: struct{ *unexported }{}, wantMarshalError: onlyV2, wantUnmarshalError: always},
1202
1203 {in: struct {
1204 unexported `json:"-"`
1205 }{}, wantMarshalError: never, wantUnmarshalError: never},
1206 {in: struct {
1207 *unexported `json:"-"`
1208 }{}, wantMarshalError: never, wantUnmarshalError: never},
1209 }
1210
1211 for _, json := range jsonPackages {
1212 t.Run("Marshal", func(t *testing.T) {
1213 for _, value := range values {
1214 wantError := value.wantMarshalError(json.Version)
1215 _, err := json.Marshal(value.in)
1216 switch {
1217 case (err == nil) && wantError:
1218 t.Fatalf("json.Marshal error is nil, want non-nil")
1219 case (err != nil) && !wantError:
1220 t.Fatalf("json.Marshal error: %v", err)
1221 }
1222 }
1223 })
1224 }
1225
1226 for _, json := range jsonPackages {
1227 t.Run("Unmarshal", func(t *testing.T) {
1228 for _, value := range values {
1229 wantError := value.wantUnmarshalError(json.Version)
1230 out := reflect.New(reflect.TypeOf(value.in)).Interface()
1231 err := json.Unmarshal([]byte(`{"Field":"Value"}`), out)
1232 switch {
1233 case (err == nil) && wantError:
1234 t.Fatalf("json.Unmarshal error is nil, want non-nil")
1235 case (err != nil) && !wantError:
1236 t.Fatalf("json.Unmarshal error: %v", err)
1237 }
1238 }
1239 })
1240 }
1241 }
1242
View as plain text