github.com/searKing/golang/go@v1.2.117/encoding/prettyjson/encode_test.go (about) 1 // Copyright 2023 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package prettyjson 6 7 import ( 8 "bytes" 9 "encoding" 10 "fmt" 11 "log" 12 "math" 13 "reflect" 14 "regexp" 15 "strconv" 16 "testing" 17 ) 18 19 type Optionals struct { 20 Sr string `json:"sr"` 21 So string `json:"so,omitempty"` 22 Sw string `json:"-"` 23 24 Ir int `json:"omitempty"` // actually named omitempty, not an option 25 Io int `json:"io,omitempty"` 26 27 Slr []string `json:"slr,random"` 28 Slo []string `json:"slo,omitempty"` 29 30 Mr map[string]any `json:"mr"` 31 Mo map[string]any `json:",omitempty"` 32 33 Fr float64 `json:"fr"` 34 Fo float64 `json:"fo,omitempty"` 35 36 Br bool `json:"br"` 37 Bo bool `json:"bo,omitempty"` 38 39 Ur uint `json:"ur"` 40 Uo uint `json:"uo,omitempty"` 41 42 Str struct{} `json:"str"` 43 Sto struct{} `json:"sto,omitempty"` 44 } 45 46 var optionalsExpected = `{ 47 "sr": "", 48 "omitempty": 0, 49 "slr": null, 50 "mr": {}, 51 "fr": 0, 52 "br": false, 53 "ur": 0, 54 "str": {} 55 }` 56 57 func TestOmitEmpty(t *testing.T) { 58 var o Optionals 59 o.Sw = "something" 60 o.Mr = map[string]any{} 61 o.Mo = map[string]any{} 62 63 got, err := MarshalIndent(&o, "", " ") 64 if err != nil { 65 t.Fatal(err) 66 } 67 if got := string(got); got != optionalsExpected { 68 t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected) 69 } 70 } 71 72 type StringTag struct { 73 BoolStr bool `json:",string"` 74 IntStr int64 `json:",string"` 75 UintptrStr uintptr `json:",string"` 76 StrStr string `json:",string"` 77 NumberStr Number `json:",string"` 78 } 79 80 // byte slices are special even if they're renamed types. 81 type renamedByte byte 82 type renamedByteSlice []byte 83 type renamedRenamedByteSlice []renamedByte 84 85 func TestEncodeRenamedByteSlice(t *testing.T) { 86 s := renamedByteSlice("abc") 87 result, err := Marshal(s) 88 if err != nil { 89 t.Fatal(err) 90 } 91 expect := `"YWJj"` 92 if string(result) != expect { 93 t.Errorf(" got %s want %s", result, expect) 94 } 95 r := renamedRenamedByteSlice("abc") 96 result, err = Marshal(r) 97 if err != nil { 98 t.Fatal(err) 99 } 100 if string(result) != expect { 101 t.Errorf(" got %s want %s", result, expect) 102 } 103 } 104 105 type SamePointerNoCycle struct { 106 Ptr1, Ptr2 *SamePointerNoCycle 107 } 108 109 var samePointerNoCycle = &SamePointerNoCycle{} 110 111 type PointerCycle struct { 112 Ptr *PointerCycle 113 } 114 115 var pointerCycle = &PointerCycle{} 116 117 type PointerCycleIndirect struct { 118 Ptrs []any 119 } 120 121 type RecursiveSlice []RecursiveSlice 122 123 var ( 124 pointerCycleIndirect = &PointerCycleIndirect{} 125 mapCycle = make(map[string]any) 126 sliceCycle = []any{nil} 127 sliceNoCycle = []any{nil, nil} 128 recursiveSliceCycle = []RecursiveSlice{nil} 129 ) 130 131 func init() { 132 ptr := &SamePointerNoCycle{} 133 samePointerNoCycle.Ptr1 = ptr 134 samePointerNoCycle.Ptr2 = ptr 135 136 pointerCycle.Ptr = pointerCycle 137 pointerCycleIndirect.Ptrs = []any{pointerCycleIndirect} 138 139 mapCycle["x"] = mapCycle 140 sliceCycle[0] = sliceCycle 141 sliceNoCycle[1] = sliceNoCycle[:1] 142 for i := startDetectingCyclesAfter; i > 0; i-- { 143 sliceNoCycle = []any{sliceNoCycle} 144 } 145 recursiveSliceCycle[0] = recursiveSliceCycle 146 } 147 148 func TestSamePointerNoCycle(t *testing.T) { 149 if _, err := Marshal(samePointerNoCycle); err != nil { 150 t.Fatalf("unexpected error: %v", err) 151 } 152 } 153 154 func TestSliceNoCycle(t *testing.T) { 155 if _, err := Marshal(sliceNoCycle); err != nil { 156 t.Fatalf("unexpected error: %v", err) 157 } 158 } 159 160 var unsupportedValues = []any{ 161 math.NaN(), 162 math.Inf(-1), 163 math.Inf(1), 164 pointerCycle, 165 pointerCycleIndirect, 166 mapCycle, 167 sliceCycle, 168 recursiveSliceCycle, 169 } 170 171 func TestUnsupportedValues(t *testing.T) { 172 for _, v := range unsupportedValues { 173 if _, err := Marshal(v); err != nil { 174 if _, ok := err.(*UnsupportedValueError); !ok { 175 t.Errorf("for %v, got %T want UnsupportedValueError", v, err) 176 } 177 } else { 178 t.Errorf("for %v, expected error", v) 179 } 180 } 181 } 182 183 // Issue 43207 184 func TestMarshalTextFloatMap(t *testing.T) { 185 m := map[textfloat]string{ 186 textfloat(math.NaN()): "1", 187 textfloat(math.NaN()): "1", 188 } 189 got, err := Marshal(m) 190 if err != nil { 191 t.Errorf("Marshal() error: %v", err) 192 } 193 want := `{"TF:NaN":"1","TF:NaN":"1"}` 194 if string(got) != want { 195 t.Errorf("Marshal() = %s, want %s", got, want) 196 } 197 } 198 199 // Ref has Marshaler and Unmarshaler methods with pointer receiver. 200 type Ref int 201 202 func (*Ref) MarshalJSON() ([]byte, error) { 203 return []byte(`"ref"`), nil 204 } 205 206 func (r *Ref) UnmarshalJSON([]byte) error { 207 *r = 12 208 return nil 209 } 210 211 // Val has Marshaler methods with value receiver. 212 type Val int 213 214 func (Val) MarshalJSON() ([]byte, error) { 215 return []byte(`"val"`), nil 216 } 217 218 // RefText has Marshaler and Unmarshaler methods with pointer receiver. 219 type RefText int 220 221 func (*RefText) MarshalText() ([]byte, error) { 222 return []byte(`"ref"`), nil 223 } 224 225 func (r *RefText) UnmarshalText([]byte) error { 226 *r = 13 227 return nil 228 } 229 230 // ValText has Marshaler methods with value receiver. 231 type ValText int 232 233 func (ValText) MarshalText() ([]byte, error) { 234 return []byte(`"val"`), nil 235 } 236 237 func TestRefValMarshal(t *testing.T) { 238 var s = struct { 239 R0 Ref 240 R1 *Ref 241 R2 RefText 242 R3 *RefText 243 V0 Val 244 V1 *Val 245 V2 ValText 246 V3 *ValText 247 }{ 248 R0: 12, 249 R1: new(Ref), 250 R2: 14, 251 R3: new(RefText), 252 V0: 13, 253 V1: new(Val), 254 V2: 15, 255 V3: new(ValText), 256 } 257 const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}` 258 b, err := Marshal(&s) 259 if err != nil { 260 t.Fatalf("Marshal: %v", err) 261 } 262 if got := string(b); got != want { 263 t.Errorf("got %q, want %q", got, want) 264 } 265 } 266 267 // C implements Marshaler and returns unescaped JSON. 268 type C int 269 270 func (C) MarshalJSON() ([]byte, error) { 271 return []byte(`"<&>"`), nil 272 } 273 274 // CText implements Marshaler and returns unescaped text. 275 type CText int 276 277 func (CText) MarshalText() ([]byte, error) { 278 return []byte(`"<&>"`), nil 279 } 280 281 func TestMarshalerEscaping(t *testing.T) { 282 var c C 283 want := `"\u003c\u0026\u003e"` 284 b, err := Marshal(c) 285 if err != nil { 286 t.Fatalf("Marshal(c): %v", err) 287 } 288 if got := string(b); got != want { 289 t.Errorf("Marshal(c) = %#q, want %#q", got, want) 290 } 291 292 var ct CText 293 want = `"\"\u003c\u0026\u003e\""` 294 b, err = Marshal(ct) 295 if err != nil { 296 t.Fatalf("Marshal(ct): %v", err) 297 } 298 if got := string(b); got != want { 299 t.Errorf("Marshal(ct) = %#q, want %#q", got, want) 300 } 301 } 302 303 func TestAnonymousFields(t *testing.T) { 304 tests := []struct { 305 label string // Test name 306 makeInput func() any // Function to create input value 307 want string // Expected JSON output 308 }{{ 309 // Both S1 and S2 have a field named X. From the perspective of S, 310 // it is ambiguous which one X refers to. 311 // This should not serialize either field. 312 label: "AmbiguousField", 313 makeInput: func() any { 314 type ( 315 S1 struct{ x, X int } 316 S2 struct{ x, X int } 317 S struct { 318 S1 319 S2 320 } 321 ) 322 return S{S1{1, 2}, S2{3, 4}} 323 }, 324 want: `{}`, 325 }, { 326 label: "DominantField", 327 // Both S1 and S2 have a field named X, but since S has an X field as 328 // well, it takes precedence over S1.X and S2.X. 329 makeInput: func() any { 330 type ( 331 S1 struct{ x, X int } 332 S2 struct{ x, X int } 333 S struct { 334 S1 335 S2 336 x, X int 337 } 338 ) 339 return S{S1{1, 2}, S2{3, 4}, 5, 6} 340 }, 341 want: `{"X":6}`, 342 }, { 343 // Unexported embedded field of non-struct type should not be serialized. 344 label: "UnexportedEmbeddedInt", 345 makeInput: func() any { 346 type ( 347 myInt int 348 S struct{ myInt } 349 ) 350 return S{5} 351 }, 352 want: `{}`, 353 }, { 354 // Exported embedded field of non-struct type should be serialized. 355 label: "ExportedEmbeddedInt", 356 makeInput: func() any { 357 type ( 358 MyInt int 359 S struct{ MyInt } 360 ) 361 return S{5} 362 }, 363 want: `{"MyInt":5}`, 364 }, { 365 // Unexported embedded field of pointer to non-struct type 366 // should not be serialized. 367 label: "UnexportedEmbeddedIntPointer", 368 makeInput: func() any { 369 type ( 370 myInt int 371 S struct{ *myInt } 372 ) 373 s := S{new(myInt)} 374 *s.myInt = 5 375 return s 376 }, 377 want: `{}`, 378 }, { 379 // Exported embedded field of pointer to non-struct type 380 // should be serialized. 381 label: "ExportedEmbeddedIntPointer", 382 makeInput: func() any { 383 type ( 384 MyInt int 385 S struct{ *MyInt } 386 ) 387 s := S{new(MyInt)} 388 *s.MyInt = 5 389 return s 390 }, 391 want: `{"MyInt":5}`, 392 }, { 393 // Exported fields of embedded structs should have their 394 // exported fields be serialized regardless of whether the struct types 395 // themselves are exported. 396 label: "EmbeddedStruct", 397 makeInput: func() any { 398 type ( 399 s1 struct{ x, X int } 400 S2 struct{ y, Y int } 401 S struct { 402 s1 403 S2 404 } 405 ) 406 return S{s1{1, 2}, S2{3, 4}} 407 }, 408 want: `{"X":2,"Y":4}`, 409 }, { 410 // Exported fields of pointers to embedded structs should have their 411 // exported fields be serialized regardless of whether the struct types 412 // themselves are exported. 413 label: "EmbeddedStructPointer", 414 makeInput: func() any { 415 type ( 416 s1 struct{ x, X int } 417 S2 struct{ y, Y int } 418 S struct { 419 *s1 420 *S2 421 } 422 ) 423 return S{&s1{1, 2}, &S2{3, 4}} 424 }, 425 want: `{"X":2,"Y":4}`, 426 }, { 427 // Exported fields on embedded unexported structs at multiple levels 428 // of nesting should still be serialized. 429 label: "NestedStructAndInts", 430 makeInput: func() any { 431 type ( 432 MyInt1 int 433 MyInt2 int 434 myInt int 435 s2 struct { 436 MyInt2 437 myInt 438 } 439 s1 struct { 440 MyInt1 441 myInt 442 s2 443 } 444 S struct { 445 s1 446 myInt 447 } 448 ) 449 return S{s1{1, 2, s2{3, 4}}, 6} 450 }, 451 want: `{"MyInt1":1,"MyInt2":3}`, 452 }, { 453 // If an anonymous struct pointer field is nil, we should ignore 454 // the embedded fields behind it. Not properly doing so may 455 // result in the wrong output or reflect panics. 456 label: "EmbeddedFieldBehindNilPointer", 457 makeInput: func() any { 458 type ( 459 S2 struct{ Field string } 460 S struct{ *S2 } 461 ) 462 return S{} 463 }, 464 want: `{}`, 465 }} 466 467 for _, tt := range tests { 468 t.Run(tt.label, func(t *testing.T) { 469 b, err := Marshal(tt.makeInput()) 470 if err != nil { 471 t.Fatalf("Marshal() = %v, want nil error", err) 472 } 473 if string(b) != tt.want { 474 t.Fatalf("Marshal() = %q, want %q", b, tt.want) 475 } 476 }) 477 } 478 } 479 480 type BugA struct { 481 S string 482 } 483 484 type BugB struct { 485 BugA 486 S string 487 } 488 489 type BugC struct { 490 S string 491 } 492 493 // Legal Go: We never use the repeated embedded field (S). 494 type BugX struct { 495 A int 496 BugA 497 BugB 498 } 499 500 // golang.org/issue/16042. 501 // Even if a nil interface value is passed in, as long as 502 // it implements Marshaler, it should be marshaled. 503 type nilJSONMarshaler string 504 505 func (nm *nilJSONMarshaler) MarshalJSON() ([]byte, error) { 506 if nm == nil { 507 return Marshal("0zenil0") 508 } 509 return Marshal("zenil:" + string(*nm)) 510 } 511 512 // golang.org/issue/34235. 513 // Even if a nil interface value is passed in, as long as 514 // it implements encoding.TextMarshaler, it should be marshaled. 515 type nilTextMarshaler string 516 517 func (nm *nilTextMarshaler) MarshalText() ([]byte, error) { 518 if nm == nil { 519 return []byte("0zenil0"), nil 520 } 521 return []byte("zenil:" + string(*nm)), nil 522 } 523 524 // See golang.org/issue/16042 and golang.org/issue/34235. 525 func TestNilMarshal(t *testing.T) { 526 testCases := []struct { 527 v any 528 want string 529 }{ 530 {v: nil, want: `null`}, 531 {v: new(float64), want: `0`}, 532 {v: []any(nil), want: `null`}, 533 {v: []string(nil), want: `null`}, 534 {v: map[string]string(nil), want: `null`}, 535 {v: []byte(nil), want: `null`}, 536 {v: struct{ M string }{"gopher"}, want: `{"M":"gopher"}`}, 537 {v: struct{ M Marshaler }{}, want: `{"M":null}`}, 538 {v: struct{ M Marshaler }{(*nilJSONMarshaler)(nil)}, want: `{"M":"0zenil0"}`}, 539 {v: struct{ M any }{(*nilJSONMarshaler)(nil)}, want: `{"M":null}`}, 540 {v: struct{ M encoding.TextMarshaler }{}, want: `{"M":null}`}, 541 {v: struct{ M encoding.TextMarshaler }{(*nilTextMarshaler)(nil)}, want: `{"M":"0zenil0"}`}, 542 {v: struct{ M any }{(*nilTextMarshaler)(nil)}, want: `{"M":null}`}, 543 } 544 545 for _, tt := range testCases { 546 out, err := Marshal(tt.v) 547 if err != nil || string(out) != tt.want { 548 t.Errorf("Marshal(%#v) = %#q, %#v, want %#q, nil", tt.v, out, err, tt.want) 549 continue 550 } 551 } 552 } 553 554 // Issue 5245. 555 func TestEmbeddedBug(t *testing.T) { 556 v := BugB{ 557 BugA{"A"}, 558 "B", 559 } 560 b, err := Marshal(v) 561 if err != nil { 562 t.Fatal("Marshal:", err) 563 } 564 want := `{"S":"B"}` 565 got := string(b) 566 if got != want { 567 t.Fatalf("Marshal: got %s want %s", got, want) 568 } 569 // Now check that the duplicate field, S, does not appear. 570 x := BugX{ 571 A: 23, 572 } 573 b, err = Marshal(x) 574 if err != nil { 575 t.Fatal("Marshal:", err) 576 } 577 want = `{"A":23}` 578 got = string(b) 579 if got != want { 580 t.Fatalf("Marshal: got %s want %s", got, want) 581 } 582 } 583 584 type BugD struct { // Same as BugA after tagging. 585 XXX string `json:"S"` 586 } 587 588 // BugD's tagged S field should dominate BugA's. 589 type BugY struct { 590 BugA 591 BugD 592 } 593 594 // Test that a field with a tag dominates untagged fields. 595 func TestTaggedFieldDominates(t *testing.T) { 596 v := BugY{ 597 BugA{"BugA"}, 598 BugD{"BugD"}, 599 } 600 b, err := Marshal(v) 601 if err != nil { 602 t.Fatal("Marshal:", err) 603 } 604 want := `{"S":"BugD"}` 605 got := string(b) 606 if got != want { 607 t.Fatalf("Marshal: got %s want %s", got, want) 608 } 609 } 610 611 // There are no tags here, so S should not appear. 612 type BugZ struct { 613 BugA 614 BugC 615 BugY // Contains a tagged S field through BugD; should not dominate. 616 } 617 618 func TestDuplicatedFieldDisappears(t *testing.T) { 619 v := BugZ{ 620 BugA{"BugA"}, 621 BugC{"BugC"}, 622 BugY{ 623 BugA{"nested BugA"}, 624 BugD{"nested BugD"}, 625 }, 626 } 627 b, err := Marshal(v) 628 if err != nil { 629 t.Fatal("Marshal:", err) 630 } 631 want := `{}` 632 got := string(b) 633 if got != want { 634 t.Fatalf("Marshal: got %s want %s", got, want) 635 } 636 } 637 638 func TestIssue10281(t *testing.T) { 639 type Foo struct { 640 N Number 641 } 642 x := Foo{Number(`invalid`)} 643 644 b, err := Marshal(&x) 645 if err == nil { 646 t.Errorf("Marshal(&x) = %#q; want error", b) 647 } 648 } 649 650 var encodeStringTests = []struct { 651 in string 652 out string 653 }{ 654 {"\x00", `"\u0000"`}, 655 {"\x01", `"\u0001"`}, 656 {"\x02", `"\u0002"`}, 657 {"\x03", `"\u0003"`}, 658 {"\x04", `"\u0004"`}, 659 {"\x05", `"\u0005"`}, 660 {"\x06", `"\u0006"`}, 661 {"\x07", `"\u0007"`}, 662 {"\x08", `"\u0008"`}, 663 {"\x09", `"\t"`}, 664 {"\x0a", `"\n"`}, 665 {"\x0b", `"\u000b"`}, 666 {"\x0c", `"\u000c"`}, 667 {"\x0d", `"\r"`}, 668 {"\x0e", `"\u000e"`}, 669 {"\x0f", `"\u000f"`}, 670 {"\x10", `"\u0010"`}, 671 {"\x11", `"\u0011"`}, 672 {"\x12", `"\u0012"`}, 673 {"\x13", `"\u0013"`}, 674 {"\x14", `"\u0014"`}, 675 {"\x15", `"\u0015"`}, 676 {"\x16", `"\u0016"`}, 677 {"\x17", `"\u0017"`}, 678 {"\x18", `"\u0018"`}, 679 {"\x19", `"\u0019"`}, 680 {"\x1a", `"\u001a"`}, 681 {"\x1b", `"\u001b"`}, 682 {"\x1c", `"\u001c"`}, 683 {"\x1d", `"\u001d"`}, 684 {"\x1e", `"\u001e"`}, 685 {"\x1f", `"\u001f"`}, 686 } 687 688 func TestEncodeString(t *testing.T) { 689 for _, tt := range encodeStringTests { 690 b, err := Marshal(tt.in) 691 if err != nil { 692 t.Errorf("Marshal(%q): %v", tt.in, err) 693 continue 694 } 695 out := string(b) 696 if out != tt.out { 697 t.Errorf("Marshal(%q) = %#q, want %#q", tt.in, out, tt.out) 698 } 699 } 700 } 701 702 type jsonbyte byte 703 704 func (b jsonbyte) MarshalJSON() ([]byte, error) { return tenc(`{"JB":%d}`, b) } 705 706 type textbyte byte 707 708 func (b textbyte) MarshalText() ([]byte, error) { return tenc(`TB:%d`, b) } 709 710 type jsonint int 711 712 func (i jsonint) MarshalJSON() ([]byte, error) { return tenc(`{"JI":%d}`, i) } 713 714 type textint int 715 716 func (i textint) MarshalText() ([]byte, error) { return tenc(`TI:%d`, i) } 717 718 func tenc(format string, a ...any) ([]byte, error) { 719 var buf bytes.Buffer 720 fmt.Fprintf(&buf, format, a...) 721 return buf.Bytes(), nil 722 } 723 724 type textfloat float64 725 726 func (f textfloat) MarshalText() ([]byte, error) { return tenc(`TF:%0.2f`, f) } 727 728 // Issue 13783 729 func TestEncodeBytekind(t *testing.T) { 730 testdata := []struct { 731 data any 732 want string 733 }{ 734 {byte(7), "7"}, 735 {jsonbyte(7), `{"JB":7}`}, 736 {textbyte(4), `"TB:4"`}, 737 {jsonint(5), `{"JI":5}`}, 738 {textint(1), `"TI:1"`}, 739 {[]byte{0, 1}, `"AAE="`}, 740 {[]jsonbyte{0, 1}, `[{"JB":0},{"JB":1}]`}, 741 {[][]jsonbyte{{0, 1}, {3}}, `[[{"JB":0},{"JB":1}],[{"JB":3}]]`}, 742 {[]textbyte{2, 3}, `["TB:2","TB:3"]`}, 743 {[]jsonint{5, 4}, `[{"JI":5},{"JI":4}]`}, 744 {[]textint{9, 3}, `["TI:9","TI:3"]`}, 745 {[]int{9, 3}, `[9,3]`}, 746 {[]textfloat{12, 3}, `["TF:12.00","TF:3.00"]`}, 747 } 748 for _, d := range testdata { 749 js, err := Marshal(d.data) 750 if err != nil { 751 t.Error(err) 752 continue 753 } 754 got, want := string(js), d.want 755 if got != want { 756 t.Errorf("got %s, want %s", got, want) 757 } 758 } 759 } 760 761 var re = regexp.MustCompile 762 763 // syntactic checks on form of marshaled floating point numbers. 764 var badFloatREs = []*regexp.Regexp{ 765 re(`p`), // no binary exponential notation 766 re(`^\+`), // no leading + sign 767 re(`^-?0[^.]`), // no unnecessary leading zeros 768 re(`^-?\.`), // leading zero required before decimal point 769 re(`\.(e|$)`), // no trailing decimal 770 re(`\.[0-9]+0(e|$)`), // no trailing zero in fraction 771 re(`^-?(0|[0-9]{2,})\..*e`), // exponential notation must have normalized mantissa 772 re(`e[0-9]`), // positive exponent must be signed 773 re(`e[+-]0`), // exponent must not have leading zeros 774 re(`e-[1-6]$`), // not tiny enough for exponential notation 775 re(`e+(.|1.|20)$`), // not big enough for exponential notation 776 re(`^-?0\.0000000`), // too tiny, should use exponential notation 777 re(`^-?[0-9]{22}`), // too big, should use exponential notation 778 re(`[1-9][0-9]{16}[1-9]`), // too many significant digits in integer 779 re(`[1-9][0-9.]{17}[1-9]`), // too many significant digits in decimal 780 // below here for float32 only 781 re(`[1-9][0-9]{8}[1-9]`), // too many significant digits in integer 782 re(`[1-9][0-9.]{9}[1-9]`), // too many significant digits in decimal 783 } 784 785 func TestMarshalFloat(t *testing.T) { 786 t.Parallel() 787 nfail := 0 788 test := func(f float64, bits int) { 789 vf := any(f) 790 if bits == 32 { 791 f = float64(float32(f)) // round 792 vf = float32(f) 793 } 794 bout, err := Marshal(vf) 795 if err != nil { 796 t.Errorf("Marshal(%T(%g)): %v", vf, vf, err) 797 nfail++ 798 return 799 } 800 out := string(bout) 801 802 // result must convert back to the same float 803 g, err := strconv.ParseFloat(out, bits) 804 if err != nil { 805 t.Errorf("Marshal(%T(%g)) = %q, cannot parse back: %v", vf, vf, out, err) 806 nfail++ 807 return 808 } 809 if f != g || fmt.Sprint(f) != fmt.Sprint(g) { // fmt.Sprint handles ±0 810 t.Errorf("Marshal(%T(%g)) = %q (is %g, not %g)", vf, vf, out, float32(g), vf) 811 nfail++ 812 return 813 } 814 815 bad := badFloatREs 816 if bits == 64 { 817 bad = bad[:len(bad)-2] 818 } 819 for _, re := range bad { 820 if re.MatchString(out) { 821 t.Errorf("Marshal(%T(%g)) = %q, must not match /%s/", vf, vf, out, re) 822 nfail++ 823 return 824 } 825 } 826 } 827 828 var ( 829 bigger = math.Inf(+1) 830 smaller = math.Inf(-1) 831 ) 832 833 var digits = "1.2345678901234567890123" 834 for i := len(digits); i >= 2; i-- { 835 if testing.Short() && i < len(digits)-4 { 836 break 837 } 838 for exp := -30; exp <= 30; exp++ { 839 for _, sign := range "+-" { 840 for bits := 32; bits <= 64; bits += 32 { 841 s := fmt.Sprintf("%c%se%d", sign, digits[:i], exp) 842 f, err := strconv.ParseFloat(s, bits) 843 if err != nil { 844 log.Fatal(err) 845 } 846 next := math.Nextafter 847 if bits == 32 { 848 next = func(g, h float64) float64 { 849 return float64(math.Nextafter32(float32(g), float32(h))) 850 } 851 } 852 test(f, bits) 853 test(next(f, bigger), bits) 854 test(next(f, smaller), bits) 855 if nfail > 50 { 856 t.Fatalf("stopping test early") 857 } 858 } 859 } 860 } 861 } 862 test(0, 64) 863 test(math.Copysign(0, -1), 64) 864 test(0, 32) 865 test(math.Copysign(0, -1), 32) 866 } 867 868 type marshalPanic struct{} 869 870 func (marshalPanic) MarshalJSON() ([]byte, error) { panic(0xdead) } 871 872 func TestMarshalPanic(t *testing.T) { 873 defer func() { 874 if got := recover(); !reflect.DeepEqual(got, 0xdead) { 875 t.Errorf("panic() = (%T)(%v), want 0xdead", got, got) 876 } 877 }() 878 Marshal(&marshalPanic{}) 879 t.Error("Marshal should have panicked") 880 } 881 882 func TestMarshalUncommonFieldNames(t *testing.T) { 883 v := struct { 884 A0, À, Aβ int 885 }{} 886 b, err := Marshal(v) 887 if err != nil { 888 t.Fatal("Marshal:", err) 889 } 890 want := `{"A0":0,"À":0,"Aβ":0}` 891 got := string(b) 892 if got != want { 893 t.Fatalf("Marshal: got %s want %s", got, want) 894 } 895 } 896 897 type marshalTruncate struct { 898 Sr string `json:"sr"` 899 900 Blr []byte `json:"blr,random"` 901 902 Slr []string `json:"slr,random"` 903 904 Mr map[string]*marshalTruncate `json:"mr"` 905 906 Str *marshalTruncate `json:"str"` 907 } 908 909 var truncateExpected = `{ 910 "sr": "ab...26 chars", 911 "blr": "YWI=...52 bytes", 912 "slr": [ 913 "0 ...28 chars", 914 "1 ...54 chars", 915 "...7 elems" 916 ], 917 "mr": { 918 "a": { 919 "sr": "ab...26 chars", 920 "blr": "YWI=...26 bytes", 921 "slr": [ 922 "0 ...28 chars", 923 "1 ...54 chars", 924 "...7 elems" 925 ], 926 "mr": null, 927 "str": null 928 }, 929 "b": null, 930 "...4 pairs": "4" 931 }, 932 "str": { 933 "sr": "ab...26 chars", 934 "blr": "YWI=...26 bytes", 935 "slr": [ 936 "0 ...28 chars", 937 "1 ...54 chars", 938 "...7 elems" 939 ], 940 "mr": null, 941 "str": null 942 } 943 }` 944 945 func TestTruncateMarshal(t *testing.T) { 946 var o = marshalTruncate{ 947 Sr: "abcdefghihklmnopqrstuvwxyz", 948 Blr: []byte("abcdefghihklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 949 Slr: []string{"0 abcdefghihklmnopqrstuvwxyz", 950 "1 abcdefghihklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 951 "2 abcdefghihklmnopqrstuvwxyzA", 952 "3 abcdefghihklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 953 "4 abcdefghihklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 954 "5 abcdefghihklmnopqrstuvwxyzA", 955 "6 abcdefghihklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"}, 956 Mr: map[string]*marshalTruncate{ 957 "a": { 958 Sr: "abcdefghihklmnopqrstuvwxyz", 959 Blr: []byte("abcdefghihklmnopqrstuvwxyz"), 960 Slr: []string{"0 abcdefghihklmnopqrstuvwxyz", 961 "1 abcdefghihklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 962 "2 abcdefghihklmnopqrstuvwxyzA", 963 "3 abcdefghihklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 964 "4 abcdefghihklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 965 "5 abcdefghihklmnopqrstuvwxyzA", 966 "6 abcdefghihklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"}, 967 Mr: nil, 968 Str: nil, 969 }, 970 "b": nil, 971 "c": nil, 972 "d": nil, 973 }, 974 Str: &marshalTruncate{ 975 Sr: "abcdefghihklmnopqrstuvwxyz", 976 Blr: []byte("abcdefghihklmnopqrstuvwxyz"), 977 Slr: []string{"0 abcdefghihklmnopqrstuvwxyz", 978 "1 abcdefghihklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 979 "2 abcdefghihklmnopqrstuvwxyzA", 980 "3 abcdefghihklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 981 "4 abcdefghihklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 982 "5 abcdefghihklmnopqrstuvwxyzA", 983 "6 abcdefghihklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"}, 984 Mr: nil, 985 Str: nil, 986 }, 987 } 988 989 got, err := MarshalIndent(&o, "", " ", WithEncOptsTruncate(2)) 990 if err != nil { 991 t.Fatal(err) 992 } 993 if got := string(got); got != truncateExpected { 994 t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected) 995 } 996 }