codekingpro/portable-devtools
114k
1// Copyright 2011 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5//go:build !goexperiment.jsonv26 7package json8 9import (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 25type OptionalsEmpty struct {26 Sr string `json:"sr"`27 So string `json:"so,omitempty"`28 Sw string `json:"-"`29 30 Ir int `json:"omitempty"` // actually named omitempty, not an option31 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 52func 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 OptionalsEmpty65 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 78type NonZeroStruct struct{}79 80func (nzs NonZeroStruct) IsZero() bool {81 return false82}83 84type NoPanicStruct struct {85 Int int `json:"int,omitzero"`86}87 88func (nps *NoPanicStruct) IsZero() bool {89 return nps.Int != 090}91 92type OptionalsZero struct {93 Sr string `json:"sr"`94 So string `json:"so,omitzero"`95 Sw string `json:"-"`96 97 Ir int `json:"omitzero"` // actually named omitzero, not an option98 Io int `json:"io,omitzero"`99 100 Slr []string `json:"slr,random"`101 Slo []string `json:"slo,omitzero"`102 SloNonNil []string `json:"slononnil,omitzero"`103 104 Mr map[string]any `json:"mr"`105 Mo map[string]any `json:",omitzero"`106 Moo map[string]any `json:"moo,omitzero"`107 108 Fr float64 `json:"fr"`109 Fo float64 `json:"fo,omitzero"`110 Foo float64 `json:"foo,omitzero"`111 Foo2 [2]float64 `json:"foo2,omitzero"`112 113 Br bool `json:"br"`114 Bo bool `json:"bo,omitzero"`115 116 Ur uint `json:"ur"`117 Uo uint `json:"uo,omitzero"`118 119 Str struct{} `json:"str"`120 Sto struct{} `json:"sto,omitzero"`121 122 Time time.Time `json:"time,omitzero"`123 TimeLocal time.Time `json:"timelocal,omitzero"`124 Nzs NonZeroStruct `json:"nzs,omitzero"`125 126 NilIsZeroer isZeroer `json:"niliszeroer,omitzero"` // nil interface127 NonNilIsZeroer isZeroer `json:"nonniliszeroer,omitzero"` // non-nil interface128 NoPanicStruct0 isZeroer `json:"nps0,omitzero"` // non-nil interface with nil pointer129 NoPanicStruct1 isZeroer `json:"nps1,omitzero"` // non-nil interface with non-nil pointer130 NoPanicStruct2 *NoPanicStruct `json:"nps2,omitzero"` // nil pointer131 NoPanicStruct3 *NoPanicStruct `json:"nps3,omitzero"` // non-nil pointer132 NoPanicStruct4 NoPanicStruct `json:"nps4,omitzero"` // concrete type133}134 135func TestOmitZero(t *testing.T) {136 const want = `{137 "sr": "",138 "omitzero": 0,139 "slr": null,140 "slononnil": [],141 "mr": {},142 "Mo": {},143 "fr": 0,144 "br": false,145 "ur": 0,146 "str": {},147 "nzs": {},148 "nps1": {},149 "nps3": {},150 "nps4": {}151}`152 var o OptionalsZero153 o.Sw = "something"154 o.SloNonNil = make([]string, 0)155 o.Mr = map[string]any{}156 o.Mo = map[string]any{}157 158 o.Foo = -0159 o.Foo2 = [2]float64{+0, -0}160 161 o.TimeLocal = time.Time{}.Local()162 163 o.NonNilIsZeroer = time.Time{}164 o.NoPanicStruct0 = (*NoPanicStruct)(nil)165 o.NoPanicStruct1 = &NoPanicStruct{}166 o.NoPanicStruct3 = &NoPanicStruct{}167 168 got, err := MarshalIndent(&o, "", " ")169 if err != nil {170 t.Fatalf("MarshalIndent error: %v", err)171 }172 if got := string(got); got != want {173 t.Errorf("MarshalIndent:\n\tgot: %s\n\twant: %s\n", indentNewlines(got), indentNewlines(want))174 }175}176 177func TestOmitZeroMap(t *testing.T) {178 const want = `{179 "foo": {180 "sr": "",181 "omitzero": 0,182 "slr": null,183 "mr": null,184 "fr": 0,185 "br": false,186 "ur": 0,187 "str": {},188 "nzs": {},189 "nps4": {}190 }191}`192 m := map[string]OptionalsZero{"foo": {}}193 got, err := MarshalIndent(m, "", " ")194 if err != nil {195 t.Fatalf("MarshalIndent error: %v", err)196 }197 if got := string(got); got != want {198 fmt.Println(got)199 t.Errorf("MarshalIndent:\n\tgot: %s\n\twant: %s\n", indentNewlines(got), indentNewlines(want))200 }201}202 203type OptionalsEmptyZero struct {204 Sr string `json:"sr"`205 So string `json:"so,omitempty,omitzero"`206 Sw string `json:"-"`207 208 Io int `json:"io,omitempty,omitzero"`209 210 Slr []string `json:"slr,random"`211 Slo []string `json:"slo,omitempty,omitzero"`212 SloNonNil []string `json:"slononnil,omitempty,omitzero"`213 214 Mr map[string]any `json:"mr"`215 Mo map[string]any `json:",omitempty,omitzero"`216 217 Fr float64 `json:"fr"`218 Fo float64 `json:"fo,omitempty,omitzero"`219 220 Br bool `json:"br"`221 Bo bool `json:"bo,omitempty,omitzero"`222 223 Ur uint `json:"ur"`224 Uo uint `json:"uo,omitempty,omitzero"`225 226 Str struct{} `json:"str"`227 Sto struct{} `json:"sto,omitempty,omitzero"`228 229 Time time.Time `json:"time,omitempty,omitzero"`230 Nzs NonZeroStruct `json:"nzs,omitempty,omitzero"`231}232 233func TestOmitEmptyZero(t *testing.T) {234 const want = `{235 "sr": "",236 "slr": null,237 "mr": {},238 "fr": 0,239 "br": false,240 "ur": 0,241 "str": {},242 "nzs": {}243}`244 var o OptionalsEmptyZero245 o.Sw = "something"246 o.SloNonNil = make([]string, 0)247 o.Mr = map[string]any{}248 o.Mo = map[string]any{}249 250 got, err := MarshalIndent(&o, "", " ")251 if err != nil {252 t.Fatalf("MarshalIndent error: %v", err)253 }254 if got := string(got); got != want {255 t.Errorf("MarshalIndent:\n\tgot: %s\n\twant: %s\n", indentNewlines(got), indentNewlines(want))256 }257}258 259type StringTag struct {260 BoolStr bool `json:",string"`261 IntStr int64 `json:",string"`262 UintptrStr uintptr `json:",string"`263 StrStr string `json:",string"`264 NumberStr Number `json:",string"`265}266 267func TestRoundtripStringTag(t *testing.T) {268 tests := []struct {269 CaseName270 in StringTag271 want string // empty to just test that we roundtrip272 }{{273 CaseName: Name("AllTypes"),274 in: StringTag{275 BoolStr: true,276 IntStr: 42,277 UintptrStr: 44,278 StrStr: "xzbit",279 NumberStr: "46",280 },281 want: `{282 "BoolStr": "true",283 "IntStr": "42",284 "UintptrStr": "44",285 "StrStr": "\"xzbit\"",286 "NumberStr": "46"287}`,288 }, {289 // See golang.org/issues/38173.290 CaseName: Name("StringDoubleEscapes"),291 in: StringTag{292 StrStr: "\b\f\n\r\t\"\\",293 NumberStr: "0", // just to satisfy the roundtrip294 },295 want: `{296 "BoolStr": "false",297 "IntStr": "0",298 "UintptrStr": "0",299 "StrStr": "\"\\b\\f\\n\\r\\t\\\"\\\\\"",300 "NumberStr": "0"301}`,302 }}303 for _, tt := range tests {304 t.Run(tt.Name, func(t *testing.T) {305 got, err := MarshalIndent(&tt.in, "", "\t")306 if err != nil {307 t.Fatalf("%s: MarshalIndent error: %v", tt.Where, err)308 }309 if got := string(got); got != tt.want {310 t.Fatalf("%s: MarshalIndent:\n\tgot: %s\n\twant: %s", tt.Where, stripWhitespace(got), stripWhitespace(tt.want))311 }312 313 // Verify that it round-trips.314 var s2 StringTag315 if err := Unmarshal(got, &s2); err != nil {316 t.Fatalf("%s: Decode error: %v", tt.Where, err)317 }318 if !reflect.DeepEqual(s2, tt.in) {319 t.Fatalf("%s: Decode:\n\tinput: %s\n\tgot: %#v\n\twant: %#v", tt.Where, indentNewlines(string(got)), s2, tt.in)320 }321 })322 }323}324 325// byte slices are special even if they're renamed types.326type renamedByte byte327type renamedByteSlice []byte328type renamedRenamedByteSlice []renamedByte329 330func TestEncodeRenamedByteSlice(t *testing.T) {331 s := renamedByteSlice("abc")332 got, err := Marshal(s)333 if err != nil {334 t.Fatalf("Marshal error: %v", err)335 }336 want := `"YWJj"`337 if string(got) != want {338 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)339 }340 r := renamedRenamedByteSlice("abc")341 got, err = Marshal(r)342 if err != nil {343 t.Fatalf("Marshal error: %v", err)344 }345 if string(got) != want {346 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)347 }348}349 350type SamePointerNoCycle struct {351 Ptr1, Ptr2 *SamePointerNoCycle352}353 354var samePointerNoCycle = &SamePointerNoCycle{}355 356type PointerCycle struct {357 Ptr *PointerCycle358}359 360var pointerCycle = &PointerCycle{}361 362type PointerCycleIndirect struct {363 Ptrs []any364}365 366type RecursiveSlice []RecursiveSlice367 368var (369 pointerCycleIndirect = &PointerCycleIndirect{}370 mapCycle = make(map[string]any)371 sliceCycle = []any{nil}372 sliceNoCycle = []any{nil, nil}373 recursiveSliceCycle = []RecursiveSlice{nil}374)375 376func init() {377 ptr := &SamePointerNoCycle{}378 samePointerNoCycle.Ptr1 = ptr379 samePointerNoCycle.Ptr2 = ptr380 381 pointerCycle.Ptr = pointerCycle382 pointerCycleIndirect.Ptrs = []any{pointerCycleIndirect}383 384 mapCycle["x"] = mapCycle385 sliceCycle[0] = sliceCycle386 sliceNoCycle[1] = sliceNoCycle[:1]387 for i := startDetectingCyclesAfter; i > 0; i-- {388 sliceNoCycle = []any{sliceNoCycle}389 }390 recursiveSliceCycle[0] = recursiveSliceCycle391}392 393func TestSamePointerNoCycle(t *testing.T) {394 if _, err := Marshal(samePointerNoCycle); err != nil {395 t.Fatalf("Marshal error: %v", err)396 }397}398 399func TestSliceNoCycle(t *testing.T) {400 if _, err := Marshal(sliceNoCycle); err != nil {401 t.Fatalf("Marshal error: %v", err)402 }403}404 405func TestUnsupportedValues(t *testing.T) {406 tests := []struct {407 CaseName408 in any409 }{410 {Name(""), math.NaN()},411 {Name(""), math.Inf(-1)},412 {Name(""), math.Inf(1)},413 {Name(""), pointerCycle},414 {Name(""), pointerCycleIndirect},415 {Name(""), mapCycle},416 {Name(""), sliceCycle},417 {Name(""), recursiveSliceCycle},418 }419 for _, tt := range tests {420 t.Run(tt.Name, func(t *testing.T) {421 if _, err := Marshal(tt.in); err != nil {422 if _, ok := err.(*UnsupportedValueError); !ok {423 t.Errorf("%s: Marshal error:\n\tgot: %T\n\twant: %T", tt.Where, err, new(UnsupportedValueError))424 }425 } else {426 t.Errorf("%s: Marshal error: got nil, want non-nil", tt.Where)427 }428 })429 }430}431 432// Issue 43207433func TestMarshalTextFloatMap(t *testing.T) {434 m := map[textfloat]string{435 textfloat(math.NaN()): "1",436 textfloat(math.NaN()): "1",437 }438 got, err := Marshal(m)439 if err != nil {440 t.Errorf("Marshal error: %v", err)441 }442 want := `{"TF:NaN":"1","TF:NaN":"1"}`443 if string(got) != want {444 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)445 }446}447 448// Ref has Marshaler and Unmarshaler methods with pointer receiver.449type Ref int450 451func (*Ref) MarshalJSON() ([]byte, error) {452 return []byte(`"ref"`), nil453}454 455func (r *Ref) UnmarshalJSON([]byte) error {456 *r = 12457 return nil458}459 460// Val has Marshaler methods with value receiver.461type Val int462 463func (Val) MarshalJSON() ([]byte, error) {464 return []byte(`"val"`), nil465}466 467// RefText has Marshaler and Unmarshaler methods with pointer receiver.468type RefText int469 470func (*RefText) MarshalText() ([]byte, error) {471 return []byte(`"ref"`), nil472}473 474func (r *RefText) UnmarshalText([]byte) error {475 *r = 13476 return nil477}478 479// ValText has Marshaler methods with value receiver.480type ValText int481 482func (ValText) MarshalText() ([]byte, error) {483 return []byte(`"val"`), nil484}485 486func TestRefValMarshal(t *testing.T) {487 var s = struct {488 R0 Ref489 R1 *Ref490 R2 RefText491 R3 *RefText492 V0 Val493 V1 *Val494 V2 ValText495 V3 *ValText496 }{497 R0: 12,498 R1: new(Ref),499 R2: 14,500 R3: new(RefText),501 V0: 13,502 V1: new(Val),503 V2: 15,504 V3: new(ValText),505 }506 const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}`507 b, err := Marshal(&s)508 if err != nil {509 t.Fatalf("Marshal error: %v", err)510 }511 if got := string(b); got != want {512 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)513 }514}515 516// C implements Marshaler and returns unescaped JSON.517type C int518 519func (C) MarshalJSON() ([]byte, error) {520 return []byte(`"<&>"`), nil521}522 523// CText implements Marshaler and returns unescaped text.524type CText int525 526func (CText) MarshalText() ([]byte, error) {527 return []byte(`"<&>"`), nil528}529 530func TestMarshalerEscaping(t *testing.T) {531 var c C532 want := `"\u003c\u0026\u003e"`533 b, err := Marshal(c)534 if err != nil {535 t.Fatalf("Marshal error: %v", err)536 }537 if got := string(b); got != want {538 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)539 }540 541 var ct CText542 want = `"\"\u003c\u0026\u003e\""`543 b, err = Marshal(ct)544 if err != nil {545 t.Fatalf("Marshal error: %v", err)546 }547 if got := string(b); got != want {548 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)549 }550}551 552func TestAnonymousFields(t *testing.T) {553 tests := []struct {554 CaseName555 makeInput func() any // Function to create input value556 want string // Expected JSON output557 }{{558 // Both S1 and S2 have a field named X. From the perspective of S,559 // it is ambiguous which one X refers to.560 // This should not serialize either field.561 CaseName: Name("AmbiguousField"),562 makeInput: func() any {563 type (564 S1 struct{ x, X int }565 S2 struct{ x, X int }566 S struct {567 S1568 S2569 }570 )571 return S{S1{1, 2}, S2{3, 4}}572 },573 want: `{}`,574 }, {575 CaseName: Name("DominantField"),576 // Both S1 and S2 have a field named X, but since S has an X field as577 // well, it takes precedence over S1.X and S2.X.578 makeInput: func() any {579 type (580 S1 struct{ x, X int }581 S2 struct{ x, X int }582 S struct {583 S1584 S2585 x, X int586 }587 )588 return S{S1{1, 2}, S2{3, 4}, 5, 6}589 },590 want: `{"X":6}`,591 }, {592 // Unexported embedded field of non-struct type should not be serialized.593 CaseName: Name("UnexportedEmbeddedInt"),594 makeInput: func() any {595 type (596 myInt int597 S struct{ myInt }598 )599 return S{5}600 },601 want: `{}`,602 }, {603 // Exported embedded field of non-struct type should be serialized.604 CaseName: Name("ExportedEmbeddedInt"),605 makeInput: func() any {606 type (607 MyInt int608 S struct{ MyInt }609 )610 return S{5}611 },612 want: `{"MyInt":5}`,613 }, {614 // Unexported embedded field of pointer to non-struct type615 // should not be serialized.616 CaseName: Name("UnexportedEmbeddedIntPointer"),617 makeInput: func() any {618 type (619 myInt int620 S struct{ *myInt }621 )622 s := S{new(myInt)}623 *s.myInt = 5624 return s625 },626 want: `{}`,627 }, {628 // Exported embedded field of pointer to non-struct type629 // should be serialized.630 CaseName: Name("ExportedEmbeddedIntPointer"),631 makeInput: func() any {632 type (633 MyInt int634 S struct{ *MyInt }635 )636 s := S{new(MyInt)}637 *s.MyInt = 5638 return s639 },640 want: `{"MyInt":5}`,641 }, {642 // Exported fields of embedded structs should have their643 // exported fields be serialized regardless of whether the struct types644 // themselves are exported.645 CaseName: Name("EmbeddedStruct"),646 makeInput: func() any {647 type (648 s1 struct{ x, X int }649 S2 struct{ y, Y int }650 S struct {651 s1652 S2653 }654 )655 return S{s1{1, 2}, S2{3, 4}}656 },657 want: `{"X":2,"Y":4}`,658 }, {659 // Exported fields of pointers to embedded structs should have their660 // exported fields be serialized regardless of whether the struct types661 // themselves are exported.662 CaseName: Name("EmbeddedStructPointer"),663 makeInput: func() any {664 type (665 s1 struct{ x, X int }666 S2 struct{ y, Y int }667 S struct {668 *s1669 *S2670 }671 )672 return S{&s1{1, 2}, &S2{3, 4}}673 },674 want: `{"X":2,"Y":4}`,675 }, {676 // Exported fields on embedded unexported structs at multiple levels677 // of nesting should still be serialized.678 CaseName: Name("NestedStructAndInts"),679 makeInput: func() any {680 type (681 MyInt1 int682 MyInt2 int683 myInt int684 s2 struct {685 MyInt2686 myInt687 }688 s1 struct {689 MyInt1690 myInt691 s2692 }693 S struct {694 s1695 myInt696 }697 )698 return S{s1{1, 2, s2{3, 4}}, 6}699 },700 want: `{"MyInt1":1,"MyInt2":3}`,701 }, {702 // If an anonymous struct pointer field is nil, we should ignore703 // the embedded fields behind it. Not properly doing so may704 // result in the wrong output or reflect panics.705 CaseName: Name("EmbeddedFieldBehindNilPointer"),706 makeInput: func() any {707 type (708 S2 struct{ Field string }709 S struct{ *S2 }710 )711 return S{}712 },713 want: `{}`,714 }}715 716 for _, tt := range tests {717 t.Run(tt.Name, func(t *testing.T) {718 b, err := Marshal(tt.makeInput())719 if err != nil {720 t.Fatalf("%s: Marshal error: %v", tt.Where, err)721 }722 if string(b) != tt.want {723 t.Fatalf("%s: Marshal:\n\tgot: %s\n\twant: %s", tt.Where, b, tt.want)724 }725 })726 }727}728 729type BugA struct {730 S string731}732 733type BugB struct {734 BugA735 S string736}737 738type BugC struct {739 S string740}741 742// Legal Go: We never use the repeated embedded field (S).743type BugX struct {744 A int745 BugA746 BugB747}748 749// golang.org/issue/16042.750// Even if a nil interface value is passed in, as long as751// it implements Marshaler, it should be marshaled.752type nilJSONMarshaler string753 754func (nm *nilJSONMarshaler) MarshalJSON() ([]byte, error) {755 if nm == nil {756 return Marshal("0zenil0")757 }758 return Marshal("zenil:" + string(*nm))759}760 761// golang.org/issue/34235.762// Even if a nil interface value is passed in, as long as763// it implements encoding.TextMarshaler, it should be marshaled.764type nilTextMarshaler string765 766func (nm *nilTextMarshaler) MarshalText() ([]byte, error) {767 if nm == nil {768 return []byte("0zenil0"), nil769 }770 return []byte("zenil:" + string(*nm)), nil771}772 773// See golang.org/issue/16042 and golang.org/issue/34235.774func TestNilMarshal(t *testing.T) {775 tests := []struct {776 CaseName777 in any778 want string779 }{780 {Name(""), nil, `null`},781 {Name(""), new(float64), `0`},782 {Name(""), []any(nil), `null`},783 {Name(""), []string(nil), `null`},784 {Name(""), map[string]string(nil), `null`},785 {Name(""), []byte(nil), `null`},786 {Name(""), struct{ M string }{"gopher"}, `{"M":"gopher"}`},787 {Name(""), struct{ M Marshaler }{}, `{"M":null}`},788 {Name(""), struct{ M Marshaler }{(*nilJSONMarshaler)(nil)}, `{"M":"0zenil0"}`},789 {Name(""), struct{ M any }{(*nilJSONMarshaler)(nil)}, `{"M":null}`},790 {Name(""), struct{ M encoding.TextMarshaler }{}, `{"M":null}`},791 {Name(""), struct{ M encoding.TextMarshaler }{(*nilTextMarshaler)(nil)}, `{"M":"0zenil0"}`},792 {Name(""), struct{ M any }{(*nilTextMarshaler)(nil)}, `{"M":null}`},793 }794 for _, tt := range tests {795 t.Run(tt.Name, func(t *testing.T) {796 switch got, err := Marshal(tt.in); {797 case err != nil:798 t.Fatalf("%s: Marshal error: %v", tt.Where, err)799 case string(got) != tt.want:800 t.Fatalf("%s: Marshal:\n\tgot: %s\n\twant: %s", tt.Where, got, tt.want)801 }802 })803 }804}805 806// Issue 5245.807func TestEmbeddedBug(t *testing.T) {808 v := BugB{809 BugA{"A"},810 "B",811 }812 b, err := Marshal(v)813 if err != nil {814 t.Fatal("Marshal error:", err)815 }816 want := `{"S":"B"}`817 got := string(b)818 if got != want {819 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)820 }821 // Now check that the duplicate field, S, does not appear.822 x := BugX{823 A: 23,824 }825 b, err = Marshal(x)826 if err != nil {827 t.Fatal("Marshal error:", err)828 }829 want = `{"A":23}`830 got = string(b)831 if got != want {832 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)833 }834}835 836type BugD struct { // Same as BugA after tagging.837 XXX string `json:"S"`838}839 840// BugD's tagged S field should dominate BugA's.841type BugY struct {842 BugA843 BugD844}845 846// Test that a field with a tag dominates untagged fields.847func TestTaggedFieldDominates(t *testing.T) {848 v := BugY{849 BugA{"BugA"},850 BugD{"BugD"},851 }852 b, err := Marshal(v)853 if err != nil {854 t.Fatal("Marshal error:", err)855 }856 want := `{"S":"BugD"}`857 got := string(b)858 if got != want {859 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)860 }861}862 863// There are no tags here, so S should not appear.864type BugZ struct {865 BugA866 BugC867 BugY // Contains a tagged S field through BugD; should not dominate.868}869 870func TestDuplicatedFieldDisappears(t *testing.T) {871 v := BugZ{872 BugA{"BugA"},873 BugC{"BugC"},874 BugY{875 BugA{"nested BugA"},876 BugD{"nested BugD"},877 },878 }879 b, err := Marshal(v)880 if err != nil {881 t.Fatal("Marshal error:", err)882 }883 want := `{}`884 got := string(b)885 if got != want {886 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)887 }888}889 890func TestIssue10281(t *testing.T) {891 type Foo struct {892 N Number893 }894 x := Foo{Number(`invalid`)}895 896 if _, err := Marshal(&x); err == nil {897 t.Fatalf("Marshal error: got nil, want non-nil")898 }899}900 901func TestMarshalErrorAndReuseEncodeState(t *testing.T) {902 // Disable the GC temporarily to prevent encodeState's in Pool being cleaned away during the test.903 percent := debug.SetGCPercent(-1)904 defer debug.SetGCPercent(percent)905 906 // Trigger an error in Marshal with cyclic data.907 type Dummy struct {908 Name string909 Next *Dummy910 }911 dummy := Dummy{Name: "Dummy"}912 dummy.Next = &dummy913 if _, err := Marshal(dummy); err == nil {914 t.Errorf("Marshal error: got nil, want non-nil")915 }916 917 type Data struct {918 A string919 I int920 }921 want := Data{A: "a", I: 1}922 b, err := Marshal(want)923 if err != nil {924 t.Errorf("Marshal error: %v", err)925 }926 927 var got Data928 if err := Unmarshal(b, &got); err != nil {929 t.Errorf("Unmarshal error: %v", err)930 }931 if got != want {932 t.Errorf("Unmarshal:\n\tgot: %v\n\twant: %v", got, want)933 }934}935 936func TestHTMLEscape(t *testing.T) {937 var b, want bytes.Buffer938 m := `{"M":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}`939 want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`))940 HTMLEscape(&b, []byte(m))941 if !bytes.Equal(b.Bytes(), want.Bytes()) {942 t.Errorf("HTMLEscape:\n\tgot: %s\n\twant: %s", b.Bytes(), want.Bytes())943 }944}945 946// golang.org/issue/8582947func TestEncodePointerString(t *testing.T) {948 type stringPointer struct {949 N *int64 `json:"n,string"`950 }951 var n int64 = 42952 b, err := Marshal(stringPointer{N: &n})953 if err != nil {954 t.Fatalf("Marshal error: %v", err)955 }956 if got, want := string(b), `{"n":"42"}`; got != want {957 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)958 }959 var back stringPointer960 switch err = Unmarshal(b, &back); {961 case err != nil:962 t.Fatalf("Unmarshal error: %v", err)963 case back.N == nil:964 t.Fatalf("Unmarshal: back.N = nil, want non-nil")965 case *back.N != 42:966 t.Fatalf("Unmarshal: *back.N = %d, want 42", *back.N)967 }968}969 970var encodeStringTests = []struct {971 in string972 out string973}{974 {"\x00", `"\u0000"`},975 {"\x01", `"\u0001"`},976 {"\x02", `"\u0002"`},977 {"\x03", `"\u0003"`},978 {"\x04", `"\u0004"`},979 {"\x05", `"\u0005"`},980 {"\x06", `"\u0006"`},981 {"\x07", `"\u0007"`},982 {"\x08", `"\b"`},983 {"\x09", `"\t"`},984 {"\x0a", `"\n"`},985 {"\x0b", `"\u000b"`},986 {"\x0c", `"\f"`},987 {"\x0d", `"\r"`},988 {"\x0e", `"\u000e"`},989 {"\x0f", `"\u000f"`},990 {"\x10", `"\u0010"`},991 {"\x11", `"\u0011"`},992 {"\x12", `"\u0012"`},993 {"\x13", `"\u0013"`},994 {"\x14", `"\u0014"`},995 {"\x15", `"\u0015"`},996 {"\x16", `"\u0016"`},997 {"\x17", `"\u0017"`},998 {"\x18", `"\u0018"`},999 {"\x19", `"\u0019"`},1000 {"\x1a", `"\u001a"`},1001 {"\x1b", `"\u001b"`},1002 {"\x1c", `"\u001c"`},1003 {"\x1d", `"\u001d"`},1004 {"\x1e", `"\u001e"`},1005 {"\x1f", `"\u001f"`},1006}1007 1008func TestEncodeString(t *testing.T) {1009 for _, tt := range encodeStringTests {1010 b, err := Marshal(tt.in)1011 if err != nil {1012 t.Errorf("Marshal(%q) error: %v", tt.in, err)1013 continue1014 }1015 out := string(b)1016 if out != tt.out {1017 t.Errorf("Marshal(%q) = %#q, want %#q", tt.in, out, tt.out)1018 }1019 }1020}1021 1022type jsonbyte byte1023 1024func (b jsonbyte) MarshalJSON() ([]byte, error) { return tenc(`{"JB":%d}`, b) }1025 1026type textbyte byte1027 1028func (b textbyte) MarshalText() ([]byte, error) { return tenc(`TB:%d`, b) }1029 1030type jsonint int1031 1032func (i jsonint) MarshalJSON() ([]byte, error) { return tenc(`{"JI":%d}`, i) }1033 1034type textint int1035 1036func (i textint) MarshalText() ([]byte, error) { return tenc(`TI:%d`, i) }1037 1038func tenc(format string, a ...any) ([]byte, error) {1039 var buf bytes.Buffer1040 fmt.Fprintf(&buf, format, a...)1041 return buf.Bytes(), nil1042}1043 1044type textfloat float641045 1046func (f textfloat) MarshalText() ([]byte, error) { return tenc(`TF:%0.2f`, f) }1047 1048// Issue 137831049func TestEncodeBytekind(t *testing.T) {1050 tests := []struct {1051 CaseName1052 in any1053 want string1054 }{1055 {Name(""), byte(7), "7"},1056 {Name(""), jsonbyte(7), `{"JB":7}`},1057 {Name(""), textbyte(4), `"TB:4"`},1058 {Name(""), jsonint(5), `{"JI":5}`},1059 {Name(""), textint(1), `"TI:1"`},1060 {Name(""), []byte{0, 1}, `"AAE="`},1061 {Name(""), []jsonbyte{0, 1}, `[{"JB":0},{"JB":1}]`},1062 {Name(""), [][]jsonbyte{{0, 1}, {3}}, `[[{"JB":0},{"JB":1}],[{"JB":3}]]`},1063 {Name(""), []textbyte{2, 3}, `["TB:2","TB:3"]`},1064 {Name(""), []jsonint{5, 4}, `[{"JI":5},{"JI":4}]`},1065 {Name(""), []textint{9, 3}, `["TI:9","TI:3"]`},1066 {Name(""), []int{9, 3}, `[9,3]`},1067 {Name(""), []textfloat{12, 3}, `["TF:12.00","TF:3.00"]`},1068 }1069 for _, tt := range tests {1070 t.Run(tt.Name, func(t *testing.T) {1071 b, err := Marshal(tt.in)1072 if err != nil {1073 t.Errorf("%s: Marshal error: %v", tt.Where, err)1074 }1075 got, want := string(b), tt.want1076 if got != want {1077 t.Errorf("%s: Marshal:\n\tgot: %s\n\twant: %s", tt.Where, got, want)1078 }1079 })1080 }1081}1082 1083func TestTextMarshalerMapKeysAreSorted(t *testing.T) {1084 got, err := Marshal(map[unmarshalerText]int{1085 {"x", "y"}: 1,1086 {"y", "x"}: 2,1087 {"a", "z"}: 3,1088 {"z", "a"}: 4,1089 })1090 if err != nil {1091 t.Fatalf("Marshal error: %v", err)1092 }1093 const want = `{"a:z":3,"x:y":1,"y:x":2,"z:a":4}`1094 if string(got) != want {1095 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)1096 }1097}1098 1099// https://golang.org/issue/336751100func TestNilMarshalerTextMapKey(t *testing.T) {1101 got, err := Marshal(map[*unmarshalerText]int{1102 (*unmarshalerText)(nil): 1,1103 {"A", "B"}: 2,1104 })1105 if err != nil {1106 t.Fatalf("Marshal error: %v", err)1107 }1108 const want = `{"":1,"A:B":2}`1109 if string(got) != want {1110 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)1111 }1112}1113 1114var re = regexp.MustCompile1115 1116// syntactic checks on form of marshaled floating point numbers.1117var badFloatREs = []*regexp.Regexp{1118 re(`p`), // no binary exponential notation1119 re(`^\+`), // no leading + sign1120 re(`^-?0[^.]`), // no unnecessary leading zeros1121 re(`^-?\.`), // leading zero required before decimal point1122 re(`\.(e|$)`), // no trailing decimal1123 re(`\.[0-9]+0(e|$)`), // no trailing zero in fraction1124 re(`^-?(0|[0-9]{2,})\..*e`), // exponential notation must have normalized mantissa1125 re(`e[0-9]`), // positive exponent must be signed1126 re(`e[+-]0`), // exponent must not have leading zeros1127 re(`e-[1-6]$`), // not tiny enough for exponential notation1128 re(`e+(.|1.|20)$`), // not big enough for exponential notation1129 re(`^-?0\.0000000`), // too tiny, should use exponential notation1130 re(`^-?[0-9]{22}`), // too big, should use exponential notation1131 re(`[1-9][0-9]{16}[1-9]`), // too many significant digits in integer1132 re(`[1-9][0-9.]{17}[1-9]`), // too many significant digits in decimal1133 // below here for float32 only1134 re(`[1-9][0-9]{8}[1-9]`), // too many significant digits in integer1135 re(`[1-9][0-9.]{9}[1-9]`), // too many significant digits in decimal1136}1137 1138func TestMarshalFloat(t *testing.T) {1139 t.Parallel()1140 nfail := 01141 test := func(f float64, bits int) {1142 vf := any(f)1143 if bits == 32 {1144 f = float64(float32(f)) // round1145 vf = float32(f)1146 }1147 bout, err := Marshal(vf)1148 if err != nil {1149 t.Errorf("Marshal(%T(%g)) error: %v", vf, vf, err)1150 nfail++1151 return1152 }1153 out := string(bout)1154 1155 // result must convert back to the same float1156 g, err := strconv.ParseFloat(out, bits)1157 if err != nil {1158 t.Errorf("ParseFloat(%q) error: %v", out, err)1159 nfail++1160 return1161 }1162 if f != g || fmt.Sprint(f) != fmt.Sprint(g) { // fmt.Sprint handles ±01163 t.Errorf("ParseFloat(%q):\n\tgot: %g\n\twant: %g", out, float32(g), vf)1164 nfail++1165 return1166 }1167 1168 bad := badFloatREs1169 if bits == 64 {1170 bad = bad[:len(bad)-2]1171 }1172 for _, re := range bad {1173 if re.MatchString(out) {1174 t.Errorf("Marshal(%T(%g)) = %q; must not match /%s/", vf, vf, out, re)1175 nfail++1176 return1177 }1178 }1179 }1180 1181 var (1182 bigger = math.Inf(+1)1183 smaller = math.Inf(-1)1184 )1185 1186 var digits = "1.2345678901234567890123"1187 for i := len(digits); i >= 2; i-- {1188 if testing.Short() && i < len(digits)-4 {1189 break1190 }1191 for exp := -30; exp <= 30; exp++ {1192 for _, sign := range "+-" {1193 for bits := 32; bits <= 64; bits += 32 {1194 s := fmt.Sprintf("%c%se%d", sign, digits[:i], exp)1195 f, err := strconv.ParseFloat(s, bits)1196 if err != nil {1197 log.Fatal(err)1198 }1199 next := math.Nextafter1200 if bits == 32 {