summaryrefslogtreecommitdiff
path: root/borrowed_decode_test.go
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@datawire.io>2022-08-15 00:22:04 -0600
committerLuke Shumaker <lukeshu@datawire.io>2022-08-15 00:28:27 -0600
commit25d0b8365020ef4051dffd4f7704328402914613 (patch)
treec84662fd6431bd79559cfa9a7e3e2a7b75302867 /borrowed_decode_test.go
parentc11411d3591de78417f9ded2ca443c366f92367e (diff)
mkdir -p compat/json && mv borrowed_*_test.go compat/json/ # [ci-skip]
Diffstat (limited to 'borrowed_decode_test.go')
-rw-r--r--borrowed_decode_test.go2590
1 files changed, 0 insertions, 2590 deletions
diff --git a/borrowed_decode_test.go b/borrowed_decode_test.go
deleted file mode 100644
index ac8594b..0000000
--- a/borrowed_decode_test.go
+++ /dev/null
@@ -1,2590 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package lowmemjson // MODIFIED
-
-import (
- "bytes"
- "encoding"
- "errors"
- "fmt"
- "image"
- "io" // MODIFIED
- "math"
- "math/big"
- "net"
- "reflect"
- "strconv"
- "strings"
- "testing"
- "time"
-)
-
-type T struct {
- X string
- Y int
- Z int `json:"-"`
-}
-
-type U struct {
- Alphabet string `json:"alpha"`
-}
-
-type V struct {
- F1 any
- F2 int32
- F3 Number
- F4 *VOuter
-}
-
-type VOuter struct {
- V V
-}
-
-type W struct {
- S SS
-}
-
-type P struct {
- PP PP
-}
-
-type PP struct {
- T T
- Ts []T
-}
-
-type SS string
-
-func (*SS) UnmarshalJSON(data []byte) error {
- return &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(SS(""))}
-}
-
-// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and
-// without UseNumber
-var ifaceNumAsFloat64 = map[string]any{
- "k1": float64(1),
- "k2": "s",
- "k3": []any{float64(1), float64(2.0), float64(3e-3)},
- "k4": map[string]any{"kk1": "s", "kk2": float64(2)},
-}
-
-var ifaceNumAsNumber = map[string]any{
- "k1": Number("1"),
- "k2": "s",
- "k3": []any{Number("1"), Number("2.0"), Number("3e-3")},
- "k4": map[string]any{"kk1": "s", "kk2": Number("2")},
-}
-
-type tx struct {
- x int
-}
-
-type u8 uint8
-
-// A type that can unmarshal itself.
-
-type unmarshaler struct {
- T bool
-}
-
-func (u *unmarshaler) UnmarshalJSON(b []byte) error {
- *u = unmarshaler{true} // All we need to see that UnmarshalJSON is called.
- return nil
-}
-
-type ustruct struct {
- M unmarshaler
-}
-
-type unmarshalerText struct {
- A, B string
-}
-
-// needed for re-marshaling tests
-func (u unmarshalerText) MarshalText() ([]byte, error) {
- return []byte(u.A + ":" + u.B), nil
-}
-
-func (u *unmarshalerText) UnmarshalText(b []byte) error {
- pos := bytes.IndexByte(b, ':')
- if pos == -1 {
- return errors.New("missing separator")
- }
- u.A, u.B = string(b[:pos]), string(b[pos+1:])
- return nil
-}
-
-var _ encoding.TextUnmarshaler = (*unmarshalerText)(nil)
-
-type ustructText struct {
- M unmarshalerText
-}
-
-// u8marshal is an integer type that can marshal/unmarshal itself.
-type u8marshal uint8
-
-func (u8 u8marshal) MarshalText() ([]byte, error) {
- return []byte(fmt.Sprintf("u%d", u8)), nil
-}
-
-var errMissingU8Prefix = errors.New("missing 'u' prefix")
-
-func (u8 *u8marshal) UnmarshalText(b []byte) error {
- if !bytes.HasPrefix(b, []byte{'u'}) {
- return errMissingU8Prefix
- }
- n, err := strconv.Atoi(string(b[1:]))
- if err != nil {
- return err
- }
- *u8 = u8marshal(n)
- return nil
-}
-
-var _ encoding.TextUnmarshaler = (*u8marshal)(nil)
-
-var (
- umtrue = unmarshaler{true}
- umslice = []unmarshaler{{true}}
- umstruct = ustruct{unmarshaler{true}}
-
- umtrueXY = unmarshalerText{"x", "y"}
- umsliceXY = []unmarshalerText{{"x", "y"}}
- umstructXY = ustructText{unmarshalerText{"x", "y"}}
-
- ummapXY = map[unmarshalerText]bool{{"x", "y"}: true}
-)
-
-// Test data structures for anonymous fields.
-
-type Point struct {
- Z int
-}
-
-type Top struct {
- Level0 int
- Embed0
- *Embed0a
- *Embed0b `json:"e,omitempty"` // treated as named
- Embed0c `json:"-"` // ignored
- Loop
- Embed0p // has Point with X, Y, used
- Embed0q // has Point with Z, used
- embed // contains exported field
-}
-
-type Embed0 struct {
- Level1a int // overridden by Embed0a's Level1a with json tag
- Level1b int // used because Embed0a's Level1b is renamed
- Level1c int // used because Embed0a's Level1c is ignored
- Level1d int // annihilated by Embed0a's Level1d
- Level1e int `json:"x"` // annihilated by Embed0a.Level1e
-}
-
-type Embed0a struct {
- Level1a int `json:"Level1a,omitempty"`
- Level1b int `json:"LEVEL1B,omitempty"`
- Level1c int `json:"-"`
- Level1d int // annihilated by Embed0's Level1d
- Level1f int `json:"x"` // annihilated by Embed0's Level1e
-}
-
-type Embed0b Embed0
-
-type Embed0c Embed0
-
-type Embed0p struct {
- image.Point
-}
-
-type Embed0q struct {
- Point
-}
-
-type embed struct {
- Q int
-}
-
-type Loop struct {
- Loop1 int `json:",omitempty"`
- Loop2 int `json:",omitempty"`
- *Loop
-}
-
-// From reflect test:
-// The X in S6 and S7 annihilate, but they also block the X in S8.S9.
-type S5 struct {
- S6
- S7
- S8
-}
-
-type S6 struct {
- X int
-}
-
-type S7 S6
-
-type S8 struct {
- S9
-}
-
-type S9 struct {
- X int
- Y int
-}
-
-// From reflect test:
-// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9.
-type S10 struct {
- S11
- S12
- S13
-}
-
-type S11 struct {
- S6
-}
-
-type S12 struct {
- S6
-}
-
-type S13 struct {
- S8
-}
-
-type Ambig struct {
- // Given "hello", the first match should win.
- First int `json:"HELLO"`
- Second int `json:"Hello"`
-}
-
-type XYZ struct {
- X any
- Y any
- Z any
-}
-
-type unexportedWithMethods struct{}
-
-func (unexportedWithMethods) F() {}
-
-type byteWithMarshalJSON byte
-
-func (b byteWithMarshalJSON) MarshalJSON() ([]byte, error) {
- return []byte(fmt.Sprintf(`"Z%.2x"`, byte(b))), nil
-}
-
-func (b *byteWithMarshalJSON) UnmarshalJSON(data []byte) error {
- if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' {
- return fmt.Errorf("bad quoted string")
- }
- i, err := strconv.ParseInt(string(data[2:4]), 16, 8)
- if err != nil {
- return fmt.Errorf("bad hex")
- }
- *b = byteWithMarshalJSON(i)
- return nil
-}
-
-type byteWithPtrMarshalJSON byte
-
-func (b *byteWithPtrMarshalJSON) MarshalJSON() ([]byte, error) {
- return byteWithMarshalJSON(*b).MarshalJSON()
-}
-
-func (b *byteWithPtrMarshalJSON) UnmarshalJSON(data []byte) error {
- return (*byteWithMarshalJSON)(b).UnmarshalJSON(data)
-}
-
-type byteWithMarshalText byte
-
-func (b byteWithMarshalText) MarshalText() ([]byte, error) {
- return []byte(fmt.Sprintf(`Z%.2x`, byte(b))), nil
-}
-
-func (b *byteWithMarshalText) UnmarshalText(data []byte) error {
- if len(data) != 3 || data[0] != 'Z' {
- return fmt.Errorf("bad quoted string")
- }
- i, err := strconv.ParseInt(string(data[1:3]), 16, 8)
- if err != nil {
- return fmt.Errorf("bad hex")
- }
- *b = byteWithMarshalText(i)
- return nil
-}
-
-type byteWithPtrMarshalText byte
-
-func (b *byteWithPtrMarshalText) MarshalText() ([]byte, error) {
- return byteWithMarshalText(*b).MarshalText()
-}
-
-func (b *byteWithPtrMarshalText) UnmarshalText(data []byte) error {
- return (*byteWithMarshalText)(b).UnmarshalText(data)
-}
-
-type intWithMarshalJSON int
-
-func (b intWithMarshalJSON) MarshalJSON() ([]byte, error) {
- return []byte(fmt.Sprintf(`"Z%.2x"`, int(b))), nil
-}
-
-func (b *intWithMarshalJSON) UnmarshalJSON(data []byte) error {
- if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' {
- return fmt.Errorf("bad quoted string")
- }
- i, err := strconv.ParseInt(string(data[2:4]), 16, 8)
- if err != nil {
- return fmt.Errorf("bad hex")
- }
- *b = intWithMarshalJSON(i)
- return nil
-}
-
-type intWithPtrMarshalJSON int
-
-func (b *intWithPtrMarshalJSON) MarshalJSON() ([]byte, error) {
- return intWithMarshalJSON(*b).MarshalJSON()
-}
-
-func (b *intWithPtrMarshalJSON) UnmarshalJSON(data []byte) error {
- return (*intWithMarshalJSON)(b).UnmarshalJSON(data)
-}
-
-type intWithMarshalText int
-
-func (b intWithMarshalText) MarshalText() ([]byte, error) {
- return []byte(fmt.Sprintf(`Z%.2x`, int(b))), nil
-}
-
-func (b *intWithMarshalText) UnmarshalText(data []byte) error {
- if len(data) != 3 || data[0] != 'Z' {
- return fmt.Errorf("bad quoted string")
- }
- i, err := strconv.ParseInt(string(data[1:3]), 16, 8)
- if err != nil {
- return fmt.Errorf("bad hex")
- }
- *b = intWithMarshalText(i)
- return nil
-}
-
-type intWithPtrMarshalText int
-
-func (b *intWithPtrMarshalText) MarshalText() ([]byte, error) {
- return intWithMarshalText(*b).MarshalText()
-}
-
-func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error {
- return (*intWithMarshalText)(b).UnmarshalText(data)
-}
-
-type mapStringToStringData struct {
- Data map[string]string `json:"data"`
-}
-
-type unmarshalTest struct {
- in string
- ptr any // new(type)
- out any
- err error
- useNumber bool
- golden bool
- disallowUnknownFields bool
-}
-
-type B struct {
- B bool `json:",string"`
-}
-
-type DoublePtr struct {
- I **int
- J **int
-}
-
-var unmarshalTests = []unmarshalTest{
- // basic types
- {in: `true`, ptr: new(bool), out: true},
- {in: `1`, ptr: new(int), out: 1},
- {in: `1.2`, ptr: new(float64), out: 1.2},
- {in: `-5`, ptr: new(int16), out: int16(-5)},
- {in: `2`, ptr: new(Number), out: Number("2"), useNumber: true},
- {in: `2`, ptr: new(Number), out: Number("2")},
- {in: `2`, ptr: new(any), out: float64(2.0)},
- {in: `2`, ptr: new(any), out: Number("2"), useNumber: true},
- {in: `"a\u1234"`, ptr: new(string), out: "a\u1234"},
- {in: `"http:\/\/"`, ptr: new(string), out: "http://"},
- {in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"},
- {in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
- {in: "null", ptr: new(any), out: nil},
- {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7, "T", "X"}},
- {in: `{"X": 23}`, ptr: new(T), out: T{}, err: &UnmarshalTypeError{"number", reflect.TypeOf(""), 8, "T", "X"}}, {in: `{"x": 1}`, ptr: new(tx), out: tx{}},
- {in: `{"x": 1}`, ptr: new(tx), out: tx{}},
- {in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true},
- {in: `{"S": 23}`, ptr: new(W), out: W{}, err: &UnmarshalTypeError{"number", reflect.TypeOf(SS("")), 0, "W", "S"}},
- {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
- {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
- {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(any), out: ifaceNumAsFloat64},
- {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(any), out: ifaceNumAsNumber, useNumber: true},
-
- // raw values with whitespace
- {in: "\n true ", ptr: new(bool), out: true},
- {in: "\t 1 ", ptr: new(int), out: 1},
- {in: "\r 1.2 ", ptr: new(float64), out: 1.2},
- {in: "\t -5 \n", ptr: new(int16), out: int16(-5)},
- {in: "\t \"a\\u1234\" \n", ptr: new(string), out: "a\u1234"},
-
- // Z has a "-" tag.
- {in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}},
- {in: `{"Y": 1, "Z": 2}`, ptr: new(T), err: fmt.Errorf("json: unknown field \"Z\""), disallowUnknownFields: true},
-
- {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}},
- {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true},
- {in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}},
- {in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}},
- {in: `{"alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true},
-
- // syntax errors
- {in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after object key", 17}},
- {in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}},
- {in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true},
- {in: `[2, 3`, err: &SyntaxError{Err: "unexpected end of JSON input", Offset: 5}}, // MODIFIED
- {in: `{"F3": -}`, ptr: new(V), out: V{F3: Number("-")}, err: &SyntaxError{Err: "invalid character '}' in numeric literal", Offset: 9}}, // MODIFIED
-
- // raw value errors
- {in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
- {in: " 42 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 5}},
- {in: "\x01 true", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
- {in: " false \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 8}},
- {in: "\x01 1.2", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
- {in: " 3.4 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 6}},
- {in: "\x01 \"string\"", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
- {in: " \"string\" \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 11}},
-
- // array tests
- {in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}},
- {in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}},
- {in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}},
- {in: `[1, 2, 3]`, ptr: new(MustNotUnmarshalJSON), err: errors.New("MustNotUnmarshalJSON was used")},
-
- // empty array to interface test
- {in: `[]`, ptr: new([]any), out: []any{}},
- {in: `null`, ptr: new([]any), out: []any(nil)},
- {in: `{"T":[]}`, ptr: new(map[string]any), out: map[string]any{"T": []any{}}},
- {in: `{"T":null}`, ptr: new(map[string]any), out: map[string]any{"T": any(nil)}},
-
- // composite tests
- {in: allValueIndent, ptr: new(All), out: allValue},
- {in: allValueCompact, ptr: new(All), out: allValue},
- {in: allValueIndent, ptr: new(*All), out: &allValue},
- {in: allValueCompact, ptr: new(*All), out: &allValue},
- {in: pallValueIndent, ptr: new(All), out: pallValue},
- {in: pallValueCompact, ptr: new(All), out: pallValue},
- {in: pallValueIndent, ptr: new(*All), out: &pallValue},
- {in: pallValueCompact, ptr: new(*All), out: &pallValue},
-
- // unmarshal interface test
- {in: `{"T":false}`, ptr: new(unmarshaler), out: umtrue}, // use "false" so test will fail if custom unmarshaler is not called
- {in: `{"T":false}`, ptr: new(*unmarshaler), out: &umtrue},
- {in: `[{"T":false}]`, ptr: new([]unmarshaler), out: umslice},
- {in: `[{"T":false}]`, ptr: new(*[]unmarshaler), out: &umslice},
- {in: `{"M":{"T":"x:y"}}`, ptr: new(ustruct), out: umstruct},
-
- // UnmarshalText interface test
- {in: `"x:y"`, ptr: new(unmarshalerText), out: umtrueXY},
- {in: `"x:y"`, ptr: new(*unmarshalerText), out: &umtrueXY},
- {in: `["x:y"]`, ptr: new([]unmarshalerText), out: umsliceXY},
- {in: `["x:y"]`, ptr: new(*[]unmarshalerText), out: &umsliceXY},
- {in: `{"M":"x:y"}`, ptr: new(ustructText), out: umstructXY},
-
- // integer-keyed map test
- {
- in: `{"-1":"a","0":"b","1":"c"}`,
- ptr: new(map[int]string),
- out: map[int]string{-1: "a", 0: "b", 1: "c"},
- },
- {
- in: `{"0":"a","10":"c","9":"b"}`,
- ptr: new(map[u8]string),
- out: map[u8]string{0: "a", 9: "b", 10: "c"},
- },
- {
- in: `{"-9223372036854775808":"min","9223372036854775807":"max"}`,
- ptr: new(map[int64]string),
- out: map[int64]string{math.MinInt64: "min", math.MaxInt64: "max"},
- },
- {
- in: `{"18446744073709551615":"max"}`,
- ptr: new(map[uint64]string),
- out: map[uint64]string{math.MaxUint64: "max"},
- },
- {
- in: `{"0":false,"10":true}`,
- ptr: new(map[uintptr]bool),
- out: map[uintptr]bool{0: false, 10: true},
- },
-
- // Check that MarshalText and UnmarshalText take precedence
- // over default integer handling in map keys.
- {
- in: `{"u2":4}`,
- ptr: new(map[u8marshal]int),
- out: map[u8marshal]int{2: 4},
- },
- {
- in: `{"2":4}`,
- ptr: new(map[u8marshal]int),
- err: errMissingU8Prefix,
- },
-
- // integer-keyed map errors
- {
- in: `{"abc":"abc"}`,
- ptr: new(map[int]string),
- err: &UnmarshalTypeError{Value: "number abc", Type: reflect.TypeOf(0), Offset: 2},
- },
- {
- in: `{"256":"abc"}`,
- ptr: new(map[uint8]string),
- err: &UnmarshalTypeError{Value: "number 256", Type: reflect.TypeOf(uint8(0)), Offset: 2},
- },
- {
- in: `{"128":"abc"}`,
- ptr: new(map[int8]string),
- err: &UnmarshalTypeError{Value: "number 128", Type: reflect.TypeOf(int8(0)), Offset: 2},
- },
- {
- in: `{"-1":"abc"}`,
- ptr: new(map[uint8]string),
- err: &UnmarshalTypeError{Value: "number -1", Type: reflect.TypeOf(uint8(0)), Offset: 2},
- },
- {
- in: `{"F":{"a":2,"3":4}}`,
- ptr: new(map[string]map[int]int),
- err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeOf(int(0)), Offset: 7},
- },
- {
- in: `{"F":{"a":2,"3":4}}`,
- ptr: new(map[string]map[uint]int),
- err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeOf(uint(0)), Offset: 7},
- },
-
- // Map keys can be encoding.TextUnmarshalers.
- {in: `{"x:y":true}`, ptr: new(map[unmarshalerText]bool), out: ummapXY},
- // If multiple values for the same key exists, only the most recent value is used.
- {in: `{"x:y":false,"x:y":true}`, ptr: new(map[unmarshalerText]bool), out: ummapXY},
-
- {
- in: `{
- "Level0": 1,
- "Level1b": 2,
- "Level1c": 3,
- "x": 4,
- "Level1a": 5,
- "LEVEL1B": 6,
- "e": {
- "Level1a": 8,
- "Level1b": 9,
- "Level1c": 10,
- "Level1d": 11,
- "x": 12
- },
- "Loop1": 13,
- "Loop2": 14,
- "X": 15,
- "Y": 16,
- "Z": 17,
- "Q": 18
- }`,
- ptr: new(Top),
- out: Top{
- Level0: 1,
- Embed0: Embed0{
- Level1b: 2,
- Level1c: 3,
- },
- Embed0a: &Embed0a{
- Level1a: 5,
- Level1b: 6,
- },
- Embed0b: &Embed0b{
- Level1a: 8,
- Level1b: 9,
- Level1c: 10,
- Level1d: 11,
- Level1e: 12,
- },
- Loop: Loop{
- Loop1: 13,
- Loop2: 14,
- },
- Embed0p: Embed0p{
- Point: image.Point{X: 15, Y: 16},
- },
- Embed0q: Embed0q{
- Point: Point{Z: 17},
- },
- embed: embed{
- Q: 18,
- },
- },
- },
- {
- in: `{"hello": 1}`,
- ptr: new(Ambig),
- out: Ambig{First: 1},
- },
-
- {
- in: `{"X": 1,"Y":2}`,
- ptr: new(S5),
- out: S5{S8: S8{S9: S9{Y: 2}}},
- },
- {
- in: `{"X": 1,"Y":2}`,
- ptr: new(S5),
- err: fmt.Errorf("json: unknown field \"X\""),
- disallowUnknownFields: true,
- },
- {
- in: `{"X": 1,"Y":2}`,
- ptr: new(S10),
- out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}},
- },
- {
- in: `{"X": 1,"Y":2}`,
- ptr: new(S10),
- err: fmt.Errorf("json: unknown field \"X\""),
- disallowUnknownFields: true,
- },
- {
- in: `{"I": 0, "I": null, "J": null}`,
- ptr: new(DoublePtr),
- out: DoublePtr{I: nil, J: nil},
- },
-
- // invalid UTF-8 is coerced to valid UTF-8.
- {
- in: "\"hello\xffworld\"",
- ptr: new(string),
- out: "hello\ufffdworld",
- },
- {
- in: "\"hello\xc2\xc2world\"",
- ptr: new(string),
- out: "hello\ufffd\ufffdworld",
- },
- {
- in: "\"hello\xc2\xffworld\"",
- ptr: new(string),
- out: "hello\ufffd\ufffdworld",
- },
- {
- in: "\"hello\\ud800world\"",
- ptr: new(string),
- out: "hello\ufffdworld",
- },
- {
- in: "\"hello\\ud800\\ud800world\"",
- ptr: new(string),
- out: "hello\ufffd\ufffdworld",
- },
- {
- in: "\"hello\\ud800\\ud800world\"",
- ptr: new(string),
- out: "hello\ufffd\ufffdworld",
- },
- {
- in: "\"hello\xed\xa0\x80\xed\xb0\x80world\"",
- ptr: new(string),
- out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld",
- },
-
- // Used to be issue 8305, but time.Time implements encoding.TextUnmarshaler so this works now.
- {
- in: `{"2009-11-10T23:00:00Z": "hello world"}`,
- ptr: new(map[time.Time]string),
- out: map[time.Time]string{time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC): "hello world"},
- },
-
- // issue 8305
- {
- in: `{"2009-11-10T23:00:00Z": "hello world"}`,
- ptr: new(map[Point]string),
- err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[Point]string{}), Offset: 1},
- },
- {
- in: `{"asdf": "hello world"}`,
- ptr: new(map[unmarshaler]string),
- err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[unmarshaler]string{}), Offset: 1},
- },
-
- // related to issue 13783.
- // Go 1.7 changed marshaling a slice of typed byte to use the methods on the byte type,
- // similar to marshaling a slice of typed int.
- // These tests check that, assuming the byte type also has valid decoding methods,
- // either the old base64 string encoding or the new per-element encoding can be
- // successfully unmarshaled. The custom unmarshalers were accessible in earlier
- // versions of Go, even though the custom marshaler was not.
- {
- in: `"AQID"`,
- ptr: new([]byteWithMarshalJSON),
- out: []byteWithMarshalJSON{1, 2, 3},
- },
- {
- in: `["Z01","Z02","Z03"]`,
- ptr: new([]byteWithMarshalJSON),
- out: []byteWithMarshalJSON{1, 2, 3},
- golden: true,
- },
- {
- in: `"AQID"`,
- ptr: new([]byteWithMarshalText),
- out: []byteWithMarshalText{1, 2, 3},
- },
- {
- in: `["Z01","Z02","Z03"]`,
- ptr: new([]byteWithMarshalText),
- out: []byteWithMarshalText{1, 2, 3},
- golden: true,
- },
- {
- in: `"AQID"`,
- ptr: new([]byteWithPtrMarshalJSON),
- out: []byteWithPtrMarshalJSON{1, 2, 3},
- },
- {
- in: `["Z01","Z02","Z03"]`,
- ptr: new([]byteWithPtrMarshalJSON),
- out: []byteWithPtrMarshalJSON{1, 2, 3},
- golden: true,
- },
- {
- in: `"AQID"`,
- ptr: new([]byteWithPtrMarshalText),
- out: []byteWithPtrMarshalText{1, 2, 3},
- },
- {
- in: `["Z01","Z02","Z03"]`,
- ptr: new([]byteWithPtrMarshalText),
- out: []byteWithPtrMarshalText{1, 2, 3},
- golden: true,
- },
-
- // ints work with the marshaler but not the base64 []byte case
- {
- in: `["Z01","Z02","Z03"]`,
- ptr: new([]intWithMarshalJSON),
- out: []intWithMarshalJSON{1, 2, 3},
- golden: true,
- },
- {
- in: `["Z01","Z02","Z03"]`,
- ptr: new([]intWithMarshalText),
- out: []intWithMarshalText{1, 2, 3},
- golden: true,
- },
- {
- in: `["Z01","Z02","Z03"]`,
- ptr: new([]intWithPtrMarshalJSON),
- out: []intWithPtrMarshalJSON{1, 2, 3},
- golden: true,
- },
- {
- in: `["Z01","Z02","Z03"]`,
- ptr: new([]intWithPtrMarshalText),
- out: []intWithPtrMarshalText{1, 2, 3},
- golden: true,
- },
-
- {in: `0.000001`, ptr: new(float64), out: 0.000001, golden: true},
- {in: `1e-7`, ptr: new(float64), out: 1e-7, golden: true},
- {in: `100000000000000000000`, ptr: new(float64), out: 100000000000000000000.0, golden: true},
- {in: `1e+21`, ptr: new(float64), out: 1e21, golden: true},
- {in: `-0.000001`, ptr: new(float64), out: -0.000001, golden: true},
- {in: `-1e-7`, ptr: new(float64), out: -1e-7, golden: true},
- {in: `-100000000000000000000`, ptr: new(float64), out: -100000000000000000000.0, golden: true},
- {in: `-1e+21`, ptr: new(float64), out: -1e21, golden: true},
- {in: `999999999999999900000`, ptr: new(float64), out: 999999999999999900000.0, golden: true},
- {in: `9007199254740992`, ptr: new(float64), out: 9007199254740992.0, golden: true},
- {in: `9007199254740993`, ptr: new(float64), out: 9007199254740992.0, golden: false},
-
- {
- in: `{"V": {"F2": "hello"}}`,
- ptr: new(VOuter),
- err: &UnmarshalTypeError{
- Value: "string",
- Struct: "V",
- Field: "V.F2",
- Type: reflect.TypeOf(int32(0)),
- Offset: 20,
- },
- },
- {
- in: `{"V": {"F4": {}, "F2": "hello"}}`,
- ptr: new(VOuter),
- err: &UnmarshalTypeError{
- Value: "string",
- Struct: "V",
- Field: "V.F2",
- Type: reflect.TypeOf(int32(0)),
- Offset: 30,
- },
- },
-
- // issue 15146.
- // invalid inputs in wrongStringTests below.
- {in: `{"B":"true"}`, ptr: new(B), out: B{true}, golden: true},
- {in: `{"B":"false"}`, ptr: new(B), out: B{false}, golden: true},
- {in: `{"B": "maybe"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "maybe" into bool`)},
- {in: `{"B": "tru"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "tru" into bool`)},
- {in: `{"B": "False"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "False" into bool`)},
- {in: `{"B": "null"}`, ptr: new(B), out: B{false}},
- {in: `{"B": "nul"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "nul" into bool`)},
- {in: `{"B": [2, 3]}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal unquoted value into bool`)},
-
- // additional tests for disallowUnknownFields
- {
- in: `{
- "Level0": 1,
- "Level1b": 2,
- "Level1c": 3,
- "x": 4,
- "Level1a": 5,
- "LEVEL1B": 6,
- "e": {
- "Level1a": 8,
- "Level1b": 9,
- "Level1c": 10,
- "Level1d": 11,
- "x": 12
- },
- "Loop1": 13,
- "Loop2": 14,
- "X": 15,
- "Y": 16,
- "Z": 17,
- "Q": 18,
- "extra": true
- }`,
- ptr: new(Top),
- err: fmt.Errorf("json: unknown field \"extra\""),
- disallowUnknownFields: true,
- },
- {
- in: `{
- "Level0": 1,
- "Level1b": 2,
- "Level1c": 3,
- "x": 4,
- "Level1a": 5,
- "LEVEL1B": 6,
- "e": {
- "Level1a": 8,
- "Level1b": 9,
- "Level1c": 10,
- "Level1d": 11,
- "x": 12,
- "extra": null
- },
- "Loop1": 13,
- "Loop2": 14,
- "X": 15,
- "Y": 16,
- "Z": 17,
- "Q": 18
- }`,
- ptr: new(Top),
- err: fmt.Errorf("json: unknown field \"extra\""),
- disallowUnknownFields: true,
- },
- // issue 26444
- // UnmarshalTypeError without field & struct values
- {
- in: `{"data":{"test1": "bob", "test2": 123}}`,
- ptr: new(mapStringToStringData),
- err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 37, Struct: "mapStringToStringData", Field: "data"},
- },
- {
- in: `{"data":{"test1": 123, "test2": "bob"}}`,
- ptr: new(mapStringToStringData),
- err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 21, Struct: "mapStringToStringData", Field: "data"},
- },
-
- // trying to decode JSON arrays or objects via TextUnmarshaler
- {
- in: `[1, 2, 3]`,
- ptr: new(MustNotUnmarshalText),
- err: &UnmarshalTypeError{Value: "array", Type: reflect.TypeOf(&MustNotUnmarshalText{}), Offset: 1},
- },
- {
- in: `{"foo": "bar"}`,
- ptr: new(MustNotUnmarshalText),
- err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(&MustNotUnmarshalText{}), Offset: 1},
- },
- // #22369
- {
- in: `{"PP": {"T": {"Y": "bad-type"}}}`,
- ptr: new(P),
- err: &UnmarshalTypeError{
- Value: "string",
- Struct: "T",
- Field: "PP.T.Y",
- Type: reflect.TypeOf(int(0)),
- Offset: 29,
- },
- },
- {
- in: `{"Ts": [{"Y": 1}, {"Y": 2}, {"Y": "bad-type"}]}`,
- ptr: new(PP),
- err: &UnmarshalTypeError{
- Value: "string",
- Struct: "T",
- Field: "Ts.Y",
- Type: reflect.TypeOf(int(0)),
- Offset: 29,
- },
- },
- // #14702
- {
- in: `invalid`,
- ptr: new(Number),
- err: &SyntaxError{
- Err: "invalid character 'i' looking for beginning of value", // MODIFIED
- Offset: 1,
- },
- },
- {
- in: `"invalid"`,
- ptr: new(Number),
- err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`),
- },
- {
- in: `{"A":"invalid"}`,
- ptr: new(struct{ A Number }),
- err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`),
- },
- {
- in: `{"A":"invalid"}`,
- ptr: new(struct {
- A Number `json:",string"`
- }),
- err: fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into json.Number", `invalid`),
- },
- {
- in: `{"A":"invalid"}`,
- ptr: new(map[string]Number),
- err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`),
- },
-}
-
-func TestMarshal(t *testing.T) {
- b, err := Marshal(allValue)
- if err != nil {
- t.Fatalf("Marshal allValue: %v", err)
- }
- if string(b) != allValueCompact {
- t.Errorf("Marshal allValueCompact")
- diff(t, b, []byte(allValueCompact))
- return
- }
-
- b, err = Marshal(pallValue)
- if err != nil {
- t.Fatalf("Marshal pallValue: %v", err)
- }
- if string(b) != pallValueCompact {
- t.Errorf("Marshal pallValueCompact")
- diff(t, b, []byte(pallValueCompact))
- return
- }
-}
-
-var badUTF8 = []struct {
- in, out string
-}{
- {"hello\xffworld", `"hello\ufffdworld"`},
- {"", `""`},
- {"\xff", `"\ufffd"`},
- {"\xff\xff", `"\ufffd\ufffd"`},
- {"a\xffb", `"a\ufffdb"`},
- {"\xe6\x97\xa5\xe6\x9c\xac\xff\xaa\x9e", `"日本\ufffd\ufffd\ufffd"`},
-}
-
-func TestMarshalBadUTF8(t *testing.T) {
- for _, tt := range badUTF8 {
- b, err := Marshal(tt.in)
- if string(b) != tt.out || err != nil {
- t.Errorf("Marshal(%q) = %#q, %v, want %#q, nil", tt.in, b, err, tt.out)
- }
- }
-}
-
-func TestMarshalNumberZeroVal(t *testing.T) {
- var n Number
- out, err := Marshal(n)
- if err != nil {
- t.Fatal(err)
- }
- outStr := string(out)
- if outStr != "0" {
- t.Fatalf("Invalid zero val for Number: %q", outStr)
- }
-}
-
-func TestMarshalEmbeds(t *testing.T) {
- t.Skip() // TODO
- top := &Top{
- Level0: 1,
- Embed0: Embed0{
- Level1b: 2,
- Level1c: 3,
- },
- Embed0a: &Embed0a{
- Level1a: 5,
- Level1b: 6,
- },
- Embed0b: &Embed0b{
- Level1a: 8,
- Level1b: 9,
- Level1c: 10,
- Level1d: 11,
- Level1e: 12,
- },
- Loop: Loop{
- Loop1: 13,
- Loop2: 14,
- },
- Embed0p: Embed0p{
- Point: image.Point{X: 15, Y: 16},
- },
- Embed0q: Embed0q{
- Point: Point{Z: 17},
- },
- embed: embed{
- Q: 18,
- },
- }
- b, err := Marshal(top)
- if err != nil {
- t.Fatal(err)
- }
- want := "{\"Level0\":1,\"Level1b\":2,\"Level1c\":3,\"Level1a\":5,\"LEVEL1B\":6,\"e\":{\"Level1a\":8,\"Level1b\":9,\"Level1c\":10,\"Level1d\":11,\"x\":12},\"Loop1\":13,\"Loop2\":14,\"X\":15,\"Y\":16,\"Z\":17,\"Q\":18}"
- if string(b) != want {
- t.Errorf("Wrong marshal result.\n got: %q\nwant: %q", b, want)
- }
-}
-
-func equalError(a, b error) bool {
- if a == nil {
- return b == nil
- }
- if b == nil {
- return a == nil
- }
- return true // a.Error() == b.Error() // MODIFIED
-}
-
-func TestUnmarshal(t *testing.T) {
- t.Skip() // TODO
- for i, tt := range unmarshalTests {
- scan := &ReEncoder{
- Out: io.Discard,
- }
- in := []byte(tt.in)
- if _, err := scan.Write(in); err != nil {
- if !equalError(err, tt.err) {
- t.Errorf("#%d: checkValid: %#v\n\n%s", i, err, tt.in)
- continue
- }
- }
- if tt.ptr == nil {
- continue
- }
-
- typ := reflect.TypeOf(tt.ptr)
- if typ.Kind() != reflect.Pointer {
- t.Errorf("#%d: unmarshalTest.ptr %T is not a pointer type", i, tt.ptr)
- continue
- }
- typ = typ.Elem()
-
- // v = new(right-type)
- v := reflect.New(typ)
-
- if !reflect.DeepEqual(tt.ptr, v.Interface()) {
- // There's no reason for ptr to point to non-zero data,
- // as we decode into new(right-type), so the data is
- // discarded.
- // This can easily mean tests that silently don't test
- // what they should. To test decoding into existing
- // data, see TestPrefilled.
- t.Errorf("#%d: unmarshalTest.ptr %#v is not a pointer to a zero value", i, tt.ptr)
- continue
- }
-
- dec := NewDecoder(bytes.NewReader(in))
- if tt.useNumber {
- dec.UseNumber()
- }
- if tt.disallowUnknownFields {
- dec.DisallowUnknownFields()
- }
- if err := dec.Decode(v.Interface()); !equalError(err, tt.err) {
- t.Errorf("#%d: %v, want %v", i, err, tt.err)
- continue
- } else if err != nil {
- continue
- }
- if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
- t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v\n\n%s", i, v.Elem().Interface(), tt.out, tt.in)
- data, _ := Marshal(v.Elem().Interface())
- println(string(data))
- data, _ = Marshal(tt.out)
- println(string(data))
- continue
- }
-
- // Check round trip also decodes correctly.
- if tt.err == nil {
- enc, err := Marshal(v.Interface())
- if err != nil {
- t.Errorf("#%d: error re-marshaling: %v", i, err)
- continue
- }
- if tt.golden && !bytes.Equal(enc, in) {
- t.Errorf("#%d: remarshal mismatch:\nhave: %s\nwant: %s", i, enc, in)
- }
- vv := reflect.New(reflect.TypeOf(tt.ptr).Elem())
- dec = NewDecoder(bytes.NewReader(enc))
- if tt.useNumber {
- dec.UseNumber()
- }
- if err := dec.Decode(vv.Interface()); err != nil {
- t.Errorf("#%d: error re-unmarshaling %#q: %v", i, enc, err)
- continue
- }
- if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) {
- t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), vv.Elem().Interface())
- t.Errorf(" In: %q", strings.Map(noSpace, string(in)))
- t.Errorf("Marshal: %q", strings.Map(noSpace, string(enc)))
- continue
- }
- }
- }
-}
-
-func TestUnmarshalMarshal(t *testing.T) {
- initBig()
- var v any
- if err := Unmarshal(jsonBig, &v); err != nil {
- t.Fatalf("Unmarshal: %v", err)
- }
- b, err := Marshal(v)
- if err != nil {
- t.Fatalf("Marshal: %v", err)
- }
- if !bytes.Equal(jsonBig, b) {
- t.Errorf("Marshal jsonBig")
- diff(t, b, jsonBig)
- return
- }
-}
-
-var numberTests = []struct {
- in string
- i int64
- intErr string
- f float64
- floatErr string
-}{
- {in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid syntax", f: -1.23e1},
- {in: "-12", i: -12, f: -12.0},
- {in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid syntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"},
-}
-
-// Independent of Decode, basic coverage of the accessors in Number
-func TestNumberAccessors(t *testing.T) {
- for _, tt := range numberTests {
- n := Number(tt.in)
- if s := n.String(); s != tt.in {
- t.Errorf("Number(%q).String() is %q", tt.in, s)
- }
- if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt.i {
- t.Errorf("Number(%q).Int64() is %d", tt.in, i)
- } else if (err == nil && tt.intErr != "") || (err != nil && err.Error() != tt.intErr) {
- t.Errorf("Number(%q).Int64() wanted error %q but got: %v", tt.in, tt.intErr, err)
- }
- if f, err := n.Float64(); err == nil && tt.floatErr == "" && f != tt.f {
- t.Errorf("Number(%q).Float64() is %g", tt.in, f)
- } else if (err == nil && tt.floatErr != "") || (err != nil && err.Error() != tt.floatErr) {
- t.Errorf("Number(%q).Float64() wanted error %q but got: %v", tt.in, tt.floatErr, err)
- }
- }
-}
-
-func TestLargeByteSlice(t *testing.T) {
- s0 := make([]byte, 2000)
- for i := range s0 {
- s0[i] = byte(i)
- }
- b, err := Marshal(s0)
- if err != nil {
- t.Fatalf("Marshal: %v", err)
- }
- var s1 []byte
- if err := Unmarshal(b, &s1); err != nil {
- t.Fatalf("Unmarshal: %v", err)
- }
- if !bytes.Equal(s0, s1) {
- t.Errorf("Marshal large byte slice")
- diff(t, s0, s1)
- }
-}
-
-type Xint struct {
- X int
-}
-
-func TestUnmarshalInterface(t *testing.T) {
- var xint Xint
- var i any = &xint
- if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
- t.Fatalf("Unmarshal: %v", err)
- }
- if xint.X != 1 {
- t.Fatalf("Did not write to xint")
- }
-}
-
-func TestUnmarshalPtrPtr(t *testing.T) {
- var xint Xint
- pxint := &xint
- if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
- t.Fatalf("Unmarshal: %v", err)
- }
- if xint.X != 1 {
- t.Fatalf("Did not write to xint")
- }
-}
-
-func TestEscape(t *testing.T) {
- const input = `"foobar"<html>` + " [\u2028 \u2029]"
- const expected = `"\"foobar\"\u003chtml\u003e [\u2028 \u2029]"`
- b, err := Marshal(input)
- if err != nil {
- t.Fatalf("Marshal error: %v", err)
- }
- if s := string(b); s != expected {
- t.Errorf("Encoding of [%s]:\n got [%s]\nwant [%s]", input, s, expected)
- }
-}
-
-// WrongString is a struct that's misusing the ,string modifier.
-type WrongString struct {
- Message string `json:"result,string"`
-}
-
-type wrongStringTest struct {
- in, err string
-}
-
-var wrongStringTests = []wrongStringTest{
- {`{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`},
- {`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`},
- {`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`},
- {`{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`},
- {`{"result":"\""}`, `json: invalid use of ,string struct tag, trying to unmarshal "\"" into string`},
- {`{"result":"\"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "\"foo" into string`},
-}
-
-// If people misuse the ,string modifier, the error message should be
-// helpful, telling the user that they're doing it wrong.
-func TestErrorMessageFromMisusedString(t *testing.T) {
- for n, tt := range wrongStringTests {
- r := strings.NewReader(tt.in)
- var s WrongString
- err := NewDecoder(r).Decode(&s)
- got := fmt.Sprintf("%v", err)
- if err == nil { // if got != tt.err { // MODIFIED
- t.Errorf("%d. got err = %q, want %q", n, got, tt.err)
- }
- }
-}
-
-func noSpace(c rune) rune {
- if isSpace(byte(c)) { //only used for ascii
- return -1
- }
- return c
-}
-
-type All struct {
- Bool bool
- Int int
- Int8 int8
- Int16 int16
- Int32 int32
- Int64 int64
- Uint uint
- Uint8 uint8
- Uint16 uint16
- Uint32 uint32
- Uint64 uint64
- Uintptr uintptr
- Float32 float32
- Float64 float64
-
- Foo string `json:"bar"`
- Foo2 string `json:"bar2,dummyopt"`
-
- IntStr int64 `json:",string"`
- UintptrStr uintptr `json:",string"`
-
- PBool *bool
- PInt *int
- PInt8 *int8
- PInt16 *int16
- PInt32 *int32
- PInt64 *int64
- PUint *uint
- PUint8 *uint8
- PUint16 *uint16
- PUint32 *uint32
- PUint64 *uint64
- PUintptr *uintptr
- PFloat32 *float32
- PFloat64 *float64
-
- String string
- PString *string
-
- Map map[string]Small
- MapP map[string]*Small
- PMap *map[string]Small
- PMapP *map[string]*Small
-
- EmptyMap map[string]Small
- NilMap map[string]Small
-
- Slice []Small
- SliceP []*Small
- PSlice *[]Small
- PSliceP *[]*Small
-
- EmptySlice []Small
- NilSlice []Small
-
- StringSlice []string
- ByteSlice []byte
-
- Small Small
- PSmall *Small
- PPSmall **Small
-
- Interface any
- PInterface *any
-
- unexported int
-}
-
-type Small struct {
- Tag string
-}
-
-var allValue = All{
- Bool: true,
- Int: 2,
- Int8: 3,
- Int16: 4,
- Int32: 5,
- Int64: 6,
- Uint: 7,
- Uint8: 8,
- Uint16: 9,
- Uint32: 10,
- Uint64: 11,
- Uintptr: 12,
- Float32: 14.1,
- Float64: 15.1,
- Foo: "foo",
- Foo2: "foo2",
- IntStr: 42,
- UintptrStr: 44,
- String: "16",
- Map: map[string]Small{
- "17": {Tag: "tag17"},
- "18": {Tag: "tag18"},
- },
- MapP: map[string]*Small{
- "19": {Tag: "tag19"},
- "20": nil,
- },
- EmptyMap: map[string]Small{},
- Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}},
- SliceP: []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}},
- EmptySlice: []Small{},
- StringSlice: []string{"str24", "str25", "str26"},
- ByteSlice: []byte{27, 28, 29},
- Small: Small{Tag: "tag30"},
- PSmall: &Small{Tag: "tag31"},
- Interface: 5.2,
-}
-
-var pallValue = All{
- PBool: &allValue.Bool,
- PInt: &allValue.Int,
- PInt8: &allValue.Int8,
- PInt16: &allValue.Int16,
- PInt32: &allValue.Int32,
- PInt64: &allValue.Int64,
- PUint: &allValue.Uint,
- PUint8: &allValue.Uint8,
- PUint16: &allValue.Uint16,
- PUint32: &allValue.Uint32,
- PUint64: &allValue.Uint64,
- PUintptr: &allValue.Uintptr,
- PFloat32: &allValue.Float32,
- PFloat64: &allValue.Float64,
- PString: &allValue.String,
- PMap: &allValue.Map,
- PMapP: &allValue.MapP,
- PSlice: &allValue.Slice,
- PSliceP: &allValue.SliceP,
- PPSmall: &allValue.PSmall,
- PInterface: &allValue.Interface,
-}
-
-var allValueIndent = `{
- "Bool": true,
- "Int": 2,
- "Int8": 3,
- "Int16": 4,
- "Int32": 5,
- "Int64": 6,
- "Uint": 7,
- "Uint8": 8,
- "Uint16": 9,
- "Uint32": 10,
- "Uint64": 11,
- "Uintptr": 12,
- "Float32": 14.1,
- "Float64": 15.1,
- "bar": "foo",
- "bar2": "foo2",
- "IntStr": "42",
- "UintptrStr": "44",
- "PBool": null,
- "PInt": null,
- "PInt8": null,
- "PInt16": null,
- "PInt32": null,
- "PInt64": null,
- "PUint": null,
- "PUint8": null,
- "PUint16": null,
- "PUint32": null,
- "PUint64": null,
- "PUintptr": null,
- "PFloat32": null,
- "PFloat64": null,
- "String": "16",
- "PString": null,
- "Map": {
- "17": {
- "Tag": "tag17"
- },
- "18": {
- "Tag": "tag18"
- }
- },
- "MapP": {
- "19": {
- "Tag": "tag19"
- },
- "20": null
- },
- "PMap": null,
- "PMapP": null,
- "EmptyMap": {},
- "NilMap": null,
- "Slice": [
- {
- "Tag": "tag20"
- },
- {
- "Tag": "tag21"
- }
- ],
- "SliceP": [
- {
- "Tag": "tag22"
- },
- null,
- {
- "Tag": "tag23"
- }
- ],
- "PSlice": null,
- "PSliceP": null,
- "EmptySlice": [],
- "NilSlice": null,
- "StringSlice": [
- "str24",
- "str25",
- "str26"
- ],
- "ByteSlice": "Gxwd",
- "Small": {
- "Tag": "tag30"
- },
- "PSmall": {
- "Tag": "tag31"
- },
- "PPSmall": null,
- "Interface": 5.2,
- "PInterface": null
-}`
-
-var allValueCompact = strings.Map(noSpace, allValueIndent)
-
-var pallValueIndent = `{
- "Bool": false,
- "Int": 0,
- "Int8": 0,
- "Int16": 0,
- "Int32": 0,
- "Int64": 0,
- "Uint": 0,
- "Uint8": 0,
- "Uint16": 0,
- "Uint32": 0,
- "Uint64": 0,
- "Uintptr": 0,
- "Float32": 0,
- "Float64": 0,
- "bar": "",
- "bar2": "",
- "IntStr": "0",
- "UintptrStr": "0",
- "PBool": true,
- "PInt": 2,
- "PInt8": 3,
- "PInt16": 4,
- "PInt32": 5,
- "PInt64": 6,
- "PUint": 7,
- "PUint8": 8,
- "PUint16": 9,
- "PUint32": 10,
- "PUint64": 11,
- "PUintptr": 12,
- "PFloat32": 14.1,
- "PFloat64": 15.1,
- "String": "",
- "PString": "16",
- "Map": null,
- "MapP": null,
- "PMap": {
- "17": {
- "Tag": "tag17"
- },
- "18": {
- "Tag": "tag18"
- }
- },
- "PMapP": {
- "19": {
- "Tag": "tag19"
- },
- "20": null
- },
- "EmptyMap": null,
- "NilMap": null,
- "Slice": null,
- "SliceP": null,
- "PSlice": [
- {
- "Tag": "tag20"
- },
- {
- "Tag": "tag21"
- }
- ],
- "PSliceP": [
- {
- "Tag": "tag22"
- },
- null,
- {
- "Tag": "tag23"
- }
- ],
- "EmptySlice": null,
- "NilSlice": null,
- "StringSlice": null,
- "ByteSlice": null,
- "Small": {
- "Tag": ""
- },
- "PSmall": null,
- "PPSmall": {
- "Tag": "tag31"
- },
- "Interface": null,
- "PInterface": 5.2
-}`
-
-var pallValueCompact = strings.Map(noSpace, pallValueIndent)
-
-func TestRefUnmarshal(t *testing.T) {
- type S struct {
- // Ref is defined in encode_test.go.
- R0 Ref
- R1 *Ref
- R2 RefText
- R3 *RefText
- }
- want := S{
- R0: 12,
- R1: new(Ref),
- R2: 13,
- R3: new(RefText),
- }
- *want.R1 = 12
- *want.R3 = 13
-
- var got S
- if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref","R2":"ref","R3":"ref"}`), &got); err != nil {
- t.Fatalf("Unmarshal: %v", err)
- }
- if !reflect.DeepEqual(got, want) {
- t.Errorf("got %+v, want %+v", got, want)
- }
-}
-
-// Test that the empty string doesn't panic decoding when ,string is specified
-// Issue 3450
-func TestEmptyString(t *testing.T) {
- type T2 struct {
- Number1 int `json:",string"`
- Number2 int `json:",string"`
- }
- data := `{"Number1":"1", "Number2":""}`
- dec := NewDecoder(strings.NewReader(data))
- var t2 T2
- err := dec.Decode(&t2)
- if err == nil {
- t.Fatal("Decode: did not return error")
- }
- if t2.Number1 != 1 {
- t.Fatal("Decode: did not set Number1")
- }
-}
-
-// Test that a null for ,string is not replaced with the previous quoted string (issue 7046).
-// It should also not be an error (issue 2540, issue 8587).
-func TestNullString(t *testing.T) {
- type T struct {
- A int `json:",string"`
- B int `json:",string"`
- C *int `json:",string"`
- }
- data := []byte(`{"A": "1", "B": null, "C": null}`)
- var s T
- s.B = 1
- s.C = new(int)
- *s.C = 2
- err := Unmarshal(data, &s)
- if err != nil {
- t.Fatalf("Unmarshal: %v", err)
- }
- if s.B != 1 || s.C != nil {
- t.Fatalf("after Unmarshal, s.B=%d, s.C=%p, want 1, nil", s.B, s.C)
- }
-}
-
-func intp(x int) *int {
- p := new(int)
- *p = x
- return p
-}
-
-func intpp(x *int) **int {
- pp := new(*int)
- *pp = x
- return pp
-}
-
-var interfaceSetTests = []struct {
- pre any
- json string
- post any
-}{
- {"foo", `"bar"`, "bar"},
- {"foo", `2`, 2.0},
- {"foo", `true`, true},
- {"foo", `null`, nil},
-
- {nil, `null`, nil},
- {new(int), `null`, nil},
- {(*int)(nil), `null`, nil},
- {new(*int), `null`, new(*int)},
- {(**int)(nil), `null`, nil},
- {intp(1), `null`, nil},
- {intpp(nil), `null`, intpp(nil)},
- {intpp(intp(1)), `null`, intpp(nil)},
-}
-
-func TestInterfaceSet(t *testing.T) {
- t.Skip() // TODO
- for _, tt := range interfaceSetTests {
- b := struct{ X any }{tt.pre}
- blob := `{"X":` + tt.json + `}`
- if err := Unmarshal([]byte(blob), &b); err != nil {
- t.Errorf("Unmarshal %#q: %v", blob, err)
- continue
- }
- if !reflect.DeepEqual(b.X, tt.post) {
- t.Errorf("Unmarshal %#q into %#v: X=%#v, want %#v", blob, tt.pre, b.X, tt.post)
- }
- }
-}
-
-type NullTest struct {
- Bool bool
- Int int
- Int8 int8
- Int16 int16
- Int32 int32
- Int64 int64
- Uint uint
- Uint8 uint8
- Uint16 uint16
- Uint32 uint32
- Uint64 uint64
- Float32 float32
- Float64 float64
- String string
- PBool *bool
- Map map[string]string
- Slice []string
- Interface any
-
- PRaw *RawMessage
- PTime *time.Time
- PBigInt *big.Int
- PText *MustNotUnmarshalText
- PBuffer *bytes.Buffer // has methods, just not relevant ones
- PStruct *struct{}
-
- Raw RawMessage
- Time time.Time
- BigInt big.Int
- Text MustNotUnmarshalText
- Buffer bytes.Buffer
- Struct struct{}
-}
-
-// JSON null values should be ignored for primitives and string values instead of resulting in an error.
-// Issue 2540
-func TestUnmarshalNulls(t *testing.T) {
- // Unmarshal docs:
- // The JSON null value unmarshals into an interface, map, pointer, or slice
- // by setting that Go value to nil. Because null is often used in JSON to mean
- // ``not present,'' unmarshaling a JSON null into any other Go type has no effect
- // on the value and produces no error.
-
- jsonData := []byte(`{
- "Bool" : null,
- "Int" : null,
- "Int8" : null,
- "Int16" : null,
- "Int32" : null,
- "Int64" : null,
- "Uint" : null,
- "Uint8" : null,
- "Uint16" : null,
- "Uint32" : null,
- "Uint64" : null,
- "Float32" : null,
- "Float64" : null,
- "String" : null,
- "PBool": null,
- "Map": null,
- "Slice": null,
- "Interface": null,
- "PRaw": null,
- "PTime": null,
- "PBigInt": null,
- "PText": null,
- "PBuffer": null,
- "PStruct": null,
- "Raw": null,
- "Time": null,
- "BigInt": null,
- "Text": null,
- "Buffer": null,
- "Struct": null
- }`)
- nulls := NullTest{
- Bool: true,
- Int: 2,
- Int8: 3,
- Int16: 4,
- Int32: 5,
- Int64: 6,
- Uint: 7,
- Uint8: 8,
- Uint16: 9,
- Uint32: 10,
- Uint64: 11,
- Float32: 12.1,
- Float64: 13.1,
- String: "14",
- PBool: new(bool),
- Map: map[string]string{},
- Slice: []string{},
- Interface: new(MustNotUnmarshalJSON),
- PRaw: new(RawMessage),
- PTime: new(time.Time),
- PBigInt: new(big.Int),
- PText: new(MustNotUnmarshalText),
- PStruct: new(struct{}),
- PBuffer: new(bytes.Buffer),
- Raw: RawMessage("123"),
- Time: time.Unix(123456789, 0),
- BigInt: *big.NewInt(123),
- }
-
- before := nulls.Time.String()
-
- err := Unmarshal(jsonData, &nulls)
- if err != nil {
- t.Errorf("Unmarshal of null values failed: %v", err)
- }
- if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 ||
- nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 ||
- nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" {
- t.Errorf("Unmarshal of null values affected primitives")
- }
-
- if nulls.PBool != nil {
- t.Errorf("Unmarshal of null did not clear nulls.PBool")
- }
- if nulls.Map != nil {
- t.Errorf("Unmarshal of null did not clear nulls.Map")
- }
- if nulls.Slice != nil {
- t.Errorf("Unmarshal of null did not clear nulls.Slice")
- }
- if nulls.Interface != nil {
- t.Errorf("Unmarshal of null did not clear nulls.Interface")
- }
- if nulls.PRaw != nil {
- t.Errorf("Unmarshal of null did not clear nulls.PRaw")
- }
- if nulls.PTime != nil {
- t.Errorf("Unmarshal of null did not clear nulls.PTime")
- }
- if nulls.PBigInt != nil {
- t.Errorf("Unmarshal of null did not clear nulls.PBigInt")
- }
- if nulls.PText != nil {
- t.Errorf("Unmarshal of null did not clear nulls.PText")
- }
- if nulls.PBuffer != nil {
- t.Errorf("Unmarshal of null did not clear nulls.PBuffer")
- }
- if nulls.PStruct != nil {
- t.Errorf("Unmarshal of null did not clear nulls.PStruct")
- }
-
- if string(nulls.Raw) != "null" {
- t.Errorf("Unmarshal of RawMessage null did not record null: %v", string(nulls.Raw))
- }
- if nulls.Time.String() != before {
- t.Errorf("Unmarshal of time.Time null set time to %v", nulls.Time.String())
- }
- if nulls.BigInt.String() != "123" {
- t.Errorf("Unmarshal of big.Int null set int to %v", nulls.BigInt.String())
- }
-}
-
-type MustNotUnmarshalJSON struct{}
-
-func (x MustNotUnmarshalJSON) UnmarshalJSON(data []byte) error {
- return errors.New("MustNotUnmarshalJSON was used")
-}
-
-type MustNotUnmarshalText struct{}
-
-func (x MustNotUnmarshalText) UnmarshalText(text []byte) error {
- return errors.New("MustNotUnmarshalText was used")
-}
-
-func TestStringKind(t *testing.T) {
- type stringKind string
-
- var m1, m2 map[stringKind]int
- m1 = map[stringKind]int{
- "foo": 42,
- }
-
- data, err := Marshal(m1)
- if err != nil {
- t.Errorf("Unexpected error marshaling: %v", err)
- }
-
- err = Unmarshal(data, &m2)
- if err != nil {
- t.Errorf("Unexpected error unmarshaling: %v", err)
- }
-
- if !reflect.DeepEqual(m1, m2) {
- t.Error("Items should be equal after encoding and then decoding")
- }
-}
-
-// Custom types with []byte as underlying type could not be marshaled
-// and then unmarshaled.
-// Issue 8962.
-func TestByteKind(t *testing.T) {
- type byteKind []byte
-
- a := byteKind("hello")
-
- data, err := Marshal(a)
- if err != nil {
- t.Error(err)
- }
- if !reflect.DeepEqual(data, []byte(`"aGVsbG8="`)) { // MODIFIED
- t.Errorf("expected %q == %q", data, `"aGVsbG8="`) // MODIFIED
- } // MODIFIED
- var b byteKind
- err = Unmarshal(data, &b)
- if err != nil {
- t.Fatal(err)
- }
- if !reflect.DeepEqual(a, b) {
- t.Errorf("expected %v == %v", a, b)
- }
-}
-
-// The fix for issue 8962 introduced a regression.
-// Issue 12921.
-func TestSliceOfCustomByte(t *testing.T) {
- type Uint8 uint8
-
- a := []Uint8("hello")
-
- data, err := Marshal(a)
- if err != nil {
- t.Fatal(err)
- }
- if !reflect.DeepEqual(data, []byte(`"aGVsbG8="`)) { // MODIFIED
- t.Errorf("expected %q == %q", data, `"aGVsbG8="`) // MODIFIED
- } // MODIFIED
- var b []Uint8
- err = Unmarshal(data, &b)
- if err != nil {
- t.Fatal(err)
- }
- if !reflect.DeepEqual(a, b) {
- t.Fatalf("expected %v == %v", a, b)
- }
-}
-
-var decodeTypeErrorTests = []struct {
- dest any
- src string
-}{
- {new(string), `{"user": "name"}`}, // issue 4628.
- {new(error), `{}`}, // issue 4222
- {new(error), `[]`},
- {new(error), `""`},
- {new(error), `123`},
- {new(error), `true`},
-}
-
-func TestUnmarshalTypeError(t *testing.T) {
- for _, item := range decodeTypeErrorTests {
- err := Unmarshal([]byte(item.src), item.dest)
- if err == nil { // if _, ok := err.(*UnmarshalTypeError); !ok { // MODIFIED
- t.Errorf("expected type error for Unmarshal(%q, type %T): got %T",
- item.src, item.dest, err)
- }
- }
-}
-
-var unmarshalSyntaxTests = []string{
- "tru",
- "fals",
- "nul",
- "123e",
- `"hello`,
- `[1,2,3`,
- `{"key":1`,
- `{"key":1,`,
-}
-
-func TestUnmarshalSyntax(t *testing.T) {
- var x any
- for _, src := range unmarshalSyntaxTests {
- err := Unmarshal([]byte(src), &x)
- if err == nil { // _, ok := err.(*SyntaxError); !ok { // MODIFIED
- t.Errorf("expected syntax error for Unmarshal(%q): got %T", src, err)
- }
- }
-}
-
-// Test handling of unexported fields that should be ignored.
-// Issue 4660
-type unexportedFields struct {
- Name string
- m map[string]any `json:"-"`
- m2 map[string]any `json:"abcd"`
-
- s []int `json:"-"`
-}
-
-func TestUnmarshalUnexported(t *testing.T) {
- input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}, "s": [2, 3]}`
- want := &unexportedFields{Name: "Bob"}
-
- out := &unexportedFields{}
- err := Unmarshal([]byte(input), out)
- if err != nil {
- t.Errorf("got error %v, expected nil", err)
- }
- if !reflect.DeepEqual(out, want) {
- t.Errorf("got %q, want %q", out, want)
- }
-}
-
-// Time3339 is a time.Time which encodes to and from JSON
-// as an RFC 3339 time in UTC.
-type Time3339 time.Time
-
-func (t *Time3339) UnmarshalJSON(b []byte) error {
- if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
- return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time", b)
- }
- tm, err := time.Parse(time.RFC3339, string(b[1:len(b)-1]))
- if err != nil {
- return err
- }
- *t = Time3339(tm)
- return nil
-}
-
-func TestUnmarshalJSONLiteralError(t *testing.T) {
- var t3 Time3339
- err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3)
- if err == nil {
- t.Fatalf("expected error; got time %v", time.Time(t3))
- }
- if !strings.Contains(err.Error(), "range") {
- t.Errorf("got err = %v; want out of range error", err)
- }
-}
-
-// Test that extra object elements in an array do not result in a
-// "data changing underfoot" error.
-// Issue 3717
-func TestSkipArrayObjects(t *testing.T) {
- json := `[{}]`
- var dest [0]any
-
- err := Unmarshal([]byte(json), &dest)
- if err != nil {
- t.Errorf("got error %q, want nil", err)
- }
-}
-
-// Test semantics of pre-filled data, such as struct fields, map elements,
-// slices, and arrays.
-// Issues 4900 and 8837, among others.
-func TestPrefilled(t *testing.T) {
- // Values here change, cannot reuse table across runs.
- var prefillTests = []struct {
- in string
- ptr any
- out any
- }{
- {
- in: `{"X": 1, "Y": 2}`,
- ptr: &XYZ{X: float32(3), Y: int16(4), Z: 1.5},
- out: &XYZ{X: float64(1), Y: float64(2), Z: 1.5},
- },
- {
- in: `{"X": 1, "Y": 2}`,
- ptr: &map[string]any{"X": float32(3), "Y": int16(4), "Z": 1.5},
- out: &map[string]any{"X": float64(1), "Y": float64(2), "Z": 1.5},
- },
- {
- in: `[2]`,
- ptr: &[]int{1},
- out: &[]int{2},
- },
- {
- in: `[2, 3]`,
- ptr: &[]int{1},
- out: &[]int{2, 3},
- },
- {
- in: `[2, 3]`,
- ptr: &[...]int{1},
- out: &[...]int{2},
- },
- {
- in: `[3]`,
- ptr: &[...]int{1, 2},
- out: &[...]int{3, 0},
- },
- }
-
- for _, tt := range prefillTests {
- ptrstr := fmt.Sprintf("%v", tt.ptr)
- err := Unmarshal([]byte(tt.in), tt.ptr) // tt.ptr edited here
- if err != nil {
- t.Errorf("Unmarshal: %v", err)
- }
- if !reflect.DeepEqual(tt.ptr, tt.out) {
- t.Errorf("Unmarshal(%#q, %s): have %v, want %v", tt.in, ptrstr, tt.ptr, tt.out)
- }
- }
-}
-
-var invalidUnmarshalTests = []struct {
- v any
- want string
-}{
- {nil, "json: Unmarshal(nil)"},
- {struct{}{}, "json: Unmarshal(non-pointer struct {})"},
- {(*int)(nil), "json: Unmarshal(nil *int)"},
-}
-
-func TestInvalidUnmarshal(t *testing.T) {
- buf := []byte(`{"a":"1"}`)
- for _, tt := range invalidUnmarshalTests {
- err := Unmarshal(buf, tt.v)
- if err == nil {
- t.Errorf("Unmarshal expecting error, got nil")
- continue
- }
- if got := err.Error(); got != tt.want {
- t.Errorf("Unmarshal = %q; want %q", got, tt.want)
- }
- }
-}
-
-var invalidUnmarshalTextTests = []struct {
- v any
- want string
-}{
- {nil, "json: Unmarshal(nil)"},
- {struct{}{}, "json: Unmarshal(non-pointer struct {})"},
- {(*int)(nil), "json: Unmarshal(nil *int)"},
- {new(net.IP), "json: cannot unmarshal number into Go value of type *net.IP"},
-}
-
-func TestInvalidUnmarshalText(t *testing.T) {
- buf := []byte(`123`)
- for _, tt := range invalidUnmarshalTextTests {
- err := Unmarshal(buf, tt.v)
- if err == nil {
- t.Errorf("Unmarshal expecting error, got nil")
- continue
- }
- // if got := err.Error(); got != tt.want { // MODIFIED
- // t.Errorf("Unmarshal = %q; want %q", got, tt.want) // MODIFIED
- // } // MODIFIED
- }
-}
-
-// Test that string option is ignored for invalid types.
-// Issue 9812.
-func TestInvalidStringOption(t *testing.T) {
- num := 0
- item := struct {
- T time.Time `json:",string"`
- M map[string]string `json:",string"`
- S []string `json:",string"`
- A [1]string `json:",string"`
- I any `json:",string"`
- P *int `json:",string"`
- }{M: make(map[string]string), S: make([]string, 0), I: num, P: &num}
-
- data, err := Marshal(item)
- if err != nil {
- t.Fatalf("Marshal: %v", err)
- }
-
- err = Unmarshal(data, &item)
- if err != nil {
- t.Fatalf("Unmarshal: %v", err)
- }
-}
-
-// Test unmarshal behavior with regards to embedded unexported structs.
-//
-// (Issue 21357) If the embedded struct is a pointer and is unallocated,
-// this returns an error because unmarshal cannot set the field.
-//
-// (Issue 24152) If the embedded struct is given an explicit name,
-// ensure that the normal unmarshal logic does not panic in reflect.
-//
-// (Issue 28145) If the embedded struct is given an explicit name and has
-// exported methods, don't cause a panic trying to get its value.
-func TestUnmarshalEmbeddedUnexported(t *testing.T) {
- t.Skip() // TODO
- type (
- embed1 struct{ Q int }
- embed2 struct{ Q int }
- embed3 struct {
- Q int64 `json:",string"`
- }
- S1 struct {
- *embed1
- R int
- }
- S2 struct {
- *embed1
- Q int
- }
- S3 struct {
- embed1
- R int
- }
- S4 struct {
- *embed1
- embed2
- }
- S5 struct {
- *embed3
- R int
- }
- S6 struct {
- embed1 `json:"embed1"`
- }
- S7 struct {
- embed1 `json:"embed1"`
- embed2
- }
- S8 struct {
- embed1 `json:"embed1"`
- embed2 `json:"embed2"`
- Q int
- }
- S9 struct {
- unexportedWithMethods `json:"embed"`
- }
- )
-
- tests := []struct {
- in string
- ptr any
- out any
- err error
- }{{
- // Error since we cannot set S1.embed1, but still able to set S1.R.
- in: `{"R":2,"Q":1}`,
- ptr: new(S1),
- out: &S1{R: 2},
- err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed1"),
- }, {
- // The top level Q field takes precedence.
- in: `{"Q":1}`,
- ptr: new(S2),
- out: &S2{Q: 1},
- }, {
- // No issue with non-pointer variant.
- in: `{"R":2,"Q":1}`,
- ptr: new(S3),
- out: &S3{embed1: embed1{Q: 1}, R: 2},
- }, {
- // No error since both embedded structs have field R, which annihilate each other.
- // Thus, no attempt is made at setting S4.embed1.
- in: `{"R":2}`,
- ptr: new(S4),
- out: new(S4),
- }, {
- // Error since we cannot set S5.embed1, but still able to set S5.R.
- in: `{"R":2,"Q":1}`,
- ptr: new(S5),
- out: &S5{R: 2},
- err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed3"),
- }, {
- // Issue 24152, ensure decodeState.indirect does not panic.
- in: `{"embed1": {"Q": 1}}`,
- ptr: new(S6),
- out: &S6{embed1{1}},
- }, {
- // Issue 24153, check that we can still set forwarded fields even in
- // the presence of a name conflict.
- //
- // This relies on obscure behavior of reflect where it is possible
- // to set a forwarded exported field on an unexported embedded struct
- // even though there is a name conflict, even when it would have been
- // impossible to do so according to Go visibility rules.
- // Go forbids this because it is ambiguous whether S7.Q refers to
- // S7.embed1.Q or S7.embed2.Q. Since embed1 and embed2 are unexported,
- // it should be impossible for an external package to set either Q.
- //
- // It is probably okay for a future reflect change to break this.
- in: `{"embed1": {"Q": 1}, "Q": 2}`,
- ptr: new(S7),
- out: &S7{embed1{1}, embed2{2}},
- }, {
- // Issue 24153, similar to the S7 case.
- in: `{"embed1": {"Q": 1}, "embed2": {"Q": 2}, "Q": 3}`,
- ptr: new(S8),
- out: &S8{embed1{1}, embed2{2}, 3},
- }, {
- // Issue 228145, similar to the cases above.
- in: `{"embed": {}}`,
- ptr: new(S9),
- out: &S9{},
- }}
-
- for i, tt := range tests {
- err := Unmarshal([]byte(tt.in), tt.ptr)
- if !equalError(err, tt.err) {
- t.Errorf("#%d: %v, want %v", i, err, tt.err)
- }
- if !reflect.DeepEqual(tt.ptr, tt.out) {
- t.Errorf("#%d: mismatch\ngot: %#+v\nwant: %#+v", i, tt.ptr, tt.out)
- }
- }
-}
-
-func TestUnmarshalErrorAfterMultipleJSON(t *testing.T) {
- t.Skip() // TODO
- tests := []struct {
- in string
- err error
- }{{
- in: `1 false null :`,
- err: &SyntaxError{"invalid character ':' looking for beginning of value", 14},
- }, {
- in: `1 [] [,]`,
- err: &SyntaxError{"invalid character ',' looking for beginning of value", 7},
- }, {
- in: `1 [] [true:]`,
- err: &SyntaxError{"invalid character ':' after array element", 11},
- }, {
- in: `1 {} {"x"=}`,
- err: &SyntaxError{"invalid character '=' after object key", 14},
- }, {
- in: `falsetruenul#`,
- err: &SyntaxError{"invalid character '#' in literal null (expecting 'l')", 13},
- }}
- for i, tt := range tests {
- dec := NewDecoder(strings.NewReader(tt.in))
- var err error
- for {
- var v any
- if err = dec.Decode(&v); err != nil {
- break
- }
- }
- if !reflect.DeepEqual(err, tt.err) {
- t.Errorf("#%d: got %#v, want %#v", i, err, tt.err)
- }
- }
-}
-
-type unmarshalPanic struct{}
-
-func (unmarshalPanic) UnmarshalJSON([]byte) error { panic(0xdead) }
-
-func TestUnmarshalPanic(t *testing.T) {
- defer func() {
- if got := recover(); !reflect.DeepEqual(got, 0xdead) {
- t.Errorf("panic() = (%T)(%v), want 0xdead", got, got)
- }
- }()
- Unmarshal([]byte("{}"), &unmarshalPanic{})
- t.Fatalf("Unmarshal should have panicked")
-}
-
-// The decoder used to hang if decoding into an interface pointing to its own address.
-// See golang.org/issues/31740.
-func TestUnmarshalRecursivePointer(t *testing.T) {
- t.Skip() // TODO
- var v any
- v = &v
- data := []byte(`{"a": "b"}`)
-
- if err := Unmarshal(data, v); err != nil {
- t.Fatal(err)
- }
-}
-
-type textUnmarshalerString string
-
-func (m *textUnmarshalerString) UnmarshalText(text []byte) error {
- *m = textUnmarshalerString(strings.ToLower(string(text)))
- return nil
-}
-
-// Test unmarshal to a map, where the map key is a user defined type.
-// See golang.org/issues/34437.
-func TestUnmarshalMapWithTextUnmarshalerStringKey(t *testing.T) {
- var p map[textUnmarshalerString]string
- if err := Unmarshal([]byte(`{"FOO": "1"}`), &p); err != nil {
- t.Fatalf("Unmarshal unexpected error: %v", err)
- }
-
- if _, ok := p["foo"]; !ok {
- t.Errorf(`Key "foo" does not exist in map: %v`, p)
- }
-}
-
-func TestUnmarshalRescanLiteralMangledUnquote(t *testing.T) {
- // See golang.org/issues/38105.
- var p map[textUnmarshalerString]string
- if err := Unmarshal([]byte(`{"开源":"12345开源"}`), &p); err != nil {
- t.Fatalf("Unmarshal unexpected error: %v", err)
- }
- if _, ok := p["开源"]; !ok {
- t.Errorf(`Key "开源" does not exist in map: %v`, p)
- }
-
- // See golang.org/issues/38126.
- type T struct {
- F1 string `json:"F1,string"`
- }
- t1 := T{"aaa\tbbb"}
-
- b, err := Marshal(t1)
- if err != nil {
- t.Fatalf("Marshal unexpected error: %v", err)
- }
- var t2 T
- if err := Unmarshal(b, &t2); err != nil {
- t.Fatalf("Unmarshal unexpected error: %v", err)
- }
- if t1 != t2 {
- t.Errorf("Marshal and Unmarshal roundtrip mismatch: want %q got %q", t1, t2)
- }
-
- // See golang.org/issues/39555.
- input := map[textUnmarshalerString]string{"FOO": "", `"`: ""}
-
- encoded, err := Marshal(input)
- if err != nil {
- t.Fatalf("Marshal unexpected error: %v", err)
- }
- var got map[textUnmarshalerString]string
- if err := Unmarshal(encoded, &got); err != nil {
- t.Fatalf("Unmarshal unexpected error: %v", err)
- }
- want := map[textUnmarshalerString]string{"foo": "", `"`: ""}
- if !reflect.DeepEqual(want, got) {
- t.Fatalf("Unexpected roundtrip result:\nwant: %q\ngot: %q", want, got)
- }
-}
-
-func TestUnmarshalMaxDepth(t *testing.T) {
- t.Skip() // TODO
- testcases := []struct {
- name string
- data string
- errMaxDepth bool
- }{
- {
- name: "ArrayUnderMaxNestingDepth",
- data: `{"a":` + strings.Repeat(`[`, 10000-1) + strings.Repeat(`]`, 10000-1) + `}`,
- errMaxDepth: false,
- },
- {
- name: "ArrayOverMaxNestingDepth",
- data: `{"a":` + strings.Repeat(`[`, 10000) + strings.Repeat(`]`, 10000) + `}`,
- errMaxDepth: true,
- },
- {
- name: "ArrayOverStackDepth",
- data: `{"a":` + strings.Repeat(`[`, 3000000) + strings.Repeat(`]`, 3000000) + `}`,
- errMaxDepth: true,
- },
- {
- name: "ObjectUnderMaxNestingDepth",
- data: `{"a":` + strings.Repeat(`{"a":`, 10000-1) + `0` + strings.Repeat(`}`, 10000-1) + `}`,
- errMaxDepth: false,
- },
- {
- name: "ObjectOverMaxNestingDepth",
- data: `{"a":` + strings.Repeat(`{"a":`, 10000) + `0` + strings.Repeat(`}`, 10000) + `}`,
- errMaxDepth: true,
- },
- {
- name: "ObjectOverStackDepth",
- data: `{"a":` + strings.Repeat(`{"a":`, 3000000) + `0` + strings.Repeat(`}`, 3000000) + `}`,
- errMaxDepth: true,
- },
- }
-
- targets := []struct {
- name string
- newValue func() any
- }{
- {
- name: "unstructured",
- newValue: func() any {
- var v any
- return &v
- },
- },
- {
- name: "typed named field",
- newValue: func() any {
- v := struct {
- A any `json:"a"`
- }{}
- return &v
- },
- },
- {
- name: "typed missing field",
- newValue: func() any {
- v := struct {
- B any `json:"b"`
- }{}
- return &v
- },
- },
- {
- name: "custom unmarshaler",
- newValue: func() any {
- v := unmarshaler{}
- return &v
- },
- },
- }
-
- for _, tc := range testcases {
- for _, target := range targets {
- t.Run(target.name+"-"+tc.name, func(t *testing.T) {
- err := Unmarshal([]byte(tc.data), target.newValue())
- if !tc.errMaxDepth {
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- } else {
- if err == nil {
- t.Errorf("expected error containing 'exceeded max depth', got none")
- } else if !strings.Contains(err.Error(), "exceeded max depth") {
- t.Errorf("expected error containing 'exceeded max depth', got: %v", err)
- }
- }
- })
- }
- }
-}