Source file
src/encoding/json/v2_encode_test.go
1
2
3
4
5
6
7 package json
8
9 import (
10 "bytes"
11 "encoding"
12 "fmt"
13 "log"
14 "math"
15 "reflect"
16 "regexp"
17 "runtime/debug"
18 "strconv"
19 "sync"
20 "testing"
21 "testing/synctest"
22 "time"
23 )
24
25 type OptionalsEmpty struct {
26 Sr string `json:"sr"`
27 So string `json:"so,omitempty"`
28 Sw string `json:"-"`
29
30 Ir int `json:"omitempty"`
31 Io int `json:"io,omitempty"`
32
33 Slr []string `json:"slr,random"`
34 Slo []string `json:"slo,omitempty"`
35
36 Mr map[string]any `json:"mr"`
37 Mo map[string]any `json:",omitempty"`
38
39 Fr float64 `json:"fr"`
40 Fo float64 `json:"fo,omitempty"`
41
42 Br bool `json:"br"`
43 Bo bool `json:"bo,omitempty"`
44
45 Ur uint `json:"ur"`
46 Uo uint `json:"uo,omitempty"`
47
48 Str struct{} `json:"str"`
49 Sto struct{} `json:"sto,omitempty"`
50 }
51
52 func TestOmitEmpty(t *testing.T) {
53 const want = `{
54 "sr": "",
55 "omitempty": 0,
56 "slr": null,
57 "mr": {},
58 "fr": 0,
59 "br": false,
60 "ur": 0,
61 "str": {},
62 "sto": {}
63 }`
64 var o OptionalsEmpty
65 o.Sw = "something"
66 o.Mr = map[string]any{}
67 o.Mo = map[string]any{}
68
69 got, err := MarshalIndent(&o, "", " ")
70 if err != nil {
71 t.Fatalf("MarshalIndent error: %v", err)
72 }
73 if got := string(got); got != want {
74 t.Errorf("MarshalIndent:\n\tgot: %s\n\twant: %s\n", indentNewlines(got), indentNewlines(want))
75 }
76 }
77
78 type NonZeroStruct struct{}
79
80 func (nzs NonZeroStruct) IsZero() bool {
81 return false
82 }
83
84 type NoPanicStruct struct {
85 Int int `json:"int,omitzero"`
86 }
87
88 func (nps *NoPanicStruct) IsZero() bool {
89 return nps.Int != 0
90 }
91
92 type isZeroer interface {
93 IsZero() bool
94 }
95
96 type OptionalsZero struct {
97 Sr string `json:"sr"`
98 So string `json:"so,omitzero"`
99 Sw string `json:"-"`
100
101 Ir int `json:"omitzero"`
102 Io int `json:"io,omitzero"`
103
104 Slr []string `json:"slr,random"`
105 Slo []string `json:"slo,omitzero"`
106 SloNonNil []string `json:"slononnil,omitzero"`
107
108 Mr map[string]any `json:"mr"`
109 Mo map[string]any `json:",omitzero"`
110 Moo map[string]any `json:"moo,omitzero"`
111
112 Fr float64 `json:"fr"`
113 Fo float64 `json:"fo,omitzero"`
114 Foo float64 `json:"foo,omitzero"`
115 Foo2 [2]float64 `json:"foo2,omitzero"`
116
117 Br bool `json:"br"`
118 Bo bool `json:"bo,omitzero"`
119
120 Ur uint `json:"ur"`
121 Uo uint `json:"uo,omitzero"`
122
123 Str struct{} `json:"str"`
124 Sto struct{} `json:"sto,omitzero"`
125
126 Time time.Time `json:"time,omitzero"`
127 TimeLocal time.Time `json:"timelocal,omitzero"`
128 Nzs NonZeroStruct `json:"nzs,omitzero"`
129
130 NilIsZeroer isZeroer `json:"niliszeroer,omitzero"`
131 NonNilIsZeroer isZeroer `json:"nonniliszeroer,omitzero"`
132 NoPanicStruct0 isZeroer `json:"nps0,omitzero"`
133 NoPanicStruct1 isZeroer `json:"nps1,omitzero"`
134 NoPanicStruct2 *NoPanicStruct `json:"nps2,omitzero"`
135 NoPanicStruct3 *NoPanicStruct `json:"nps3,omitzero"`
136 NoPanicStruct4 NoPanicStruct `json:"nps4,omitzero"`
137 }
138
139 func TestOmitZero(t *testing.T) {
140 const want = `{
141 "sr": "",
142 "omitzero": 0,
143 "slr": null,
144 "slononnil": [],
145 "mr": {},
146 "Mo": {},
147 "fr": 0,
148 "br": false,
149 "ur": 0,
150 "str": {},
151 "nzs": {},
152 "nps1": {},
153 "nps3": {},
154 "nps4": {}
155 }`
156 var o OptionalsZero
157 o.Sw = "something"
158 o.SloNonNil = make([]string, 0)
159 o.Mr = map[string]any{}
160 o.Mo = map[string]any{}
161
162 o.Foo = -0
163 o.Foo2 = [2]float64{+0, -0}
164
165 o.TimeLocal = time.Time{}.Local()
166
167 o.NonNilIsZeroer = time.Time{}
168 o.NoPanicStruct0 = (*NoPanicStruct)(nil)
169 o.NoPanicStruct1 = &NoPanicStruct{}
170 o.NoPanicStruct3 = &NoPanicStruct{}
171
172 got, err := MarshalIndent(&o, "", " ")
173 if err != nil {
174 t.Fatalf("MarshalIndent error: %v", err)
175 }
176 if got := string(got); got != want {
177 t.Errorf("MarshalIndent:\n\tgot: %s\n\twant: %s\n", indentNewlines(got), indentNewlines(want))
178 }
179 }
180
181 func TestOmitZeroMap(t *testing.T) {
182 const want = `{
183 "foo": {
184 "sr": "",
185 "omitzero": 0,
186 "slr": null,
187 "mr": null,
188 "fr": 0,
189 "br": false,
190 "ur": 0,
191 "str": {},
192 "nzs": {},
193 "nps4": {}
194 }
195 }`
196 m := map[string]OptionalsZero{"foo": {}}
197 got, err := MarshalIndent(m, "", " ")
198 if err != nil {
199 t.Fatalf("MarshalIndent error: %v", err)
200 }
201 if got := string(got); got != want {
202 fmt.Println(got)
203 t.Errorf("MarshalIndent:\n\tgot: %s\n\twant: %s\n", indentNewlines(got), indentNewlines(want))
204 }
205 }
206
207 type OptionalsEmptyZero struct {
208 Sr string `json:"sr"`
209 So string `json:"so,omitempty,omitzero"`
210 Sw string `json:"-"`
211
212 Io int `json:"io,omitempty,omitzero"`
213
214 Slr []string `json:"slr,random"`
215 Slo []string `json:"slo,omitempty,omitzero"`
216 SloNonNil []string `json:"slononnil,omitempty,omitzero"`
217
218 Mr map[string]any `json:"mr"`
219 Mo map[string]any `json:",omitempty,omitzero"`
220
221 Fr float64 `json:"fr"`
222 Fo float64 `json:"fo,omitempty,omitzero"`
223
224 Br bool `json:"br"`
225 Bo bool `json:"bo,omitempty,omitzero"`
226
227 Ur uint `json:"ur"`
228 Uo uint `json:"uo,omitempty,omitzero"`
229
230 Str struct{} `json:"str"`
231 Sto struct{} `json:"sto,omitempty,omitzero"`
232
233 Time time.Time `json:"time,omitempty,omitzero"`
234 Nzs NonZeroStruct `json:"nzs,omitempty,omitzero"`
235 }
236
237 func TestOmitEmptyZero(t *testing.T) {
238 const want = `{
239 "sr": "",
240 "slr": null,
241 "mr": {},
242 "fr": 0,
243 "br": false,
244 "ur": 0,
245 "str": {},
246 "nzs": {}
247 }`
248 var o OptionalsEmptyZero
249 o.Sw = "something"
250 o.SloNonNil = make([]string, 0)
251 o.Mr = map[string]any{}
252 o.Mo = map[string]any{}
253
254 got, err := MarshalIndent(&o, "", " ")
255 if err != nil {
256 t.Fatalf("MarshalIndent error: %v", err)
257 }
258 if got := string(got); got != want {
259 t.Errorf("MarshalIndent:\n\tgot: %s\n\twant: %s\n", indentNewlines(got), indentNewlines(want))
260 }
261 }
262
263 type StringTag struct {
264 BoolStr bool `json:",string"`
265 IntStr int64 `json:",string"`
266 UintptrStr uintptr `json:",string"`
267 StrStr string `json:",string"`
268 NumberStr Number `json:",string"`
269 }
270
271 func TestRoundtripStringTag(t *testing.T) {
272 tests := []struct {
273 CaseName
274 in StringTag
275 want string
276 }{{
277 CaseName: Name("AllTypes"),
278 in: StringTag{
279 BoolStr: true,
280 IntStr: 42,
281 UintptrStr: 44,
282 StrStr: "xzbit",
283 NumberStr: "46",
284 },
285 want: `{
286 "BoolStr": "true",
287 "IntStr": "42",
288 "UintptrStr": "44",
289 "StrStr": "\"xzbit\"",
290 "NumberStr": "46"
291 }`,
292 }, {
293
294 CaseName: Name("StringDoubleEscapes"),
295 in: StringTag{
296 StrStr: "\b\f\n\r\t\"\\",
297 NumberStr: "0",
298 },
299 want: `{
300 "BoolStr": "false",
301 "IntStr": "0",
302 "UintptrStr": "0",
303 "StrStr": "\"\\b\\f\\n\\r\\t\\\"\\\\\"",
304 "NumberStr": "0"
305 }`,
306 }}
307 for _, tt := range tests {
308 t.Run(tt.Name, func(t *testing.T) {
309 got, err := MarshalIndent(&tt.in, "", "\t")
310 if err != nil {
311 t.Fatalf("%s: MarshalIndent error: %v", tt.Where, err)
312 }
313 if got := string(got); got != tt.want {
314 t.Fatalf("%s: MarshalIndent:\n\tgot: %s\n\twant: %s", tt.Where, stripWhitespace(got), stripWhitespace(tt.want))
315 }
316
317
318 var s2 StringTag
319 if err := Unmarshal(got, &s2); err != nil {
320 t.Fatalf("%s: Decode error: %v", tt.Where, err)
321 }
322 if !reflect.DeepEqual(s2, tt.in) {
323 t.Fatalf("%s: Decode:\n\tinput: %s\n\tgot: %#v\n\twant: %#v", tt.Where, indentNewlines(string(got)), s2, tt.in)
324 }
325 })
326 }
327 }
328
329
330 type renamedByte byte
331 type renamedByteSlice []byte
332 type renamedRenamedByteSlice []renamedByte
333
334 func TestEncodeRenamedByteSlice(t *testing.T) {
335 s := renamedByteSlice("abc")
336 got, err := Marshal(s)
337 if err != nil {
338 t.Fatalf("Marshal error: %v", err)
339 }
340 want := `"YWJj"`
341 if string(got) != want {
342 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
343 }
344 r := renamedRenamedByteSlice("abc")
345 got, err = Marshal(r)
346 if err != nil {
347 t.Fatalf("Marshal error: %v", err)
348 }
349 if string(got) != want {
350 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
351 }
352 }
353
354 type SamePointerNoCycle struct {
355 Ptr1, Ptr2 *SamePointerNoCycle
356 }
357
358 var samePointerNoCycle = &SamePointerNoCycle{}
359
360 type PointerCycle struct {
361 Ptr *PointerCycle
362 }
363
364 var pointerCycle = &PointerCycle{}
365
366 type PointerCycleIndirect struct {
367 Ptrs []any
368 }
369
370 type RecursiveSlice []RecursiveSlice
371
372 var (
373 pointerCycleIndirect = &PointerCycleIndirect{}
374 mapCycle = make(map[string]any)
375 sliceCycle = []any{nil}
376 sliceNoCycle = []any{nil, nil}
377 recursiveSliceCycle = []RecursiveSlice{nil}
378 )
379
380 func init() {
381 ptr := &SamePointerNoCycle{}
382 samePointerNoCycle.Ptr1 = ptr
383 samePointerNoCycle.Ptr2 = ptr
384
385 pointerCycle.Ptr = pointerCycle
386 pointerCycleIndirect.Ptrs = []any{pointerCycleIndirect}
387
388 mapCycle["x"] = mapCycle
389 sliceCycle[0] = sliceCycle
390 sliceNoCycle[1] = sliceNoCycle[:1]
391 const startDetectingCyclesAfter = 1e3
392 for i := startDetectingCyclesAfter; i > 0; i-- {
393 sliceNoCycle = []any{sliceNoCycle}
394 }
395 recursiveSliceCycle[0] = recursiveSliceCycle
396 }
397
398 func TestSamePointerNoCycle(t *testing.T) {
399 if _, err := Marshal(samePointerNoCycle); err != nil {
400 t.Fatalf("Marshal error: %v", err)
401 }
402 }
403
404 func TestSliceNoCycle(t *testing.T) {
405 if _, err := Marshal(sliceNoCycle); err != nil {
406 t.Fatalf("Marshal error: %v", err)
407 }
408 }
409
410 func TestUnsupportedValues(t *testing.T) {
411 tests := []struct {
412 CaseName
413 in any
414 }{
415 {Name(""), math.NaN()},
416 {Name(""), math.Inf(-1)},
417 {Name(""), math.Inf(1)},
418 {Name(""), pointerCycle},
419 {Name(""), pointerCycleIndirect},
420 {Name(""), mapCycle},
421 {Name(""), sliceCycle},
422 {Name(""), recursiveSliceCycle},
423 }
424 for _, tt := range tests {
425 t.Run(tt.Name, func(t *testing.T) {
426 if _, err := Marshal(tt.in); err != nil {
427 if _, ok := err.(*UnsupportedValueError); !ok {
428 t.Errorf("%s: Marshal error:\n\tgot: %T\n\twant: %T", tt.Where, err, new(UnsupportedValueError))
429 }
430 } else {
431 t.Errorf("%s: Marshal error: got nil, want non-nil", tt.Where)
432 }
433 })
434 }
435 }
436
437
438 func TestUnsupportedValueErrorValue(t *testing.T) {
439 type NamedFloat float64
440 tests := []struct {
441 CaseName
442 in any
443 want any
444 }{
445 {Name(""), NamedFloat(math.NaN()), NamedFloat(math.NaN())},
446 {Name(""), math.Inf(-1), math.Inf(-1)},
447 {Name(""), NamedFloat(math.Inf(1)), NamedFloat(math.Inf(1))},
448 {Name(""), map[string]float64{"x": math.Inf(1)}, math.Inf(1)},
449 {Name(""), []NamedFloat{NamedFloat(math.NaN())}, NamedFloat(math.NaN())},
450 {Name(""), struct{ F float64 }{math.Inf(-1)}, math.Inf(-1)},
451 }
452 for _, tt := range tests {
453 t.Run(tt.Name, func(t *testing.T) {
454 _, err := Marshal(tt.in)
455 uve, ok := err.(*UnsupportedValueError)
456 if !ok {
457 t.Fatalf("%s: Marshal error:\n\tgot: %T\n\twant: %T", tt.Where, err, new(UnsupportedValueError))
458 }
459 got := uve.Value
460 want := reflect.ValueOf(tt.want)
461 if got.Type() != want.Type() {
462 t.Fatalf("%s: UnsupportedValueError.Value.Type = %v, want %v", tt.Where, got.Type(), want.Type())
463 }
464 equalFloat := func(x, y float64) bool {
465 return x == y || math.IsNaN(x) == math.IsNaN(y)
466 }
467 if !equalFloat(got.Float(), want.Float()) {
468 t.Fatalf("%s: UnsupportedValueError.Value.Float = %v, want %v", tt.Where, got.Float(), want.Float())
469 }
470 })
471 }
472 }
473
474
475 func TestMarshalTextFloatMap(t *testing.T) {
476 m := map[textfloat]string{
477 textfloat(math.NaN()): "1",
478 textfloat(math.NaN()): "1",
479 }
480 got, err := Marshal(m)
481 if err != nil {
482 t.Errorf("Marshal error: %v", err)
483 }
484 want := `{"TF:NaN":"1","TF:NaN":"1"}`
485 if string(got) != want {
486 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
487 }
488 }
489
490
491 type Ref int
492
493 func (*Ref) MarshalJSON() ([]byte, error) {
494 return []byte(`"ref"`), nil
495 }
496
497 func (r *Ref) UnmarshalJSON([]byte) error {
498 *r = 12
499 return nil
500 }
501
502
503 type Val int
504
505 func (Val) MarshalJSON() ([]byte, error) {
506 return []byte(`"val"`), nil
507 }
508
509
510 type RefText int
511
512 func (*RefText) MarshalText() ([]byte, error) {
513 return []byte(`"ref"`), nil
514 }
515
516 func (r *RefText) UnmarshalText([]byte) error {
517 *r = 13
518 return nil
519 }
520
521
522 type ValText int
523
524 func (ValText) MarshalText() ([]byte, error) {
525 return []byte(`"val"`), nil
526 }
527
528 func TestRefValMarshal(t *testing.T) {
529 var s = struct {
530 R0 Ref
531 R1 *Ref
532 R2 RefText
533 R3 *RefText
534 V0 Val
535 V1 *Val
536 V2 ValText
537 V3 *ValText
538 }{
539 R0: 12,
540 R1: new(Ref),
541 R2: 14,
542 R3: new(RefText),
543 V0: 13,
544 V1: new(Val),
545 V2: 15,
546 V3: new(ValText),
547 }
548 const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}`
549 b, err := Marshal(&s)
550 if err != nil {
551 t.Fatalf("Marshal error: %v", err)
552 }
553 if got := string(b); got != want {
554 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
555 }
556 }
557
558
559 type C int
560
561 func (C) MarshalJSON() ([]byte, error) {
562 return []byte(`"<&>"`), nil
563 }
564
565
566 type CText int
567
568 func (CText) MarshalText() ([]byte, error) {
569 return []byte(`"<&>"`), nil
570 }
571
572 func TestMarshalerEscaping(t *testing.T) {
573 var c C
574 want := `"\u003c\u0026\u003e"`
575 b, err := Marshal(c)
576 if err != nil {
577 t.Fatalf("Marshal error: %v", err)
578 }
579 if got := string(b); got != want {
580 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
581 }
582
583 var ct CText
584 want = `"\"\u003c\u0026\u003e\""`
585 b, err = Marshal(ct)
586 if err != nil {
587 t.Fatalf("Marshal error: %v", err)
588 }
589 if got := string(b); got != want {
590 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
591 }
592 }
593
594 func TestAnonymousFields(t *testing.T) {
595 tests := []struct {
596 CaseName
597 makeInput func() any
598 want string
599 }{{
600
601
602
603 CaseName: Name("AmbiguousField"),
604 makeInput: func() any {
605 type (
606 S1 struct{ x, X int }
607 S2 struct{ x, X int }
608 S struct {
609 S1
610 S2
611 }
612 )
613 return S{S1{1, 2}, S2{3, 4}}
614 },
615 want: `{}`,
616 }, {
617 CaseName: Name("DominantField"),
618
619
620 makeInput: func() any {
621 type (
622 S1 struct{ x, X int }
623 S2 struct{ x, X int }
624 S struct {
625 S1
626 S2
627 x, X int
628 }
629 )
630 return S{S1{1, 2}, S2{3, 4}, 5, 6}
631 },
632 want: `{"X":6}`,
633 }, {
634
635 CaseName: Name("UnexportedEmbeddedInt"),
636 makeInput: func() any {
637 type (
638 myInt int
639 S struct{ myInt }
640 )
641 return S{5}
642 },
643 want: `{}`,
644 }, {
645
646 CaseName: Name("ExportedEmbeddedInt"),
647 makeInput: func() any {
648 type (
649 MyInt int
650 S struct{ MyInt }
651 )
652 return S{5}
653 },
654 want: `{"MyInt":5}`,
655 }, {
656
657
658 CaseName: Name("UnexportedEmbeddedIntPointer"),
659 makeInput: func() any {
660 type (
661 myInt int
662 S struct{ *myInt }
663 )
664 s := S{new(myInt)}
665 *s.myInt = 5
666 return s
667 },
668 want: `{}`,
669 }, {
670
671
672 CaseName: Name("ExportedEmbeddedIntPointer"),
673 makeInput: func() any {
674 type (
675 MyInt int
676 S struct{ *MyInt }
677 )
678 s := S{new(MyInt)}
679 *s.MyInt = 5
680 return s
681 },
682 want: `{"MyInt":5}`,
683 }, {
684
685
686
687 CaseName: Name("EmbeddedStruct"),
688 makeInput: func() any {
689 type (
690 s1 struct{ x, X int }
691 S2 struct{ y, Y int }
692 S struct {
693 s1
694 S2
695 }
696 )
697 return S{s1{1, 2}, S2{3, 4}}
698 },
699 want: `{"X":2,"Y":4}`,
700 }, {
701
702
703
704 CaseName: Name("EmbeddedStructPointer"),
705 makeInput: func() any {
706 type (
707 s1 struct{ x, X int }
708 S2 struct{ y, Y int }
709 S struct {
710 *s1
711 *S2
712 }
713 )
714 return S{&s1{1, 2}, &S2{3, 4}}
715 },
716 want: `{"X":2,"Y":4}`,
717 }, {
718
719
720 CaseName: Name("NestedStructAndInts"),
721 makeInput: func() any {
722 type (
723 MyInt1 int
724 MyInt2 int
725 myInt int
726 s2 struct {
727 MyInt2
728 myInt
729 }
730 s1 struct {
731 MyInt1
732 myInt
733 s2
734 }
735 S struct {
736 s1
737 myInt
738 }
739 )
740 return S{s1{1, 2, s2{3, 4}}, 6}
741 },
742 want: `{"MyInt1":1,"MyInt2":3}`,
743 }, {
744
745
746
747 CaseName: Name("EmbeddedFieldBehindNilPointer"),
748 makeInput: func() any {
749 type (
750 S2 struct{ Field string }
751 S struct{ *S2 }
752 )
753 return S{}
754 },
755 want: `{}`,
756 }}
757
758 for _, tt := range tests {
759 t.Run(tt.Name, func(t *testing.T) {
760 b, err := Marshal(tt.makeInput())
761 if err != nil {
762 t.Fatalf("%s: Marshal error: %v", tt.Where, err)
763 }
764 if string(b) != tt.want {
765 t.Fatalf("%s: Marshal:\n\tgot: %s\n\twant: %s", tt.Where, b, tt.want)
766 }
767 })
768 }
769 }
770
771 type BugA struct {
772 S string
773 }
774
775 type BugB struct {
776 BugA
777 S string
778 }
779
780 type BugC struct {
781 S string
782 }
783
784
785 type BugX struct {
786 A int
787 BugA
788 BugB
789 }
790
791
792
793
794 type nilJSONMarshaler string
795
796 func (nm *nilJSONMarshaler) MarshalJSON() ([]byte, error) {
797 if nm == nil {
798 return Marshal("0zenil0")
799 }
800 return Marshal("zenil:" + string(*nm))
801 }
802
803
804
805
806 type nilTextMarshaler string
807
808 func (nm *nilTextMarshaler) MarshalText() ([]byte, error) {
809 if nm == nil {
810 return []byte("0zenil0"), nil
811 }
812 return []byte("zenil:" + string(*nm)), nil
813 }
814
815
816 func TestNilMarshal(t *testing.T) {
817 tests := []struct {
818 CaseName
819 in any
820 want string
821 }{
822 {Name(""), nil, `null`},
823 {Name(""), new(float64), `0`},
824 {Name(""), []any(nil), `null`},
825 {Name(""), []string(nil), `null`},
826 {Name(""), map[string]string(nil), `null`},
827 {Name(""), []byte(nil), `null`},
828 {Name(""), struct{ M string }{"gopher"}, `{"M":"gopher"}`},
829 {Name(""), struct{ M Marshaler }{}, `{"M":null}`},
830 {Name(""), struct{ M Marshaler }{(*nilJSONMarshaler)(nil)}, `{"M":"0zenil0"}`},
831 {Name(""), struct{ M any }{(*nilJSONMarshaler)(nil)}, `{"M":null}`},
832 {Name(""), struct{ M encoding.TextMarshaler }{}, `{"M":null}`},
833 {Name(""), struct{ M encoding.TextMarshaler }{(*nilTextMarshaler)(nil)}, `{"M":"0zenil0"}`},
834 {Name(""), struct{ M any }{(*nilTextMarshaler)(nil)}, `{"M":null}`},
835 }
836 for _, tt := range tests {
837 t.Run(tt.Name, func(t *testing.T) {
838 switch got, err := Marshal(tt.in); {
839 case err != nil:
840 t.Fatalf("%s: Marshal error: %v", tt.Where, err)
841 case string(got) != tt.want:
842 t.Fatalf("%s: Marshal:\n\tgot: %s\n\twant: %s", tt.Where, got, tt.want)
843 }
844 })
845 }
846 }
847
848
849 func TestEmbeddedBug(t *testing.T) {
850 v := BugB{
851 BugA{"A"},
852 "B",
853 }
854 b, err := Marshal(v)
855 if err != nil {
856 t.Fatal("Marshal error:", err)
857 }
858 want := `{"S":"B"}`
859 got := string(b)
860 if got != want {
861 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
862 }
863
864 x := BugX{
865 A: 23,
866 }
867 b, err = Marshal(x)
868 if err != nil {
869 t.Fatal("Marshal error:", err)
870 }
871 want = `{"A":23}`
872 got = string(b)
873 if got != want {
874 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
875 }
876 }
877
878 type BugD struct {
879 XXX string `json:"S"`
880 }
881
882
883 type BugY struct {
884 BugA
885 BugD
886 }
887
888
889 func TestTaggedFieldDominates(t *testing.T) {
890 v := BugY{
891 BugA{"BugA"},
892 BugD{"BugD"},
893 }
894 b, err := Marshal(v)
895 if err != nil {
896 t.Fatal("Marshal error:", err)
897 }
898 want := `{"S":"BugD"}`
899 got := string(b)
900 if got != want {
901 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
902 }
903 }
904
905
906 type BugZ struct {
907 BugA
908 BugC
909 BugY
910 }
911
912 func TestDuplicatedFieldDisappears(t *testing.T) {
913 v := BugZ{
914 BugA{"BugA"},
915 BugC{"BugC"},
916 BugY{
917 BugA{"nested BugA"},
918 BugD{"nested BugD"},
919 },
920 }
921 b, err := Marshal(v)
922 if err != nil {
923 t.Fatal("Marshal error:", err)
924 }
925 want := `{}`
926 got := string(b)
927 if got != want {
928 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
929 }
930 }
931
932 func TestIssue10281(t *testing.T) {
933 type Foo struct {
934 N Number
935 }
936 x := Foo{Number(`invalid`)}
937
938 if _, err := Marshal(&x); err == nil {
939 t.Fatalf("Marshal error: got nil, want non-nil")
940 }
941 }
942
943 func TestMarshalErrorAndReuseEncodeState(t *testing.T) {
944
945 percent := debug.SetGCPercent(-1)
946 defer debug.SetGCPercent(percent)
947
948
949 type Dummy struct {
950 Name string
951 Next *Dummy
952 }
953 dummy := Dummy{Name: "Dummy"}
954 dummy.Next = &dummy
955 if _, err := Marshal(dummy); err == nil {
956 t.Errorf("Marshal error: got nil, want non-nil")
957 }
958
959 type Data struct {
960 A string
961 I int
962 }
963 want := Data{A: "a", I: 1}
964 b, err := Marshal(want)
965 if err != nil {
966 t.Errorf("Marshal error: %v", err)
967 }
968
969 var got Data
970 if err := Unmarshal(b, &got); err != nil {
971 t.Errorf("Unmarshal error: %v", err)
972 }
973 if got != want {
974 t.Errorf("Unmarshal:\n\tgot: %v\n\twant: %v", got, want)
975 }
976 }
977
978 func TestHTMLEscape(t *testing.T) {
979 var b, want bytes.Buffer
980 m := `{"M":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}`
981 want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`))
982 HTMLEscape(&b, []byte(m))
983 if !bytes.Equal(b.Bytes(), want.Bytes()) {
984 t.Errorf("HTMLEscape:\n\tgot: %s\n\twant: %s", b.Bytes(), want.Bytes())
985 }
986 }
987
988
989 func TestEncodePointerString(t *testing.T) {
990 type stringPointer struct {
991 N *int64 `json:"n,string"`
992 }
993 var n int64 = 42
994 b, err := Marshal(stringPointer{N: &n})
995 if err != nil {
996 t.Fatalf("Marshal error: %v", err)
997 }
998 if got, want := string(b), `{"n":"42"}`; got != want {
999 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
1000 }
1001 var back stringPointer
1002 switch err = Unmarshal(b, &back); {
1003 case err != nil:
1004 t.Fatalf("Unmarshal error: %v", err)
1005 case back.N == nil:
1006 t.Fatalf("Unmarshal: back.N = nil, want non-nil")
1007 case *back.N != 42:
1008 t.Fatalf("Unmarshal: *back.N = %d, want 42", *back.N)
1009 }
1010 }
1011
1012 var encodeStringTests = []struct {
1013 in string
1014 out string
1015 }{
1016 {"\x00", `"\u0000"`},
1017 {"\x01", `"\u0001"`},
1018 {"\x02", `"\u0002"`},
1019 {"\x03", `"\u0003"`},
1020 {"\x04", `"\u0004"`},
1021 {"\x05", `"\u0005"`},
1022 {"\x06", `"\u0006"`},
1023 {"\x07", `"\u0007"`},
1024 {"\x08", `"\b"`},
1025 {"\x09", `"\t"`},
1026 {"\x0a", `"\n"`},
1027 {"\x0b", `"\u000b"`},
1028 {"\x0c", `"\f"`},
1029 {"\x0d", `"\r"`},
1030 {"\x0e", `"\u000e"`},
1031 {"\x0f", `"\u000f"`},
1032 {"\x10", `"\u0010"`},
1033 {"\x11", `"\u0011"`},
1034 {"\x12", `"\u0012"`},
1035 {"\x13", `"\u0013"`},
1036 {"\x14", `"\u0014"`},
1037 {"\x15", `"\u0015"`},
1038 {"\x16", `"\u0016"`},
1039 {"\x17", `"\u0017"`},
1040 {"\x18", `"\u0018"`},
1041 {"\x19", `"\u0019"`},
1042 {"\x1a", `"\u001a"`},
1043 {"\x1b", `"\u001b"`},
1044 {"\x1c", `"\u001c"`},
1045 {"\x1d", `"\u001d"`},
1046 {"\x1e", `"\u001e"`},
1047 {"\x1f", `"\u001f"`},
1048 }
1049
1050 func TestEncodeString(t *testing.T) {
1051 for _, tt := range encodeStringTests {
1052 b, err := Marshal(tt.in)
1053 if err != nil {
1054 t.Errorf("Marshal(%q) error: %v", tt.in, err)
1055 continue
1056 }
1057 out := string(b)
1058 if out != tt.out {
1059 t.Errorf("Marshal(%q) = %#q, want %#q", tt.in, out, tt.out)
1060 }
1061 }
1062 }
1063
1064 type jsonbyte byte
1065
1066 func (b jsonbyte) MarshalJSON() ([]byte, error) { return tenc(`{"JB":%d}`, b) }
1067
1068 type textbyte byte
1069
1070 func (b textbyte) MarshalText() ([]byte, error) { return tenc(`TB:%d`, b) }
1071
1072 type jsonint int
1073
1074 func (i jsonint) MarshalJSON() ([]byte, error) { return tenc(`{"JI":%d}`, i) }
1075
1076 type textint int
1077
1078 func (i textint) MarshalText() ([]byte, error) { return tenc(`TI:%d`, i) }
1079
1080 func tenc(format string, a ...any) ([]byte, error) {
1081 var buf bytes.Buffer
1082 fmt.Fprintf(&buf, format, a...)
1083 return buf.Bytes(), nil
1084 }
1085
1086 type textfloat float64
1087
1088 func (f textfloat) MarshalText() ([]byte, error) { return tenc(`TF:%0.2f`, f) }
1089
1090
1091 func TestEncodeBytekind(t *testing.T) {
1092 tests := []struct {
1093 CaseName
1094 in any
1095 want string
1096 }{
1097 {Name(""), byte(7), "7"},
1098 {Name(""), jsonbyte(7), `{"JB":7}`},
1099 {Name(""), textbyte(4), `"TB:4"`},
1100 {Name(""), jsonint(5), `{"JI":5}`},
1101 {Name(""), textint(1), `"TI:1"`},
1102 {Name(""), []byte{0, 1}, `"AAE="`},
1103 {Name(""), []jsonbyte{0, 1}, `[{"JB":0},{"JB":1}]`},
1104 {Name(""), [][]jsonbyte{{0, 1}, {3}}, `[[{"JB":0},{"JB":1}],[{"JB":3}]]`},
1105 {Name(""), []textbyte{2, 3}, `["TB:2","TB:3"]`},
1106 {Name(""), []jsonint{5, 4}, `[{"JI":5},{"JI":4}]`},
1107 {Name(""), []textint{9, 3}, `["TI:9","TI:3"]`},
1108 {Name(""), []int{9, 3}, `[9,3]`},
1109 {Name(""), []textfloat{12, 3}, `["TF:12.00","TF:3.00"]`},
1110 }
1111 for _, tt := range tests {
1112 t.Run(tt.Name, func(t *testing.T) {
1113 b, err := Marshal(tt.in)
1114 if err != nil {
1115 t.Errorf("%s: Marshal error: %v", tt.Where, err)
1116 }
1117 got, want := string(b), tt.want
1118 if got != want {
1119 t.Errorf("%s: Marshal:\n\tgot: %s\n\twant: %s", tt.Where, got, want)
1120 }
1121 })
1122 }
1123 }
1124
1125 func TestTextMarshalerMapKeysAreSorted(t *testing.T) {
1126 got, err := Marshal(map[unmarshalerText]int{
1127 {"x", "y"}: 1,
1128 {"y", "x"}: 2,
1129 {"a", "z"}: 3,
1130 {"z", "a"}: 4,
1131 })
1132 if err != nil {
1133 t.Fatalf("Marshal error: %v", err)
1134 }
1135 const want = `{"a:z":3,"x:y":1,"y:x":2,"z:a":4}`
1136 if string(got) != want {
1137 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
1138 }
1139 }
1140
1141
1142 func TestNilMarshalerTextMapKey(t *testing.T) {
1143 got, err := Marshal(map[*unmarshalerText]int{
1144 (*unmarshalerText)(nil): 1,
1145 {"A", "B"}: 2,
1146 })
1147 if err != nil {
1148 t.Fatalf("Marshal error: %v", err)
1149 }
1150 const want = `{"":1,"A:B":2}`
1151 if string(got) != want {
1152 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
1153 }
1154 }
1155
1156
1157 type textMarshalerString string
1158
1159 func (s textMarshalerString) MarshalText() ([]byte, error) {
1160 return []byte("X_" + string(s)), nil
1161 }
1162
1163 func (s textMarshalerString) AppendText(b []byte) ([]byte, error) {
1164 return append(b, ("X_" + string(s))...), nil
1165 }
1166
1167
1168
1169 func TestStringKindTextMarshalerMapKey(t *testing.T) {
1170 got, err := Marshal(map[textMarshalerString]textMarshalerString{"foo": "bar"})
1171 if err != nil {
1172 t.Fatalf("Marshal error: %v", err)
1173 }
1174 const want = `{"foo":"X_bar"}`
1175 if string(got) != want {
1176 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
1177 }
1178 }
1179
1180 var re = regexp.MustCompile
1181
1182
1183 var badFloatREs = []*regexp.Regexp{
1184 re(`p`),
1185 re(`^\+`),
1186 re(`^-?0[^.]`),
1187 re(`^-?\.`),
1188 re(`\.(e|$)`),
1189 re(`\.[0-9]+0(e|$)`),
1190 re(`^-?(0|[0-9]{2,})\..*e`),
1191 re(`e[0-9]`),
1192 re(`e[+-]0`),
1193 re(`e-[1-6]$`),
1194 re(`e+(.|1.|20)$`),
1195 re(`^-?0\.0000000`),
1196 re(`^-?[0-9]{22}`),
1197 re(`[1-9][0-9]{16}[1-9]`),
1198 re(`[1-9][0-9.]{17}[1-9]`),
1199
1200 re(`[1-9][0-9]{8}[1-9]`),
1201 re(`[1-9][0-9.]{9}[1-9]`),
1202 }
1203
1204 func TestMarshalFloat(t *testing.T) {
1205 t.Parallel()
1206 nfail := 0
1207 test := func(f float64, bits int) {
1208 vf := any(f)
1209 if bits == 32 {
1210 f = float64(float32(f))
1211 vf = float32(f)
1212 }
1213 bout, err := Marshal(vf)
1214 if err != nil {
1215 t.Errorf("Marshal(%T(%g)) error: %v", vf, vf, err)
1216 nfail++
1217 return
1218 }
1219 out := string(bout)
1220
1221
1222 g, err := strconv.ParseFloat(out, bits)
1223 if err != nil {
1224 t.Errorf("ParseFloat(%q) error: %v", out, err)
1225 nfail++
1226 return
1227 }
1228 if f != g || fmt.Sprint(f) != fmt.Sprint(g) {
1229 t.Errorf("ParseFloat(%q):\n\tgot: %g\n\twant: %g", out, float32(g), vf)
1230 nfail++
1231 return
1232 }
1233
1234 bad := badFloatREs
1235 if bits == 64 {
1236 bad = bad[:len(bad)-2]
1237 }
1238 for _, re := range bad {
1239 if re.MatchString(out) {
1240 t.Errorf("Marshal(%T(%g)) = %q; must not match /%s/", vf, vf, out, re)
1241 nfail++
1242 return
1243 }
1244 }
1245 }
1246
1247 var (
1248 bigger = math.Inf(+1)
1249 smaller = math.Inf(-1)
1250 )
1251
1252 var digits = "1.2345678901234567890123"
1253 for i := len(digits); i >= 2; i-- {
1254 if testing.Short() && i < len(digits)-4 {
1255 break
1256 }
1257 for exp := -30; exp <= 30; exp++ {
1258 for _, sign := range "+-" {
1259 for bits := 32; bits <= 64; bits += 32 {
1260 s := fmt.Sprintf("%c%se%d", sign, digits[:i], exp)
1261 f, err := strconv.ParseFloat(s, bits)
1262 if err != nil {
1263 log.Fatal(err)
1264 }
1265 next := math.Nextafter
1266 if bits == 32 {
1267 next = func(g, h float64) float64 {
1268 return float64(math.Nextafter32(float32(g), float32(h)))
1269 }
1270 }
1271 test(f, bits)
1272 test(next(f, bigger), bits)
1273 test(next(f, smaller), bits)
1274 if nfail > 50 {
1275 t.Fatalf("stopping test early")
1276 }
1277 }
1278 }
1279 }
1280 }
1281 test(0, 64)
1282 test(math.Copysign(0, -1), 64)
1283 test(0, 32)
1284 test(math.Copysign(0, -1), 32)
1285 }
1286
1287 func TestMarshalRawMessageValue(t *testing.T) {
1288 type (
1289 T1 struct {
1290 M RawMessage `json:",omitempty"`
1291 }
1292 T2 struct {
1293 M *RawMessage `json:",omitempty"`
1294 }
1295 )
1296
1297 var (
1298 rawNil = RawMessage(nil)
1299 rawEmpty = RawMessage([]byte{})
1300 rawText = RawMessage([]byte(`"foo"`))
1301 )
1302
1303 tests := []struct {
1304 CaseName
1305 in any
1306 want string
1307 ok bool
1308 }{
1309
1310 {Name(""), rawNil, "null", true},
1311 {Name(""), &rawNil, "null", true},
1312 {Name(""), []any{rawNil}, "[null]", true},
1313 {Name(""), &[]any{rawNil}, "[null]", true},
1314 {Name(""), []any{&rawNil}, "[null]", true},
1315 {Name(""), &[]any{&rawNil}, "[null]", true},
1316 {Name(""), struct{ M RawMessage }{rawNil}, `{"M":null}`, true},
1317 {Name(""), &struct{ M RawMessage }{rawNil}, `{"M":null}`, true},
1318 {Name(""), struct{ M *RawMessage }{&rawNil}, `{"M":null}`, true},
1319 {Name(""), &struct{ M *RawMessage }{&rawNil}, `{"M":null}`, true},
1320 {Name(""), map[string]any{"M": rawNil}, `{"M":null}`, true},
1321 {Name(""), &map[string]any{"M": rawNil}, `{"M":null}`, true},
1322 {Name(""), map[string]any{"M": &rawNil}, `{"M":null}`, true},
1323 {Name(""), &map[string]any{"M": &rawNil}, `{"M":null}`, true},
1324 {Name(""), T1{rawNil}, "{}", true},
1325 {Name(""), T2{&rawNil}, `{"M":null}`, true},
1326 {Name(""), &T1{rawNil}, "{}", true},
1327 {Name(""), &T2{&rawNil}, `{"M":null}`, true},
1328
1329
1330 {Name(""), rawEmpty, "", false},
1331 {Name(""), &rawEmpty, "", false},
1332 {Name(""), []any{rawEmpty}, "", false},
1333 {Name(""), &[]any{rawEmpty}, "", false},
1334 {Name(""), []any{&rawEmpty}, "", false},
1335 {Name(""), &[]any{&rawEmpty}, "", false},
1336 {Name(""), struct{ X RawMessage }{rawEmpty}, "", false},
1337 {Name(""), &struct{ X RawMessage }{rawEmpty}, "", false},
1338 {Name(""), struct{ X *RawMessage }{&rawEmpty}, "", false},
1339 {Name(""), &struct{ X *RawMessage }{&rawEmpty}, "", false},
1340 {Name(""), map[string]any{"nil": rawEmpty}, "", false},
1341 {Name(""), &map[string]any{"nil": rawEmpty}, "", false},
1342 {Name(""), map[string]any{"nil": &rawEmpty}, "", false},
1343 {Name(""), &map[string]any{"nil": &rawEmpty}, "", false},
1344 {Name(""), T1{rawEmpty}, "{}", true},
1345 {Name(""), T2{&rawEmpty}, "", false},
1346 {Name(""), &T1{rawEmpty}, "{}", true},
1347 {Name(""), &T2{&rawEmpty}, "", false},
1348
1349
1350
1351
1352
1353
1354 {Name(""), rawText, `"foo"`, true},
1355 {Name(""), &rawText, `"foo"`, true},
1356 {Name(""), []any{rawText}, `["foo"]`, true},
1357 {Name(""), &[]any{rawText}, `["foo"]`, true},
1358 {Name(""), []any{&rawText}, `["foo"]`, true},
1359 {Name(""), &[]any{&rawText}, `["foo"]`, true},
1360 {Name(""), struct{ M RawMessage }{rawText}, `{"M":"foo"}`, true},
1361 {Name(""), &struct{ M RawMessage }{rawText}, `{"M":"foo"}`, true},
1362 {Name(""), struct{ M *RawMessage }{&rawText}, `{"M":"foo"}`, true},
1363 {Name(""), &struct{ M *RawMessage }{&rawText}, `{"M":"foo"}`, true},
1364 {Name(""), map[string]any{"M": rawText}, `{"M":"foo"}`, true},
1365 {Name(""), &map[string]any{"M": rawText}, `{"M":"foo"}`, true},
1366 {Name(""), map[string]any{"M": &rawText}, `{"M":"foo"}`, true},
1367 {Name(""), &map[string]any{"M": &rawText}, `{"M":"foo"}`, true},
1368 {Name(""), T1{rawText}, `{"M":"foo"}`, true},
1369 {Name(""), T2{&rawText}, `{"M":"foo"}`, true},
1370 {Name(""), &T1{rawText}, `{"M":"foo"}`, true},
1371 {Name(""), &T2{&rawText}, `{"M":"foo"}`, true},
1372 }
1373
1374 for _, tt := range tests {
1375 t.Run(tt.Name, func(t *testing.T) {
1376 b, err := Marshal(tt.in)
1377 if ok := (err == nil); ok != tt.ok {
1378 if err != nil {
1379 t.Errorf("%s: Marshal error: %v", tt.Where, err)
1380 } else {
1381 t.Errorf("%s: Marshal error: got nil, want non-nil", tt.Where)
1382 }
1383 }
1384 if got := string(b); got != tt.want {
1385 t.Errorf("%s: Marshal:\n\tinput: %#v\n\tgot: %s\n\twant: %s", tt.Where, tt.in, got, tt.want)
1386 }
1387 })
1388 }
1389 }
1390
1391 type marshalPanic struct{}
1392
1393 func (marshalPanic) MarshalJSON() ([]byte, error) { panic(0xdead) }
1394
1395 func TestMarshalPanic(t *testing.T) {
1396 defer func() {
1397 if got := recover(); !reflect.DeepEqual(got, 0xdead) {
1398 t.Errorf("panic() = (%T)(%v), want 0xdead", got, got)
1399 }
1400 }()
1401 Marshal(&marshalPanic{})
1402 t.Error("Marshal should have panicked")
1403 }
1404
1405 func TestMarshalUncommonFieldNames(t *testing.T) {
1406 v := struct {
1407 A0, À, Aβ int
1408 }{}
1409 b, err := Marshal(v)
1410 if err != nil {
1411 t.Fatal("Marshal error:", err)
1412 }
1413 want := `{"A0":0,"À":0,"Aβ":0}`
1414 got := string(b)
1415 if got != want {
1416 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
1417 }
1418 }
1419
1420 func TestMarshalerError(t *testing.T) {
1421 s := "test variable"
1422 st := reflect.TypeOf(s)
1423 const errText = "json: test error"
1424
1425 tests := []struct {
1426 CaseName
1427 err *MarshalerError
1428 want string
1429 }{{
1430 Name(""),
1431 &MarshalerError{st, fmt.Errorf(errText), ""},
1432 "json: error calling MarshalJSON for type " + st.String() + ": " + errText,
1433 }, {
1434 Name(""),
1435 &MarshalerError{st, fmt.Errorf(errText), "TestMarshalerError"},
1436 "json: error calling TestMarshalerError for type " + st.String() + ": " + errText,
1437 }}
1438
1439 for _, tt := range tests {
1440 t.Run(tt.Name, func(t *testing.T) {
1441 got := tt.err.Error()
1442 if got != tt.want {
1443 t.Errorf("%s: Error:\n\tgot: %s\n\twant: %s", tt.Where, got, tt.want)
1444 }
1445 })
1446 }
1447 }
1448
1449 type marshaledValue string
1450
1451 func (v marshaledValue) MarshalJSON() ([]byte, error) {
1452 return []byte(v), nil
1453 }
1454
1455 func TestIssue63379(t *testing.T) {
1456 for _, v := range []string{
1457 "[]<",
1458 "[]>",
1459 "[]&",
1460 "[]\u2028",
1461 "[]\u2029",
1462 "{}<",
1463 "{}>",
1464 "{}&",
1465 "{}\u2028",
1466 "{}\u2029",
1467 } {
1468 _, err := Marshal(marshaledValue(v))
1469 if err == nil {
1470 t.Errorf("expected error for %q", v)
1471 }
1472 }
1473 }
1474
1475
1476
1477
1478 func TestSynctestMarshal(t *testing.T) {
1479 var wg sync.WaitGroup
1480 for range 5 {
1481 wg.Go(func() {
1482 synctest.Test(t, func(t *testing.T) {
1483 _, err := Marshal([]string{})
1484 if err != nil {
1485 t.Errorf("Marshal: %v", err)
1486 }
1487 })
1488 })
1489 }
1490 wg.Wait()
1491 }
1492
View as plain text