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 isZeroer interface {93 IsZero() bool94}95 96type OptionalsZero struct {97 Sr string `json:"sr"`98 So string `json:"so,omitzero"`99 Sw string `json:"-"`100 101 Ir int `json:"omitzero"` // actually named omitzero, not an option102 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"` // nil interface131 NonNilIsZeroer isZeroer `json:"nonniliszeroer,omitzero"` // non-nil interface132 NoPanicStruct0 isZeroer `json:"nps0,omitzero"` // non-nil interface with nil pointer133 NoPanicStruct1 isZeroer `json:"nps1,omitzero"` // non-nil interface with non-nil pointer134 NoPanicStruct2 *NoPanicStruct `json:"nps2,omitzero"` // nil pointer135 NoPanicStruct3 *NoPanicStruct `json:"nps3,omitzero"` // non-nil pointer136 NoPanicStruct4 NoPanicStruct `json:"nps4,omitzero"` // concrete type137}138 139func 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 OptionalsZero157 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 = -0163 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 181func 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 207type 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 237func 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 OptionalsEmptyZero249 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 263type 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 271func TestRoundtripStringTag(t *testing.T) {272 tests := []struct {273 CaseName274 in StringTag275 want string // empty to just test that we roundtrip276 }{{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 // See golang.org/issues/38173.294 CaseName: Name("StringDoubleEscapes"),295 in: StringTag{296 StrStr: "\b\f\n\r\t\"\\",297 NumberStr: "0", // just to satisfy the roundtrip298 },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 // Verify that it round-trips.318 var s2 StringTag319 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// byte slices are special even if they're renamed types.330type renamedByte byte331type renamedByteSlice []byte332type renamedRenamedByteSlice []renamedByte333 334func 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 354type SamePointerNoCycle struct {355 Ptr1, Ptr2 *SamePointerNoCycle356}357 358var samePointerNoCycle = &SamePointerNoCycle{}359 360type PointerCycle struct {361 Ptr *PointerCycle362}363 364var pointerCycle = &PointerCycle{}365 366type PointerCycleIndirect struct {367 Ptrs []any368}369 370type RecursiveSlice []RecursiveSlice371 372var (373 pointerCycleIndirect = &PointerCycleIndirect{}374 mapCycle = make(map[string]any)375 sliceCycle = []any{nil}376 sliceNoCycle = []any{nil, nil}377 recursiveSliceCycle = []RecursiveSlice{nil}378)379 380func init() {381 ptr := &SamePointerNoCycle{}382 samePointerNoCycle.Ptr1 = ptr383 samePointerNoCycle.Ptr2 = ptr384 385 pointerCycle.Ptr = pointerCycle386 pointerCycleIndirect.Ptrs = []any{pointerCycleIndirect}387 388 mapCycle["x"] = mapCycle389 sliceCycle[0] = sliceCycle390 sliceNoCycle[1] = sliceNoCycle[:1]391 const startDetectingCyclesAfter = 1e3392 for i := startDetectingCyclesAfter; i > 0; i-- {393 sliceNoCycle = []any{sliceNoCycle}394 }395 recursiveSliceCycle[0] = recursiveSliceCycle396}397 398func TestSamePointerNoCycle(t *testing.T) {399 if _, err := Marshal(samePointerNoCycle); err != nil {400 t.Fatalf("Marshal error: %v", err)401 }402}403 404func TestSliceNoCycle(t *testing.T) {405 if _, err := Marshal(sliceNoCycle); err != nil {406 t.Fatalf("Marshal error: %v", err)407 }408}409 410func TestUnsupportedValues(t *testing.T) {411 tests := []struct {412 CaseName413 in any414 }{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// Issue 43207438func TestMarshalTextFloatMap(t *testing.T) {439 m := map[textfloat]string{440 textfloat(math.NaN()): "1",441 textfloat(math.NaN()): "1",442 }443 got, err := Marshal(m)444 if err != nil {445 t.Errorf("Marshal error: %v", err)446 }447 want := `{"TF:NaN":"1","TF:NaN":"1"}`448 if string(got) != want {449 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)450 }451}452 453// Ref has Marshaler and Unmarshaler methods with pointer receiver.454type Ref int455 456func (*Ref) MarshalJSON() ([]byte, error) {457 return []byte(`"ref"`), nil458}459 460func (r *Ref) UnmarshalJSON([]byte) error {461 *r = 12462 return nil463}464 465// Val has Marshaler methods with value receiver.466type Val int467 468func (Val) MarshalJSON() ([]byte, error) {469 return []byte(`"val"`), nil470}471 472// RefText has Marshaler and Unmarshaler methods with pointer receiver.473type RefText int474 475func (*RefText) MarshalText() ([]byte, error) {476 return []byte(`"ref"`), nil477}478 479func (r *RefText) UnmarshalText([]byte) error {480 *r = 13481 return nil482}483 484// ValText has Marshaler methods with value receiver.485type ValText int486 487func (ValText) MarshalText() ([]byte, error) {488 return []byte(`"val"`), nil489}490 491func TestRefValMarshal(t *testing.T) {492 var s = struct {493 R0 Ref494 R1 *Ref495 R2 RefText496 R3 *RefText497 V0 Val498 V1 *Val499 V2 ValText500 V3 *ValText501 }{502 R0: 12,503 R1: new(Ref),504 R2: 14,505 R3: new(RefText),506 V0: 13,507 V1: new(Val),508 V2: 15,509 V3: new(ValText),510 }511 const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}`512 b, err := Marshal(&s)513 if err != nil {514 t.Fatalf("Marshal error: %v", err)515 }516 if got := string(b); got != want {517 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)518 }519}520 521// C implements Marshaler and returns unescaped JSON.522type C int523 524func (C) MarshalJSON() ([]byte, error) {525 return []byte(`"<&>"`), nil526}527 528// CText implements Marshaler and returns unescaped text.529type CText int530 531func (CText) MarshalText() ([]byte, error) {532 return []byte(`"<&>"`), nil533}534 535func TestMarshalerEscaping(t *testing.T) {536 var c C537 want := `"\u003c\u0026\u003e"`538 b, err := Marshal(c)539 if err != nil {540 t.Fatalf("Marshal error: %v", err)541 }542 if got := string(b); got != want {543 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)544 }545 546 var ct CText547 want = `"\"\u003c\u0026\u003e\""`548 b, err = Marshal(ct)549 if err != nil {550 t.Fatalf("Marshal error: %v", err)551 }552 if got := string(b); got != want {553 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)554 }555}556 557func TestAnonymousFields(t *testing.T) {558 tests := []struct {559 CaseName560 makeInput func() any // Function to create input value561 want string // Expected JSON output562 }{{563 // Both S1 and S2 have a field named X. From the perspective of S,564 // it is ambiguous which one X refers to.565 // This should not serialize either field.566 CaseName: Name("AmbiguousField"),567 makeInput: func() any {568 type (569 S1 struct{ x, X int }570 S2 struct{ x, X int }571 S struct {572 S1573 S2574 }575 )576 return S{S1{1, 2}, S2{3, 4}}577 },578 want: `{}`,579 }, {580 CaseName: Name("DominantField"),581 // Both S1 and S2 have a field named X, but since S has an X field as582 // well, it takes precedence over S1.X and S2.X.583 makeInput: func() any {584 type (585 S1 struct{ x, X int }586 S2 struct{ x, X int }587 S struct {588 S1589 S2590 x, X int591 }592 )593 return S{S1{1, 2}, S2{3, 4}, 5, 6}594 },595 want: `{"X":6}`,596 }, {597 // Unexported embedded field of non-struct type should not be serialized.598 CaseName: Name("UnexportedEmbeddedInt"),599 makeInput: func() any {600 type (601 myInt int602 S struct{ myInt }603 )604 return S{5}605 },606 want: `{}`,607 }, {608 // Exported embedded field of non-struct type should be serialized.609 CaseName: Name("ExportedEmbeddedInt"),610 makeInput: func() any {611 type (612 MyInt int613 S struct{ MyInt }614 )615 return S{5}616 },617 want: `{"MyInt":5}`,618 }, {619 // Unexported embedded field of pointer to non-struct type620 // should not be serialized.621 CaseName: Name("UnexportedEmbeddedIntPointer"),622 makeInput: func() any {623 type (624 myInt int625 S struct{ *myInt }626 )627 s := S{new(myInt)}628 *s.myInt = 5629 return s630 },631 want: `{}`,632 }, {633 // Exported embedded field of pointer to non-struct type634 // should be serialized.635 CaseName: Name("ExportedEmbeddedIntPointer"),636 makeInput: func() any {637 type (638 MyInt int639 S struct{ *MyInt }640 )641 s := S{new(MyInt)}642 *s.MyInt = 5643 return s644 },645 want: `{"MyInt":5}`,646 }, {647 // Exported fields of embedded structs should have their648 // exported fields be serialized regardless of whether the struct types649 // themselves are exported.650 CaseName: Name("EmbeddedStruct"),651 makeInput: func() any {652 type (653 s1 struct{ x, X int }654 S2 struct{ y, Y int }655 S struct {656 s1657 S2658 }659 )660 return S{s1{1, 2}, S2{3, 4}}661 },662 want: `{"X":2,"Y":4}`,663 }, {664 // Exported fields of pointers to embedded structs should have their665 // exported fields be serialized regardless of whether the struct types666 // themselves are exported.667 CaseName: Name("EmbeddedStructPointer"),668 makeInput: func() any {669 type (670 s1 struct{ x, X int }671 S2 struct{ y, Y int }672 S struct {673 *s1674 *S2675 }676 )677 return S{&s1{1, 2}, &S2{3, 4}}678 },679 want: `{"X":2,"Y":4}`,680 }, {681 // Exported fields on embedded unexported structs at multiple levels682 // of nesting should still be serialized.683 CaseName: Name("NestedStructAndInts"),684 makeInput: func() any {685 type (686 MyInt1 int687 MyInt2 int688 myInt int689 s2 struct {690 MyInt2691 myInt692 }693 s1 struct {694 MyInt1695 myInt696 s2697 }698 S struct {699 s1700 myInt701 }702 )703 return S{s1{1, 2, s2{3, 4}}, 6}704 },705 want: `{"MyInt1":1,"MyInt2":3}`,706 }, {707 // If an anonymous struct pointer field is nil, we should ignore708 // the embedded fields behind it. Not properly doing so may709 // result in the wrong output or reflect panics.710 CaseName: Name("EmbeddedFieldBehindNilPointer"),711 makeInput: func() any {712 type (713 S2 struct{ Field string }714 S struct{ *S2 }715 )716 return S{}717 },718 want: `{}`,719 }}720 721 for _, tt := range tests {722 t.Run(tt.Name, func(t *testing.T) {723 b, err := Marshal(tt.makeInput())724 if err != nil {725 t.Fatalf("%s: Marshal error: %v", tt.Where, err)726 }727 if string(b) != tt.want {728 t.Fatalf("%s: Marshal:\n\tgot: %s\n\twant: %s", tt.Where, b, tt.want)729 }730 })731 }732}733 734type BugA struct {735 S string736}737 738type BugB struct {739 BugA740 S string741}742 743type BugC struct {744 S string745}746 747// Legal Go: We never use the repeated embedded field (S).748type BugX struct {749 A int750 BugA751 BugB752}753 754// golang.org/issue/16042.755// Even if a nil interface value is passed in, as long as756// it implements Marshaler, it should be marshaled.757type nilJSONMarshaler string758 759func (nm *nilJSONMarshaler) MarshalJSON() ([]byte, error) {760 if nm == nil {761 return Marshal("0zenil0")762 }763 return Marshal("zenil:" + string(*nm))764}765 766// golang.org/issue/34235.767// Even if a nil interface value is passed in, as long as768// it implements encoding.TextMarshaler, it should be marshaled.769type nilTextMarshaler string770 771func (nm *nilTextMarshaler) MarshalText() ([]byte, error) {772 if nm == nil {773 return []byte("0zenil0"), nil774 }775 return []byte("zenil:" + string(*nm)), nil776}777 778// See golang.org/issue/16042 and golang.org/issue/34235.779func TestNilMarshal(t *testing.T) {780 tests := []struct {781 CaseName782 in any783 want string784 }{785 {Name(""), nil, `null`},786 {Name(""), new(float64), `0`},787 {Name(""), []any(nil), `null`},788 {Name(""), []string(nil), `null`},789 {Name(""), map[string]string(nil), `null`},790 {Name(""), []byte(nil), `null`},791 {Name(""), struct{ M string }{"gopher"}, `{"M":"gopher"}`},792 {Name(""), struct{ M Marshaler }{}, `{"M":null}`},793 {Name(""), struct{ M Marshaler }{(*nilJSONMarshaler)(nil)}, `{"M":"0zenil0"}`},794 {Name(""), struct{ M any }{(*nilJSONMarshaler)(nil)}, `{"M":null}`},795 {Name(""), struct{ M encoding.TextMarshaler }{}, `{"M":null}`},796 {Name(""), struct{ M encoding.TextMarshaler }{(*nilTextMarshaler)(nil)}, `{"M":"0zenil0"}`},797 {Name(""), struct{ M any }{(*nilTextMarshaler)(nil)}, `{"M":null}`},798 }799 for _, tt := range tests {800 t.Run(tt.Name, func(t *testing.T) {801 switch got, err := Marshal(tt.in); {802 case err != nil:803 t.Fatalf("%s: Marshal error: %v", tt.Where, err)804 case string(got) != tt.want:805 t.Fatalf("%s: Marshal:\n\tgot: %s\n\twant: %s", tt.Where, got, tt.want)806 }807 })808 }809}810 811// Issue 5245.812func TestEmbeddedBug(t *testing.T) {813 v := BugB{814 BugA{"A"},815 "B",816 }817 b, err := Marshal(v)818 if err != nil {819 t.Fatal("Marshal error:", err)820 }821 want := `{"S":"B"}`822 got := string(b)823 if got != want {824 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)825 }826 // Now check that the duplicate field, S, does not appear.827 x := BugX{828 A: 23,829 }830 b, err = Marshal(x)831 if err != nil {832 t.Fatal("Marshal error:", err)833 }834 want = `{"A":23}`835 got = string(b)836 if got != want {837 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)838 }839}840 841type BugD struct { // Same as BugA after tagging.842 XXX string `json:"S"`843}844 845// BugD's tagged S field should dominate BugA's.846type BugY struct {847 BugA848 BugD849}850 851// Test that a field with a tag dominates untagged fields.852func TestTaggedFieldDominates(t *testing.T) {853 v := BugY{854 BugA{"BugA"},855 BugD{"BugD"},856 }857 b, err := Marshal(v)858 if err != nil {859 t.Fatal("Marshal error:", err)860 }861 want := `{"S":"BugD"}`862 got := string(b)863 if got != want {864 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)865 }866}867 868// There are no tags here, so S should not appear.869type BugZ struct {870 BugA871 BugC872 BugY // Contains a tagged S field through BugD; should not dominate.873}874 875func TestDuplicatedFieldDisappears(t *testing.T) {876 v := BugZ{877 BugA{"BugA"},878 BugC{"BugC"},879 BugY{880 BugA{"nested BugA"},881 BugD{"nested BugD"},882 },883 }884 b, err := Marshal(v)885 if err != nil {886 t.Fatal("Marshal error:", err)887 }888 want := `{}`889 got := string(b)890 if got != want {891 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)892 }893}894 895func TestIssue10281(t *testing.T) {896 type Foo struct {897 N Number898 }899 x := Foo{Number(`invalid`)}900 901 if _, err := Marshal(&x); err == nil {902 t.Fatalf("Marshal error: got nil, want non-nil")903 }904}905 906func TestMarshalErrorAndReuseEncodeState(t *testing.T) {907 // Disable the GC temporarily to prevent encodeState's in Pool being cleaned away during the test.908 percent := debug.SetGCPercent(-1)909 defer debug.SetGCPercent(percent)910 911 // Trigger an error in Marshal with cyclic data.912 type Dummy struct {913 Name string914 Next *Dummy915 }916 dummy := Dummy{Name: "Dummy"}917 dummy.Next = &dummy918 if _, err := Marshal(dummy); err == nil {919 t.Errorf("Marshal error: got nil, want non-nil")920 }921 922 type Data struct {923 A string924 I int925 }926 want := Data{A: "a", I: 1}927 b, err := Marshal(want)928 if err != nil {929 t.Errorf("Marshal error: %v", err)930 }931 932 var got Data933 if err := Unmarshal(b, &got); err != nil {934 t.Errorf("Unmarshal error: %v", err)935 }936 if got != want {937 t.Errorf("Unmarshal:\n\tgot: %v\n\twant: %v", got, want)938 }939}940 941func TestHTMLEscape(t *testing.T) {942 var b, want bytes.Buffer943 m := `{"M":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}`944 want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`))945 HTMLEscape(&b, []byte(m))946 if !bytes.Equal(b.Bytes(), want.Bytes()) {947 t.Errorf("HTMLEscape:\n\tgot: %s\n\twant: %s", b.Bytes(), want.Bytes())948 }949}950 951// golang.org/issue/8582952func TestEncodePointerString(t *testing.T) {953 type stringPointer struct {954 N *int64 `json:"n,string"`955 }956 var n int64 = 42957 b, err := Marshal(stringPointer{N: &n})958 if err != nil {959 t.Fatalf("Marshal error: %v", err)960 }961 if got, want := string(b), `{"n":"42"}`; got != want {962 t.Fatalf("Marshal:\n\tgot: %s\n\twant: %s", got, want)963 }964 var back stringPointer965 switch err = Unmarshal(b, &back); {966 case err != nil:967 t.Fatalf("Unmarshal error: %v", err)968 case back.N == nil:969 t.Fatalf("Unmarshal: back.N = nil, want non-nil")970 case *back.N != 42:971 t.Fatalf("Unmarshal: *back.N = %d, want 42", *back.N)972 }973}974 975var encodeStringTests = []struct {976 in string977 out string978}{979 {"\x00", `"\u0000"`},980 {"\x01", `"\u0001"`},981 {"\x02", `"\u0002"`},982 {"\x03", `"\u0003"`},983 {"\x04", `"\u0004"`},984 {"\x05", `"\u0005"`},985 {"\x06", `"\u0006"`},986 {"\x07", `"\u0007"`},987 {"\x08", `"\b"`},988 {"\x09", `"\t"`},989 {"\x0a", `"\n"`},990 {"\x0b", `"\u000b"`},991 {"\x0c", `"\f"`},992 {"\x0d", `"\r"`},993 {"\x0e", `"\u000e"`},994 {"\x0f", `"\u000f"`},995 {"\x10", `"\u0010"`},996 {"\x11", `"\u0011"`},997 {"\x12", `"\u0012"`},998 {"\x13", `"\u0013"`},999 {"\x14", `"\u0014"`},1000 {"\x15", `"\u0015"`},1001 {"\x16", `"\u0016"`},1002 {"\x17", `"\u0017"`},1003 {"\x18", `"\u0018"`},1004 {"\x19", `"\u0019"`},1005 {"\x1a", `"\u001a"`},1006 {"\x1b", `"\u001b"`},1007 {"\x1c", `"\u001c"`},1008 {"\x1d", `"\u001d"`},1009 {"\x1e", `"\u001e"`},1010 {"\x1f", `"\u001f"`},1011}1012 1013func TestEncodeString(t *testing.T) {1014 for _, tt := range encodeStringTests {1015 b, err := Marshal(tt.in)1016 if err != nil {1017 t.Errorf("Marshal(%q) error: %v", tt.in, err)1018 continue1019 }1020 out := string(b)1021 if out != tt.out {1022 t.Errorf("Marshal(%q) = %#q, want %#q", tt.in, out, tt.out)1023 }1024 }1025}1026 1027type jsonbyte byte1028 1029func (b jsonbyte) MarshalJSON() ([]byte, error) { return tenc(`{"JB":%d}`, b) }1030 1031type textbyte byte1032 1033func (b textbyte) MarshalText() ([]byte, error) { return tenc(`TB:%d`, b) }1034 1035type jsonint int1036 1037func (i jsonint) MarshalJSON() ([]byte, error) { return tenc(`{"JI":%d}`, i) }1038 1039type textint int1040 1041func (i textint) MarshalText() ([]byte, error) { return tenc(`TI:%d`, i) }1042 1043func tenc(format string, a ...any) ([]byte, error) {1044 var buf bytes.Buffer1045 fmt.Fprintf(&buf, format, a...)1046 return buf.Bytes(), nil1047}1048 1049type textfloat float641050 1051func (f textfloat) MarshalText() ([]byte, error) { return tenc(`TF:%0.2f`, f) }1052 1053// Issue 137831054func TestEncodeBytekind(t *testing.T) {1055 tests := []struct {1056 CaseName1057 in any1058 want string1059 }{1060 {Name(""), byte(7), "7"},1061 {Name(""), jsonbyte(7), `{"JB":7}`},1062 {Name(""), textbyte(4), `"TB:4"`},1063 {Name(""), jsonint(5), `{"JI":5}`},1064 {Name(""), textint(1), `"TI:1"`},1065 {Name(""), []byte{0, 1}, `"AAE="`},1066 {Name(""), []jsonbyte{0, 1}, `[{"JB":0},{"JB":1}]`},1067 {Name(""), [][]jsonbyte{{0, 1}, {3}}, `[[{"JB":0},{"JB":1}],[{"JB":3}]]`},1068 {Name(""), []textbyte{2, 3}, `["TB:2","TB:3"]`},1069 {Name(""), []jsonint{5, 4}, `[{"JI":5},{"JI":4}]`},1070 {Name(""), []textint{9, 3}, `["TI:9","TI:3"]`},1071 {Name(""), []int{9, 3}, `[9,3]`},1072 {Name(""), []textfloat{12, 3}, `["TF:12.00","TF:3.00"]`},1073 }1074 for _, tt := range tests {1075 t.Run(tt.Name, func(t *testing.T) {1076 b, err := Marshal(tt.in)1077 if err != nil {1078 t.Errorf("%s: Marshal error: %v", tt.Where, err)1079 }1080 got, want := string(b), tt.want1081 if got != want {1082 t.Errorf("%s: Marshal:\n\tgot: %s\n\twant: %s", tt.Where, got, want)1083 }1084 })1085 }1086}1087 1088func TestTextMarshalerMapKeysAreSorted(t *testing.T) {1089 got, err := Marshal(map[unmarshalerText]int{1090 {"x", "y"}: 1,1091 {"y", "x"}: 2,1092 {"a", "z"}: 3,1093 {"z", "a"}: 4,1094 })1095 if err != nil {1096 t.Fatalf("Marshal error: %v", err)1097 }1098 const want = `{"a:z":3,"x:y":1,"y:x":2,"z:a":4}`1099 if string(got) != want {1100 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)1101 }1102}1103 1104// https://golang.org/issue/336751105func TestNilMarshalerTextMapKey(t *testing.T) {1106 got, err := Marshal(map[*unmarshalerText]int{1107 (*unmarshalerText)(nil): 1,1108 {"A", "B"}: 2,1109 })1110 if err != nil {1111 t.Fatalf("Marshal error: %v", err)1112 }1113 const want = `{"":1,"A:B":2}`1114 if string(got) != want {1115 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)1116 }1117}1118 1119var re = regexp.MustCompile1120 1121// syntactic checks on form of marshaled floating point numbers.1122var badFloatREs = []*regexp.Regexp{1123 re(`p`), // no binary exponential notation1124 re(`^\+`), // no leading + sign1125 re(`^-?0[^.]`), // no unnecessary leading zeros1126 re(`^-?\.`), // leading zero required before decimal point1127 re(`\.(e|$)`), // no trailing decimal1128 re(`\.[0-9]+0(e|$)`), // no trailing zero in fraction1129 re(`^-?(0|[0-9]{2,})\..*e`), // exponential notation must have normalized mantissa1130 re(`e[0-9]`), // positive exponent must be signed1131 re(`e[+-]0`), // exponent must not have leading zeros1132 re(`e-[1-6]$`), // not tiny enough for exponential notation1133 re(`e+(.|1.|20)$`), // not big enough for exponential notation1134 re(`^-?0\.0000000`), // too tiny, should use exponential notation1135 re(`^-?[0-9]{22}`), // too big, should use exponential notation1136 re(`[1-9][0-9]{16}[1-9]`), // too many significant digits in integer1137 re(`[1-9][0-9.]{17}[1-9]`), // too many significant digits in decimal1138 // below here for float32 only1139 re(`[1-9][0-9]{8}[1-9]`), // too many significant digits in integer1140 re(`[1-9][0-9.]{9}[1-9]`), // too many significant digits in decimal1141}1142 1143func TestMarshalFloat(t *testing.T) {1144 t.Parallel()1145 nfail := 01146 test := func(f float64, bits int) {1147 vf := any(f)1148 if bits == 32 {1149 f = float64(float32(f)) // round1150 vf = float32(f)1151 }1152 bout, err := Marshal(vf)1153 if err != nil {1154 t.Errorf("Marshal(%T(%g)) error: %v", vf, vf, err)1155 nfail++1156 return1157 }1158 out := string(bout)1159 1160 // result must convert back to the same float1161 g, err := strconv.ParseFloat(out, bits)1162 if err != nil {1163 t.Errorf("ParseFloat(%q) error: %v", out, err)1164 nfail++1165 return1166 }1167 if f != g || fmt.Sprint(f) != fmt.Sprint(g) { // fmt.Sprint handles ±01168 t.Errorf("ParseFloat(%q):\n\tgot: %g\n\twant: %g", out, float32(g), vf)1169 nfail++1170 return1171 }1172 1173 bad := badFloatREs1174 if bits == 64 {1175 bad = bad[:len(bad)-2]1176 }1177 for _, re := range bad {1178 if re.MatchString(out) {1179 t.Errorf("Marshal(%T(%g)) = %q; must not match /%s/", vf, vf, out, re)1180 nfail++1181 return1182 }1183 }1184 }1185 1186 var (1187 bigger = math.Inf(+1)1188 smaller = math.Inf(-1)1189 )1190 1191 var digits = "1.2345678901234567890123"1192 for i := len(digits); i >= 2; i-- {1193 if testing.Short() && i < len(digits)-4 {1194 break1195 }1196 for exp := -30; exp <= 30; exp++ {1197 for _, sign := range "+-" {1198 for bits := 32; bits <= 64; bits += 32 {1199 s := fmt.Sprintf("%c%se%d", sign, digits[:i], exp)1200 f, err := strconv.ParseFloat(s, bits)