aboutsummaryrefslogtreecommitdiff
path: root/src/encoding/json/decode_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/encoding/json/decode_test.go')
-rw-r--r--src/encoding/json/decode_test.go1638
1 files changed, 842 insertions, 796 deletions
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go
index 5c34139d92..a10c1e1ebb 100644
--- a/src/encoding/json/decode_test.go
+++ b/src/encoding/json/decode_test.go
@@ -387,16 +387,6 @@ 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"`
}
@@ -406,179 +396,203 @@ type DoublePtr struct {
J **int
}
-var unmarshalTests = []unmarshalTest{
+var unmarshalTests = []struct {
+ CaseName
+ in string
+ ptr any // new(type)
+ out any
+ err error
+ useNumber bool
+ golden bool
+ disallowUnknownFields bool
+}{
// 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.TypeFor[string](), 7, "T", "X"}},
- {in: `{"X": 23}`, ptr: new(T), out: T{}, err: &UnmarshalTypeError{"number", reflect.TypeFor[string](), 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.TypeFor[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},
+ {CaseName: Name(""), in: `true`, ptr: new(bool), out: true},
+ {CaseName: Name(""), in: `1`, ptr: new(int), out: 1},
+ {CaseName: Name(""), in: `1.2`, ptr: new(float64), out: 1.2},
+ {CaseName: Name(""), in: `-5`, ptr: new(int16), out: int16(-5)},
+ {CaseName: Name(""), in: `2`, ptr: new(Number), out: Number("2"), useNumber: true},
+ {CaseName: Name(""), in: `2`, ptr: new(Number), out: Number("2")},
+ {CaseName: Name(""), in: `2`, ptr: new(any), out: float64(2.0)},
+ {CaseName: Name(""), in: `2`, ptr: new(any), out: Number("2"), useNumber: true},
+ {CaseName: Name(""), in: `"a\u1234"`, ptr: new(string), out: "a\u1234"},
+ {CaseName: Name(""), in: `"http:\/\/"`, ptr: new(string), out: "http://"},
+ {CaseName: Name(""), in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"},
+ {CaseName: Name(""), in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
+ {CaseName: Name(""), in: "null", ptr: new(any), out: nil},
+ {CaseName: Name(""), in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeFor[string](), 7, "T", "X"}},
+ {CaseName: Name(""), in: `{"X": 23}`, ptr: new(T), out: T{}, err: &UnmarshalTypeError{"number", reflect.TypeFor[string](), 8, "T", "X"}},
+ {CaseName: Name(""), in: `{"x": 1}`, ptr: new(tx), out: tx{}},
+ {CaseName: Name(""), in: `{"x": 1}`, ptr: new(tx), out: tx{}},
+ {CaseName: Name(""), in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true},
+ {CaseName: Name(""), in: `{"S": 23}`, ptr: new(W), out: W{}, err: &UnmarshalTypeError{"number", reflect.TypeFor[SS](), 0, "W", "S"}},
+ {CaseName: Name(""), in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
+ {CaseName: Name(""), in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
+ {CaseName: Name(""), in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(any), out: ifaceNumAsFloat64},
+ {CaseName: Name(""), 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"},
+ {CaseName: Name(""), in: "\n true ", ptr: new(bool), out: true},
+ {CaseName: Name(""), in: "\t 1 ", ptr: new(int), out: 1},
+ {CaseName: Name(""), in: "\r 1.2 ", ptr: new(float64), out: 1.2},
+ {CaseName: Name(""), in: "\t -5 \n", ptr: new(int16), out: int16(-5)},
+ {CaseName: Name(""), 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},
+ {CaseName: Name(""), in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}},
+ {CaseName: Name(""), 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},
+ {CaseName: Name(""), in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}},
+ {CaseName: Name(""), in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true},
+ {CaseName: Name(""), in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}},
+ {CaseName: Name(""), in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}},
+ {CaseName: Name(""), 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{msg: "unexpected end of JSON input", Offset: 5}},
- {in: `{"F3": -}`, ptr: new(V), out: V{F3: Number("-")}, err: &SyntaxError{msg: "invalid character '}' in numeric literal", Offset: 9}},
+ {CaseName: Name(""), in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after object key", 17}},
+ {CaseName: Name(""), in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}},
+ {CaseName: Name(""), in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true},
+ {CaseName: Name(""), in: `[2, 3`, err: &SyntaxError{msg: "unexpected end of JSON input", Offset: 5}},
+ {CaseName: Name(""), in: `{"F3": -}`, ptr: new(V), out: V{F3: Number("-")}, err: &SyntaxError{msg: "invalid character '}' in numeric literal", Offset: 9}},
// 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}},
+ {CaseName: Name(""), in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
+ {CaseName: Name(""), in: " 42 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 5}},
+ {CaseName: Name(""), in: "\x01 true", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
+ {CaseName: Name(""), in: " false \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 8}},
+ {CaseName: Name(""), in: "\x01 1.2", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
+ {CaseName: Name(""), in: " 3.4 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 6}},
+ {CaseName: Name(""), in: "\x01 \"string\"", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
+ {CaseName: Name(""), 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")},
+ {CaseName: Name(""), in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}},
+ {CaseName: Name(""), in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}},
+ {CaseName: Name(""), in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}},
+ {CaseName: Name(""), 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)}},
+ {CaseName: Name(""), in: `[]`, ptr: new([]any), out: []any{}},
+ {CaseName: Name(""), in: `null`, ptr: new([]any), out: []any(nil)},
+ {CaseName: Name(""), in: `{"T":[]}`, ptr: new(map[string]any), out: map[string]any{"T": []any{}}},
+ {CaseName: Name(""), 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},
+ {CaseName: Name(""), in: allValueIndent, ptr: new(All), out: allValue},
+ {CaseName: Name(""), in: allValueCompact, ptr: new(All), out: allValue},
+ {CaseName: Name(""), in: allValueIndent, ptr: new(*All), out: &allValue},
+ {CaseName: Name(""), in: allValueCompact, ptr: new(*All), out: &allValue},
+ {CaseName: Name(""), in: pallValueIndent, ptr: new(All), out: pallValue},
+ {CaseName: Name(""), in: pallValueCompact, ptr: new(All), out: pallValue},
+ {CaseName: Name(""), in: pallValueIndent, ptr: new(*All), out: &pallValue},
+ {CaseName: Name(""), 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},
+ {CaseName: Name(""), in: `{"T":false}`, ptr: new(unmarshaler), out: umtrue}, // use "false" so test will fail if custom unmarshaler is not called
+ {CaseName: Name(""), in: `{"T":false}`, ptr: new(*unmarshaler), out: &umtrue},
+ {CaseName: Name(""), in: `[{"T":false}]`, ptr: new([]unmarshaler), out: umslice},
+ {CaseName: Name(""), in: `[{"T":false}]`, ptr: new(*[]unmarshaler), out: &umslice},
+ {CaseName: Name(""), 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},
+ {CaseName: Name(""), in: `"x:y"`, ptr: new(unmarshalerText), out: umtrueXY},
+ {CaseName: Name(""), in: `"x:y"`, ptr: new(*unmarshalerText), out: &umtrueXY},
+ {CaseName: Name(""), in: `["x:y"]`, ptr: new([]unmarshalerText), out: umsliceXY},
+ {CaseName: Name(""), in: `["x:y"]`, ptr: new(*[]unmarshalerText), out: &umsliceXY},
+ {CaseName: Name(""), 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"},
+ CaseName: Name(""),
+ 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"},
+ CaseName: Name(""),
+ 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"},
+ CaseName: Name(""),
+ 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"},
+ CaseName: Name(""),
+ 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},
+ CaseName: Name(""),
+ 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},
+ CaseName: Name(""),
+ in: `{"u2":4}`,
+ ptr: new(map[u8marshal]int),
+ out: map[u8marshal]int{2: 4},
},
{
- in: `{"2":4}`,
- ptr: new(map[u8marshal]int),
- err: errMissingU8Prefix,
+ CaseName: Name(""),
+ 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.TypeFor[int](), Offset: 2},
+ CaseName: Name(""),
+ in: `{"abc":"abc"}`,
+ ptr: new(map[int]string),
+ err: &UnmarshalTypeError{Value: "number abc", Type: reflect.TypeFor[int](), Offset: 2},
},
{
- in: `{"256":"abc"}`,
- ptr: new(map[uint8]string),
- err: &UnmarshalTypeError{Value: "number 256", Type: reflect.TypeFor[uint8](), Offset: 2},
+ CaseName: Name(""),
+ in: `{"256":"abc"}`,
+ ptr: new(map[uint8]string),
+ err: &UnmarshalTypeError{Value: "number 256", Type: reflect.TypeFor[uint8](), Offset: 2},
},
{
- in: `{"128":"abc"}`,
- ptr: new(map[int8]string),
- err: &UnmarshalTypeError{Value: "number 128", Type: reflect.TypeFor[int8](), Offset: 2},
+ CaseName: Name(""),
+ in: `{"128":"abc"}`,
+ ptr: new(map[int8]string),
+ err: &UnmarshalTypeError{Value: "number 128", Type: reflect.TypeFor[int8](), Offset: 2},
},
{
- in: `{"-1":"abc"}`,
- ptr: new(map[uint8]string),
- err: &UnmarshalTypeError{Value: "number -1", Type: reflect.TypeFor[uint8](), Offset: 2},
+ CaseName: Name(""),
+ in: `{"-1":"abc"}`,
+ ptr: new(map[uint8]string),
+ err: &UnmarshalTypeError{Value: "number -1", Type: reflect.TypeFor[uint8](), Offset: 2},
},
{
- in: `{"F":{"a":2,"3":4}}`,
- ptr: new(map[string]map[int]int),
- err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeFor[int](), Offset: 7},
+ CaseName: Name(""),
+ in: `{"F":{"a":2,"3":4}}`,
+ ptr: new(map[string]map[int]int),
+ err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeFor[int](), Offset: 7},
},
{
- in: `{"F":{"a":2,"3":4}}`,
- ptr: new(map[string]map[uint]int),
- err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeFor[uint](), Offset: 7},
+ CaseName: Name(""),
+ in: `{"F":{"a":2,"3":4}}`,
+ ptr: new(map[string]map[uint]int),
+ err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeFor[uint](), Offset: 7},
},
// Map keys can be encoding.TextUnmarshalers.
- {in: `{"x:y":true}`, ptr: new(map[unmarshalerText]bool), out: ummapXY},
+ {CaseName: Name(""), 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},
+ {CaseName: Name(""), in: `{"x:y":false,"x:y":true}`, ptr: new(map[unmarshalerText]bool), out: ummapXY},
{
+ CaseName: Name(""),
in: `{
"Level0": 1,
"Level1b": 2,
@@ -634,93 +648,109 @@ var unmarshalTests = []unmarshalTest{
},
},
{
- in: `{"hello": 1}`,
- ptr: new(Ambig),
- out: Ambig{First: 1},
+ CaseName: Name(""),
+ 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}}},
+ CaseName: Name(""),
+ in: `{"X": 1,"Y":2}`,
+ ptr: new(S5),
+ out: S5{S8: S8{S9: S9{Y: 2}}},
},
{
+ CaseName: Name(""),
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}}}},
+ CaseName: Name(""),
+ in: `{"X": 1,"Y":2}`,
+ ptr: new(S10),
+ out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}},
},
{
+ CaseName: Name(""),
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},
+ CaseName: Name(""),
+ 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",
+ CaseName: Name(""),
+ in: "\"hello\xffworld\"",
+ ptr: new(string),
+ out: "hello\ufffdworld",
},
{
- in: "\"hello\xc2\xc2world\"",
- ptr: new(string),
- out: "hello\ufffd\ufffdworld",
+ CaseName: Name(""),
+ in: "\"hello\xc2\xc2world\"",
+ ptr: new(string),
+ out: "hello\ufffd\ufffdworld",
},
{
- in: "\"hello\xc2\xffworld\"",
- ptr: new(string),
- out: "hello\ufffd\ufffdworld",
+ CaseName: Name(""),
+ in: "\"hello\xc2\xffworld\"",
+ ptr: new(string),
+ out: "hello\ufffd\ufffdworld",
},
{
- in: "\"hello\\ud800world\"",
- ptr: new(string),
- out: "hello\ufffdworld",
+ CaseName: Name(""),
+ in: "\"hello\\ud800world\"",
+ ptr: new(string),
+ out: "hello\ufffdworld",
},
{
- in: "\"hello\\ud800\\ud800world\"",
- ptr: new(string),
- out: "hello\ufffd\ufffdworld",
+ CaseName: Name(""),
+ in: "\"hello\\ud800\\ud800world\"",
+ ptr: new(string),
+ out: "hello\ufffd\ufffdworld",
},
{
- in: "\"hello\\ud800\\ud800world\"",
- ptr: new(string),
- out: "hello\ufffd\ufffdworld",
+ CaseName: Name(""),
+ 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",
+ CaseName: Name(""),
+ 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"},
+ CaseName: Name(""),
+ 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.TypeFor[map[Point]string](), Offset: 1},
+ CaseName: Name(""),
+ in: `{"2009-11-10T23:00:00Z": "hello world"}`,
+ ptr: new(map[Point]string),
+ err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeFor[map[Point]string](), Offset: 1},
},
{
- in: `{"asdf": "hello world"}`,
- ptr: new(map[unmarshaler]string),
- err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeFor[map[unmarshaler]string](), Offset: 1},
+ CaseName: Name(""),
+ in: `{"asdf": "hello world"}`,
+ ptr: new(map[unmarshaler]string),
+ err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeFor[map[unmarshaler]string](), Offset: 1},
},
// related to issue 13783.
@@ -731,91 +761,104 @@ var unmarshalTests = []unmarshalTest{
// 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},
+ CaseName: Name(""),
+ in: `"AQID"`,
+ ptr: new([]byteWithMarshalJSON),
+ out: []byteWithMarshalJSON{1, 2, 3},
},
{
- in: `["Z01","Z02","Z03"]`,
- ptr: new([]byteWithMarshalJSON),
- out: []byteWithMarshalJSON{1, 2, 3},
- golden: true,
+ CaseName: Name(""),
+ in: `["Z01","Z02","Z03"]`,
+ ptr: new([]byteWithMarshalJSON),
+ out: []byteWithMarshalJSON{1, 2, 3},
+ golden: true,
},
{
- in: `"AQID"`,
- ptr: new([]byteWithMarshalText),
- out: []byteWithMarshalText{1, 2, 3},
+ CaseName: Name(""),
+ in: `"AQID"`,
+ ptr: new([]byteWithMarshalText),
+ out: []byteWithMarshalText{1, 2, 3},
},
{
- in: `["Z01","Z02","Z03"]`,
- ptr: new([]byteWithMarshalText),
- out: []byteWithMarshalText{1, 2, 3},
- golden: true,
+ CaseName: Name(""),
+ in: `["Z01","Z02","Z03"]`,
+ ptr: new([]byteWithMarshalText),
+ out: []byteWithMarshalText{1, 2, 3},
+ golden: true,
},
{
- in: `"AQID"`,
- ptr: new([]byteWithPtrMarshalJSON),
- out: []byteWithPtrMarshalJSON{1, 2, 3},
+ CaseName: Name(""),
+ in: `"AQID"`,
+ ptr: new([]byteWithPtrMarshalJSON),
+ out: []byteWithPtrMarshalJSON{1, 2, 3},
},
{
- in: `["Z01","Z02","Z03"]`,
- ptr: new([]byteWithPtrMarshalJSON),
- out: []byteWithPtrMarshalJSON{1, 2, 3},
- golden: true,
+ CaseName: Name(""),
+ in: `["Z01","Z02","Z03"]`,
+ ptr: new([]byteWithPtrMarshalJSON),
+ out: []byteWithPtrMarshalJSON{1, 2, 3},
+ golden: true,
},
{
- in: `"AQID"`,
- ptr: new([]byteWithPtrMarshalText),
- out: []byteWithPtrMarshalText{1, 2, 3},
+ CaseName: Name(""),
+ in: `"AQID"`,
+ ptr: new([]byteWithPtrMarshalText),
+ out: []byteWithPtrMarshalText{1, 2, 3},
},
{
- in: `["Z01","Z02","Z03"]`,
- ptr: new([]byteWithPtrMarshalText),
- out: []byteWithPtrMarshalText{1, 2, 3},
- golden: true,
+ CaseName: Name(""),
+ 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,
+ CaseName: Name(""),
+ 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,
+ CaseName: Name(""),
+ 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,
+ CaseName: Name(""),
+ 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,
+ CaseName: Name(""),
+ 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},
+ {CaseName: Name(""), in: `0.000001`, ptr: new(float64), out: 0.000001, golden: true},
+ {CaseName: Name(""), in: `1e-7`, ptr: new(float64), out: 1e-7, golden: true},
+ {CaseName: Name(""), in: `100000000000000000000`, ptr: new(float64), out: 100000000000000000000.0, golden: true},
+ {CaseName: Name(""), in: `1e+21`, ptr: new(float64), out: 1e21, golden: true},
+ {CaseName: Name(""), in: `-0.000001`, ptr: new(float64), out: -0.000001, golden: true},
+ {CaseName: Name(""), in: `-1e-7`, ptr: new(float64), out: -1e-7, golden: true},
+ {CaseName: Name(""), in: `-100000000000000000000`, ptr: new(float64), out: -100000000000000000000.0, golden: true},
+ {CaseName: Name(""), in: `-1e+21`, ptr: new(float64), out: -1e21, golden: true},
+ {CaseName: Name(""), in: `999999999999999900000`, ptr: new(float64), out: 999999999999999900000.0, golden: true},
+ {CaseName: Name(""), in: `9007199254740992`, ptr: new(float64), out: 9007199254740992.0, golden: true},
+ {CaseName: Name(""), in: `9007199254740993`, ptr: new(float64), out: 9007199254740992.0, golden: false},
{
- in: `{"V": {"F2": "hello"}}`,
- ptr: new(VOuter),
+ CaseName: Name(""),
+ in: `{"V": {"F2": "hello"}}`,
+ ptr: new(VOuter),
err: &UnmarshalTypeError{
Value: "string",
Struct: "V",
@@ -825,8 +868,9 @@ var unmarshalTests = []unmarshalTest{
},
},
{
- in: `{"V": {"F4": {}, "F2": "hello"}}`,
- ptr: new(VOuter),
+ CaseName: Name(""),
+ in: `{"V": {"F4": {}, "F2": "hello"}}`,
+ ptr: new(VOuter),
err: &UnmarshalTypeError{
Value: "string",
Struct: "V",
@@ -838,17 +882,18 @@ var unmarshalTests = []unmarshalTest{
// 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`)},
+ {CaseName: Name(""), in: `{"B":"true"}`, ptr: new(B), out: B{true}, golden: true},
+ {CaseName: Name(""), in: `{"B":"false"}`, ptr: new(B), out: B{false}, golden: true},
+ {CaseName: Name(""), in: `{"B": "maybe"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "maybe" into bool`)},
+ {CaseName: Name(""), in: `{"B": "tru"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "tru" into bool`)},
+ {CaseName: Name(""), in: `{"B": "False"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "False" into bool`)},
+ {CaseName: Name(""), in: `{"B": "null"}`, ptr: new(B), out: B{false}},
+ {CaseName: Name(""), in: `{"B": "nul"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "nul" into bool`)},
+ {CaseName: Name(""), 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
{
+ CaseName: Name(""),
in: `{
"Level0": 1,
"Level1b": 2,
@@ -876,6 +921,7 @@ var unmarshalTests = []unmarshalTest{
disallowUnknownFields: true,
},
{
+ CaseName: Name(""),
in: `{
"Level0": 1,
"Level1b": 2,
@@ -905,31 +951,36 @@ var unmarshalTests = []unmarshalTest{
// issue 26444
// UnmarshalTypeError without field & struct values
{
- in: `{"data":{"test1": "bob", "test2": 123}}`,
- ptr: new(mapStringToStringData),
- err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[string](), Offset: 37, Struct: "mapStringToStringData", Field: "data"},
+ CaseName: Name(""),
+ in: `{"data":{"test1": "bob", "test2": 123}}`,
+ ptr: new(mapStringToStringData),
+ err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[string](), Offset: 37, Struct: "mapStringToStringData", Field: "data"},
},
{
- in: `{"data":{"test1": 123, "test2": "bob"}}`,
- ptr: new(mapStringToStringData),
- err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[string](), Offset: 21, Struct: "mapStringToStringData", Field: "data"},
+ CaseName: Name(""),
+ in: `{"data":{"test1": 123, "test2": "bob"}}`,
+ ptr: new(mapStringToStringData),
+ err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[string](), 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.TypeFor[*MustNotUnmarshalText](), Offset: 1},
+ CaseName: Name(""),
+ in: `[1, 2, 3]`,
+ ptr: new(MustNotUnmarshalText),
+ err: &UnmarshalTypeError{Value: "array", Type: reflect.TypeFor[*MustNotUnmarshalText](), Offset: 1},
},
{
- in: `{"foo": "bar"}`,
- ptr: new(MustNotUnmarshalText),
- err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeFor[*MustNotUnmarshalText](), Offset: 1},
+ CaseName: Name(""),
+ in: `{"foo": "bar"}`,
+ ptr: new(MustNotUnmarshalText),
+ err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeFor[*MustNotUnmarshalText](), Offset: 1},
},
// #22369
{
- in: `{"PP": {"T": {"Y": "bad-type"}}}`,
- ptr: new(P),
+ CaseName: Name(""),
+ in: `{"PP": {"T": {"Y": "bad-type"}}}`,
+ ptr: new(P),
err: &UnmarshalTypeError{
Value: "string",
Struct: "T",
@@ -939,8 +990,9 @@ var unmarshalTests = []unmarshalTest{
},
},
{
- in: `{"Ts": [{"Y": 1}, {"Y": 2}, {"Y": "bad-type"}]}`,
- ptr: new(PP),
+ CaseName: Name(""),
+ in: `{"Ts": [{"Y": 1}, {"Y": 2}, {"Y": "bad-type"}]}`,
+ ptr: new(PP),
err: &UnmarshalTypeError{
Value: "string",
Struct: "T",
@@ -951,76 +1003,84 @@ var unmarshalTests = []unmarshalTest{
},
// #14702
{
- in: `invalid`,
- ptr: new(Number),
+ CaseName: Name(""),
+ in: `invalid`,
+ ptr: new(Number),
err: &SyntaxError{
msg: "invalid character 'i' looking for beginning of value",
Offset: 1,
},
},
{
- in: `"invalid"`,
- ptr: new(Number),
- err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`),
+ CaseName: Name(""),
+ 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"`),
+ CaseName: Name(""),
+ 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"}`,
+ CaseName: Name(""),
+ 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"`),
+ CaseName: Name(""),
+ 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)
+ t.Fatalf("Marshal error: %v", err)
}
if string(b) != allValueCompact {
- t.Errorf("Marshal allValueCompact")
+ t.Errorf("Marshal:")
diff(t, b, []byte(allValueCompact))
return
}
b, err = Marshal(pallValue)
if err != nil {
- t.Fatalf("Marshal pallValue: %v", err)
+ t.Fatalf("Marshal error: %v", err)
}
if string(b) != pallValueCompact {
- t.Errorf("Marshal pallValueCompact")
+ t.Errorf("Marshal:")
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 TestMarshalInvalidUTF8(t *testing.T) {
+ tests := []struct {
+ CaseName
+ in string
+ want string
+ }{
+ {Name(""), "hello\xffworld", `"hello\ufffdworld"`},
+ {Name(""), "", `""`},
+ {Name(""), "\xff", `"\ufffd"`},
+ {Name(""), "\xff\xff", `"\ufffd\ufffd"`},
+ {Name(""), "a\xffb", `"a\ufffdb"`},
+ {Name(""), "\xe6\x97\xa5\xe6\x9c\xac\xff\xaa\x9e", `"日本\ufffd\ufffd\ufffd"`},
+ }
+ for _, tt := range tests {
+ t.Run(tt.Name, func(t *testing.T) {
+ got, err := Marshal(tt.in)
+ if string(got) != tt.want || err != nil {
+ t.Errorf("%s: Marshal(%q):\n\tgot: (%q, %v)\n\twant: (%q, nil)", tt.Where, tt.in, got, err, tt.want)
+ }
+ })
}
}
@@ -1028,11 +1088,11 @@ func TestMarshalNumberZeroVal(t *testing.T) {
var n Number
out, err := Marshal(n)
if err != nil {
- t.Fatal(err)
+ t.Fatalf("Marshal error: %v", err)
}
- outStr := string(out)
- if outStr != "0" {
- t.Fatalf("Invalid zero val for Number: %q", outStr)
+ got := string(out)
+ if got != "0" {
+ t.Fatalf("Marshal: got %s, want 0", got)
}
}
@@ -1068,109 +1128,98 @@ func TestMarshalEmbeds(t *testing.T) {
Q: 18,
},
}
- b, err := Marshal(top)
+ got, err := Marshal(top)
if err != nil {
- t.Fatal(err)
+ t.Fatalf("Marshal error: %v", 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)
+ if string(got) != want {
+ t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
}
}
func equalError(a, b error) bool {
- if a == nil {
- return b == nil
- }
- if b == nil {
- return a == nil
+ if a == nil || b == nil {
+ return a == nil && b == nil
}
return a.Error() == b.Error()
}
func TestUnmarshal(t *testing.T) {
- for i, tt := range unmarshalTests {
- var scan scanner
- in := []byte(tt.in)
- if err := checkValid(in, &scan); err != nil {
- if !equalError(err, tt.err) {
- t.Errorf("#%d: checkValid: %#v", i, err)
- continue
+ for _, tt := range unmarshalTests {
+ t.Run(tt.Name, func(t *testing.T) {
+ in := []byte(tt.in)
+ var scan scanner
+ if err := checkValid(in, &scan); err != nil {
+ if !equalError(err, tt.err) {
+ t.Fatalf("%s: checkValid error: %#v", tt.Where, err)
+ }
+ }
+ if tt.ptr == nil {
+ return
}
- }
- 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
- }
+ typ := reflect.TypeOf(tt.ptr)
+ if typ.Kind() != reflect.Pointer {
+ t.Fatalf("%s: unmarshalTest.ptr %T is not a pointer type", tt.Where, tt.ptr)
+ }
+ typ = typ.Elem()
- 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", i, v.Elem().Interface(), tt.out)
- data, _ := Marshal(v.Elem().Interface())
- println(string(data))
- data, _ = Marshal(tt.out)
- println(string(data))
- continue
- }
+ // v = new(right-type)
+ v := reflect.New(typ)
- // 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 !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.Fatalf("%s: unmarshalTest.ptr %#v is not a pointer to a zero value", tt.Where, tt.ptr)
}
- 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))
+
+ dec := NewDecoder(bytes.NewReader(in))
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 tt.disallowUnknownFields {
+ dec.DisallowUnknownFields()
}
- 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
+ if err := dec.Decode(v.Interface()); !equalError(err, tt.err) {
+ t.Fatalf("%s: Decode error:\n\tgot: %v\n\twant: %v", tt.Where, err, tt.err)
+ } else if err != nil {
+ return
}
- }
+ if got := v.Elem().Interface(); !reflect.DeepEqual(got, tt.out) {
+ gotJSON, _ := Marshal(got)
+ wantJSON, _ := Marshal(tt.out)
+ t.Fatalf("%s: Decode:\n\tgot: %#+v\n\twant: %#+v\n\n\tgotJSON: %s\n\twantJSON: %s", tt.Where, got, tt.out, gotJSON, wantJSON)
+ }
+
+ // Check round trip also decodes correctly.
+ if tt.err == nil {
+ enc, err := Marshal(v.Interface())
+ if err != nil {
+ t.Fatalf("%s: Marshal error after roundtrip: %v", tt.Where, err)
+ }
+ if tt.golden && !bytes.Equal(enc, in) {
+ t.Errorf("%s: Marshal:\n\tgot: %s\n\twant: %s", tt.Where, 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.Fatalf("%s: Decode(%#q) error after roundtrip: %v", tt.Where, enc, err)
+ }
+ if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) {
+ t.Fatalf("%s: Decode:\n\tgot: %#+v\n\twant: %#+v\n\n\tgotJSON: %s\n\twantJSON: %s",
+ tt.Where, v.Elem().Interface(), vv.Elem().Interface(),
+ stripWhitespace(string(enc)), stripWhitespace(string(in)))
+ }
+ }
+ })
}
}
@@ -1178,48 +1227,50 @@ func TestUnmarshalMarshal(t *testing.T) {
initBig()
var v any
if err := Unmarshal(jsonBig, &v); err != nil {
- t.Fatalf("Unmarshal: %v", err)
+ t.Fatalf("Unmarshal error: %v", err)
}
b, err := Marshal(v)
if err != nil {
- t.Fatalf("Marshal: %v", err)
+ t.Fatalf("Marshal error: %v", err)
}
if !bytes.Equal(jsonBig, b) {
- t.Errorf("Marshal jsonBig")
+ t.Errorf("Marshal:")
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)
- }
+ tests := []struct {
+ CaseName
+ in string
+ i int64
+ intErr string
+ f float64
+ floatErr string
+ }{
+ {CaseName: Name(""), in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid syntax", f: -1.23e1},
+ {CaseName: Name(""), in: "-12", i: -12, f: -12.0},
+ {CaseName: Name(""), in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid syntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"},
+ }
+ for _, tt := range tests {
+ t.Run(tt.Name, func(t *testing.T) {
+ n := Number(tt.in)
+ if got := n.String(); got != tt.in {
+ t.Errorf("%s: Number(%q).String() = %s, want %s", tt.Where, tt.in, got, tt.in)
+ }
+ if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt.i {
+ t.Errorf("%s: Number(%q).Int64() = %d, want %d", tt.Where, tt.in, i, tt.i)
+ } else if (err == nil && tt.intErr != "") || (err != nil && err.Error() != tt.intErr) {
+ t.Errorf("%s: Number(%q).Int64() error:\n\tgot: %v\n\twant: %v", tt.Where, tt.in, err, tt.intErr)
+ }
+ if f, err := n.Float64(); err == nil && tt.floatErr == "" && f != tt.f {
+ t.Errorf("%s: Number(%q).Float64() = %g, want %g", tt.Where, tt.in, f, tt.f)
+ } else if (err == nil && tt.floatErr != "") || (err != nil && err.Error() != tt.floatErr) {
+ t.Errorf("%s: Number(%q).Float64() error:\n\tgot %v\n\twant: %v", tt.Where, tt.in, err, tt.floatErr)
+ }
+ })
}
}
@@ -1230,14 +1281,14 @@ func TestLargeByteSlice(t *testing.T) {
}
b, err := Marshal(s0)
if err != nil {
- t.Fatalf("Marshal: %v", err)
+ t.Fatalf("Marshal error: %v", err)
}
var s1 []byte
if err := Unmarshal(b, &s1); err != nil {
- t.Fatalf("Unmarshal: %v", err)
+ t.Fatalf("Unmarshal error: %v", err)
}
if !bytes.Equal(s0, s1) {
- t.Errorf("Marshal large byte slice")
+ t.Errorf("Marshal:")
diff(t, s0, s1)
}
}
@@ -1250,10 +1301,10 @@ 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)
+ t.Fatalf("Unmarshal error: %v", err)
}
if xint.X != 1 {
- t.Fatalf("Did not write to xint")
+ t.Fatalf("xint.X = %d, want 1", xint.X)
}
}
@@ -1264,59 +1315,51 @@ func TestUnmarshalPtrPtr(t *testing.T) {
t.Fatalf("Unmarshal: %v", err)
}
if xint.X != 1 {
- t.Fatalf("Did not write to xint")
+ t.Fatalf("xint.X = %d, want 1", xint.X)
}
}
func TestEscape(t *testing.T) {
const input = `"foobar"<html>` + " [\u2028 \u2029]"
- const expected = `"\"foobar\"\u003chtml\u003e [\u2028 \u2029]"`
- b, err := Marshal(input)
+ const want = `"\"foobar\"\u003chtml\u003e [\u2028 \u2029]"`
+ got, 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)
+ if string(got) != want {
+ t.Errorf("Marshal(%#q):\n\tgot: %s\n\twant: %s", input, got, want)
}
}
-// 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 got != tt.err {
- t.Errorf("%d. got err = %q, want %q", n, got, tt.err)
- }
+ // WrongString is a struct that's misusing the ,string modifier.
+ type WrongString struct {
+ Message string `json:"result,string"`
}
-}
-
-func noSpace(c rune) rune {
- if isSpace(byte(c)) { //only used for ascii
- return -1
+ tests := []struct {
+ CaseName
+ in, err string
+ }{
+ {Name(""), `{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`},
+ {Name(""), `{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`},
+ {Name(""), `{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`},
+ {Name(""), `{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`},
+ {Name(""), `{"result":"\""}`, `json: invalid use of ,string struct tag, trying to unmarshal "\"" into string`},
+ {Name(""), `{"result":"\"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "\"foo" into string`},
+ }
+ for _, tt := range tests {
+ t.Run(tt.Name, func(t *testing.T) {
+ r := strings.NewReader(tt.in)
+ var s WrongString
+ err := NewDecoder(r).Decode(&s)
+ got := fmt.Sprintf("%v", err)
+ if got != tt.err {
+ t.Errorf("%s: Decode error:\n\tgot: %s\n\twant: %s", tt.Where, got, tt.err)
+ }
+ })
}
- return c
}
type All struct {
@@ -1546,7 +1589,7 @@ var allValueIndent = `{
"PInterface": null
}`
-var allValueCompact = strings.Map(noSpace, allValueIndent)
+var allValueCompact = stripWhitespace(allValueIndent)
var pallValueIndent = `{
"Bool": false,
@@ -1635,7 +1678,7 @@ var pallValueIndent = `{
"PInterface": 5.2
}`
-var pallValueCompact = strings.Map(noSpace, pallValueIndent)
+var pallValueCompact = stripWhitespace(pallValueIndent)
func TestRefUnmarshal(t *testing.T) {
type S struct {
@@ -1656,10 +1699,10 @@ func TestRefUnmarshal(t *testing.T) {
var got S
if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref","R2":"ref","R3":"ref"}`), &got); err != nil {
- t.Fatalf("Unmarshal: %v", err)
+ t.Fatalf("Unmarshal error: %v", err)
}
if !reflect.DeepEqual(got, want) {
- t.Errorf("got %+v, want %+v", got, want)
+ t.Errorf("Unmarsha:\n\tgot: %+v\n\twant: %+v", got, want)
}
}
@@ -1672,13 +1715,12 @@ func TestEmptyString(t *testing.T) {
}
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")
+ var got T2
+ switch err := dec.Decode(&got); {
+ case err == nil:
+ t.Fatalf("Decode error: got nil, want non-nil")
+ case got.Number1 != 1:
+ t.Fatalf("Decode: got.Number1 = %d, want 1", got.Number1)
}
}
@@ -1695,12 +1737,13 @@ func TestNullString(t *testing.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)
+ switch err := Unmarshal(data, &s); {
+ case err != nil:
+ t.Fatalf("Unmarshal error: %v", err)
+ case s.B != 1:
+ t.Fatalf("Unmarshal: s.B = %d, want 1", s.B)
+ case s.C != nil:
+ t.Fatalf("Unmarshal: s.C = %d, want non-nil", s.C)
}
}
@@ -1716,37 +1759,38 @@ func intpp(x *int) **int {
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) {
- 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)
- }
+ tests := []struct {
+ CaseName
+ pre any
+ json string
+ post any
+ }{
+ {Name(""), "foo", `"bar"`, "bar"},
+ {Name(""), "foo", `2`, 2.0},
+ {Name(""), "foo", `true`, true},
+ {Name(""), "foo", `null`, nil},
+
+ {Name(""), nil, `null`, nil},
+ {Name(""), new(int), `null`, nil},
+ {Name(""), (*int)(nil), `null`, nil},
+ {Name(""), new(*int), `null`, new(*int)},
+ {Name(""), (**int)(nil), `null`, nil},
+ {Name(""), intp(1), `null`, nil},
+ {Name(""), intpp(nil), `null`, intpp(nil)},
+ {Name(""), intpp(intp(1)), `null`, intpp(nil)},
+ }
+ for _, tt := range tests {
+ t.Run(tt.Name, func(t *testing.T) {
+ b := struct{ X any }{tt.pre}
+ blob := `{"X":` + tt.json + `}`
+ if err := Unmarshal([]byte(blob), &b); err != nil {
+ t.Fatalf("%s: Unmarshal(%#q) error: %v", tt.Where, blob, err)
+ }
+ if !reflect.DeepEqual(b.X, tt.post) {
+ t.Errorf("%s: Unmarshal(%#q):\n\tpre.X: %#v\n\tgot.X: %#v\n\twant.X: %#v", tt.Where, blob, tt.pre, b.X, tt.post)
+ }
+ })
}
}
@@ -1924,24 +1968,18 @@ func (x MustNotUnmarshalText) UnmarshalText(text []byte) error {
func TestStringKind(t *testing.T) {
type stringKind string
-
- var m1, m2 map[stringKind]int
- m1 = map[stringKind]int{
- "foo": 42,
- }
-
- data, err := Marshal(m1)
+ want := map[stringKind]int{"foo": 42}
+ data, err := Marshal(want)
if err != nil {
- t.Errorf("Unexpected error marshaling: %v", err)
+ t.Fatalf("Marshal error: %v", err)
}
-
- err = Unmarshal(data, &m2)
+ var got map[stringKind]int
+ err = Unmarshal(data, &got)
if err != nil {
- t.Errorf("Unexpected error unmarshaling: %v", err)
+ t.Fatalf("Unmarshal error: %v", err)
}
-
- if !reflect.DeepEqual(m1, m2) {
- t.Error("Items should be equal after encoding and then decoding")
+ if !reflect.DeepEqual(got, want) {
+ t.Fatalf("Marshal/Unmarshal mismatch:\n\tgot: %v\n\twant: %v", got, want)
}
}
@@ -1950,20 +1988,18 @@ func TestStringKind(t *testing.T) {
// Issue 8962.
func TestByteKind(t *testing.T) {
type byteKind []byte
-
- a := byteKind("hello")
-
- data, err := Marshal(a)
+ want := byteKind("hello")
+ data, err := Marshal(want)
if err != nil {
- t.Error(err)
+ t.Fatalf("Marshal error: %v", err)
}
- var b byteKind
- err = Unmarshal(data, &b)
+ var got byteKind
+ err = Unmarshal(data, &got)
if err != nil {
- t.Fatal(err)
+ t.Fatalf("Unmarshal error: %v", err)
}
- if !reflect.DeepEqual(a, b) {
- t.Errorf("expected %v == %v", a, b)
+ if !reflect.DeepEqual(got, want) {
+ t.Fatalf("Marshal/Unmarshal mismatch:\n\tgot: %v\n\twant: %v", got, want)
}
}
@@ -1971,63 +2007,68 @@ func TestByteKind(t *testing.T) {
// Issue 12921.
func TestSliceOfCustomByte(t *testing.T) {
type Uint8 uint8
-
- a := []Uint8("hello")
-
- data, err := Marshal(a)
+ want := []Uint8("hello")
+ data, err := Marshal(want)
if err != nil {
- t.Fatal(err)
+ t.Fatalf("Marshal error: %v", err)
}
- var b []Uint8
- err = Unmarshal(data, &b)
+ var got []Uint8
+ err = Unmarshal(data, &got)
if err != nil {
- t.Fatal(err)
+ t.Fatalf("Unmarshal error: %v", err)
}
- if !reflect.DeepEqual(a, b) {
- t.Fatalf("expected %v == %v", a, b)
+ if !reflect.DeepEqual(got, want) {
+ t.Fatalf("Marshal/Unmarshal mismatch:\n\tgot: %v\n\twant: %v", got, want)
}
}
-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 _, ok := err.(*UnmarshalTypeError); !ok {
- t.Errorf("expected type error for Unmarshal(%q, type %T): got %T",
- item.src, item.dest, err)
- }
+ tests := []struct {
+ CaseName
+ dest any
+ in string
+ }{
+ {Name(""), new(string), `{"user": "name"}`}, // issue 4628.
+ {Name(""), new(error), `{}`}, // issue 4222
+ {Name(""), new(error), `[]`},
+ {Name(""), new(error), `""`},
+ {Name(""), new(error), `123`},
+ {Name(""), new(error), `true`},
+ }
+ for _, tt := range tests {
+ t.Run(tt.Name, func(t *testing.T) {
+ err := Unmarshal([]byte(tt.in), tt.dest)
+ if _, ok := err.(*UnmarshalTypeError); !ok {
+ t.Errorf("%s: Unmarshal(%#q, %T):\n\tgot: %T\n\twant: %T",
+ tt.Where, tt.in, tt.dest, err, new(UnmarshalTypeError))
+ }
+ })
}
-}
-
-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 _, ok := err.(*SyntaxError); !ok {
- t.Errorf("expected syntax error for Unmarshal(%q): got %T", src, err)
- }
+ tests := []struct {
+ CaseName
+ in string
+ }{
+ {Name(""), "tru"},
+ {Name(""), "fals"},
+ {Name(""), "nul"},
+ {Name(""), "123e"},
+ {Name(""), `"hello`},
+ {Name(""), `[1,2,3`},
+ {Name(""), `{"key":1`},
+ {Name(""), `{"key":1,`},
+ }
+ for _, tt := range tests {
+ t.Run(tt.Name, func(t *testing.T) {
+ err := Unmarshal([]byte(tt.in), &x)
+ if _, ok := err.(*SyntaxError); !ok {
+ t.Errorf("%s: Unmarshal(%#q, any):\n\tgot: %T\n\twant: %T",
+ tt.Where, tt.in, err, new(SyntaxError))
+ }
+ })
}
}
@@ -2048,10 +2089,10 @@ func TestUnmarshalUnexported(t *testing.T) {
out := &unexportedFields{}
err := Unmarshal([]byte(input), out)
if err != nil {
- t.Errorf("got error %v, expected nil", err)
+ t.Errorf("Unmarshal error: %v", err)
}
if !reflect.DeepEqual(out, want) {
- t.Errorf("got %q, want %q", out, want)
+ t.Errorf("Unmarshal:\n\tgot: %+v\n\twant: %+v", out, want)
}
}
@@ -2073,12 +2114,11 @@ func (t *Time3339) UnmarshalJSON(b []byte) error {
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)
+ switch err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3); {
+ case err == nil:
+ t.Fatalf("Unmarshal error: got nil, want non-nil")
+ case !strings.Contains(err.Error(), "range"):
+ t.Errorf("Unmarshal error:\n\tgot: %v\n\twant: out of range", err)
}
}
@@ -2091,7 +2131,7 @@ func TestSkipArrayObjects(t *testing.T) {
err := Unmarshal([]byte(json), &dest)
if err != nil {
- t.Errorf("got error %q, want nil", err)
+ t.Errorf("Unmarshal error: %v", err)
}
}
@@ -2100,99 +2140,102 @@ func TestSkipArrayObjects(t *testing.T) {
// Issues 4900 and 8837, among others.
func TestPrefilled(t *testing.T) {
// Values here change, cannot reuse table across runs.
- var prefillTests = []struct {
+ tests := []struct {
+ CaseName
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)
- }
+ }{{
+ CaseName: Name(""),
+ 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},
+ }, {
+ CaseName: Name(""),
+ 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},
+ }, {
+ CaseName: Name(""),
+ in: `[2]`,
+ ptr: &[]int{1},
+ out: &[]int{2},
+ }, {
+ CaseName: Name(""),
+ in: `[2, 3]`,
+ ptr: &[]int{1},
+ out: &[]int{2, 3},
+ }, {
+ CaseName: Name(""),
+ in: `[2, 3]`,
+ ptr: &[...]int{1},
+ out: &[...]int{2},
+ }, {
+ CaseName: Name(""),
+ in: `[3]`,
+ ptr: &[...]int{1, 2},
+ out: &[...]int{3, 0},
+ }}
+ for _, tt := range tests {
+ t.Run(tt.Name, func(t *testing.T) {
+ ptrstr := fmt.Sprintf("%v", tt.ptr)
+ err := Unmarshal([]byte(tt.in), tt.ptr) // tt.ptr edited here
+ if err != nil {
+ t.Errorf("%s: Unmarshal error: %v", tt.Where, err)
+ }
+ if !reflect.DeepEqual(tt.ptr, tt.out) {
+ t.Errorf("%s: Unmarshal(%#q, %T):\n\tgot: %v\n\twant: %v", tt.Where, 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)
- }
+ tests := []struct {
+ CaseName
+ v any
+ want string
+ }{
+ {Name(""), nil, "json: Unmarshal(nil)"},
+ {Name(""), struct{}{}, "json: Unmarshal(non-pointer struct {})"},
+ {Name(""), (*int)(nil), "json: Unmarshal(nil *int)"},
+ }
+ for _, tt := range tests {
+ t.Run(tt.Name, func(t *testing.T) {
+ err := Unmarshal(buf, tt.v)
+ if err == nil {
+ t.Fatalf("%s: Unmarshal error: got nil, want non-nil", tt.Where)
+ }
+ if got := err.Error(); got != tt.want {
+ t.Errorf("%s: Unmarshal error:\n\tgot: %s\n\twant: %s", tt.Where, 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 {
- t.Errorf("Unmarshal = %q; want %q", got, tt.want)
- }
+ tests := []struct {
+ CaseName
+ v any
+ want string
+ }{
+ {Name(""), nil, "json: Unmarshal(nil)"},
+ {Name(""), struct{}{}, "json: Unmarshal(non-pointer struct {})"},
+ {Name(""), (*int)(nil), "json: Unmarshal(nil *int)"},
+ {Name(""), new(net.IP), "json: cannot unmarshal number into Go value of type *net.IP"},
+ }
+ for _, tt := range tests {
+ t.Run(tt.Name, func(t *testing.T) {
+ err := Unmarshal(buf, tt.v)
+ if err == nil {
+ t.Fatalf("%s: Unmarshal error: got nil, want non-nil", tt.Where)
+ }
+ if got := err.Error(); got != tt.want {
+ t.Errorf("%s: Unmarshal error:\n\tgot: %s\n\twant: %s", tt.Where, got, tt.want)
+ }
+ })
}
}
@@ -2211,12 +2254,12 @@ func TestInvalidStringOption(t *testing.T) {
data, err := Marshal(item)
if err != nil {
- t.Fatalf("Marshal: %v", err)
+ t.Fatalf("Marshal error: %v", err)
}
err = Unmarshal(data, &item)
if err != nil {
- t.Fatalf("Unmarshal: %v", err)
+ t.Fatalf("Unmarshal error: %v", err)
}
}
@@ -2275,43 +2318,50 @@ func TestUnmarshalEmbeddedUnexported(t *testing.T) {
)
tests := []struct {
+ CaseName
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"),
+ CaseName: Name(""),
+ 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},
+ CaseName: Name(""),
+ 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},
+ CaseName: Name(""),
+ 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),
+ CaseName: Name(""),
+ 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"),
+ CaseName: Name(""),
+ 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}},
+ CaseName: Name(""),
+ 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.
@@ -2325,64 +2375,74 @@ func TestUnmarshalEmbeddedUnexported(t *testing.T) {
// 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}},
+ CaseName: Name(""),
+ 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},
+ CaseName: Name(""),
+ 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{},
+ CaseName: Name(""),
+ 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)
- }
+ for _, tt := range tests {
+ t.Run(tt.Name, func(t *testing.T) {
+ err := Unmarshal([]byte(tt.in), tt.ptr)
+ if !equalError(err, tt.err) {
+ t.Errorf("%s: Unmarshal error:\n\tgot: %v\n\twant: %v", tt.Where, err, tt.err)
+ }
+ if !reflect.DeepEqual(tt.ptr, tt.out) {
+ t.Errorf("%s: Unmarshal:\n\tgot: %#+v\n\twant: %#+v", tt.Where, tt.ptr, tt.out)
+ }
+ })
}
}
func TestUnmarshalErrorAfterMultipleJSON(t *testing.T) {
tests := []struct {
+ CaseName
in string
err error
}{{
- in: `1 false null :`,
- err: &SyntaxError{"invalid character ':' looking for beginning of value", 14},
+ CaseName: Name(""),
+ 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},
+ CaseName: Name(""),
+ in: `1 [] [,]`,
+ err: &SyntaxError{"invalid character ',' looking for beginning of value", 7},
}, {
- in: `1 [] [true:]`,
- err: &SyntaxError{"invalid character ':' after array element", 11},
+ CaseName: Name(""),
+ in: `1 [] [true:]`,
+ err: &SyntaxError{"invalid character ':' after array element", 11},
}, {
- in: `1 {} {"x"=}`,
- err: &SyntaxError{"invalid character '=' after object key", 14},
+ CaseName: Name(""),
+ in: `1 {} {"x"=}`,
+ err: &SyntaxError{"invalid character '=' after object key", 14},
}, {
- in: `falsetruenul#`,
- err: &SyntaxError{"invalid character '#' in literal null (expecting 'l')", 13},
+ CaseName: Name(""),
+ 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
+ for _, tt := range tests {
+ t.Run(tt.Name, func(t *testing.T) {
+ dec := NewDecoder(strings.NewReader(tt.in))
+ var err error
+ for err == nil {
+ var v any
+ err = dec.Decode(&v)
}
- }
- if !reflect.DeepEqual(err, tt.err) {
- t.Errorf("#%d: got %#v, want %#v", i, err, tt.err)
- }
+ if !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("%s: Decode error:\n\tgot: %v\n\twant: %v", tt.Where, err, tt.err)
+ }
+ })
}
}
@@ -2408,7 +2468,7 @@ func TestUnmarshalRecursivePointer(t *testing.T) {
data := []byte(`{"a": "b"}`)
if err := Unmarshal(data, v); err != nil {
- t.Fatal(err)
+ t.Fatalf("Unmarshal error: %v", err)
}
}
@@ -2424,11 +2484,11 @@ func (m *textUnmarshalerString) UnmarshalText(text []byte) error {
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)
+ t.Fatalf("Unmarshal error: %v", err)
}
if _, ok := p["foo"]; !ok {
- t.Errorf(`Key "foo" does not exist in map: %v`, p)
+ t.Errorf(`key "foo" missing in map: %v`, p)
}
}
@@ -2436,28 +2496,28 @@ 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)
+ t.Fatalf("Unmarshal error: %v", err)
}
if _, ok := p["开源"]; !ok {
- t.Errorf(`Key "开源" does not exist in map: %v`, p)
+ t.Errorf(`key "开源" missing in map: %v`, p)
}
// See golang.org/issues/38126.
type T struct {
F1 string `json:"F1,string"`
}
- t1 := T{"aaa\tbbb"}
+ wantT := T{"aaa\tbbb"}
- b, err := Marshal(t1)
+ b, err := Marshal(wantT)
if err != nil {
- t.Fatalf("Marshal unexpected error: %v", err)
+ t.Fatalf("Marshal error: %v", err)
}
- var t2 T
- if err := Unmarshal(b, &t2); err != nil {
- t.Fatalf("Unmarshal unexpected error: %v", err)
+ var gotT T
+ if err := Unmarshal(b, &gotT); err != nil {
+ t.Fatalf("Unmarshal error: %v", err)
}
- if t1 != t2 {
- t.Errorf("Marshal and Unmarshal roundtrip mismatch: want %q got %q", t1, t2)
+ if gotT != wantT {
+ t.Errorf("Marshal/Unmarshal roundtrip:\n\tgot: %q\n\twant: %q", gotT, wantT)
}
// See golang.org/issues/39555.
@@ -2465,107 +2525,93 @@ func TestUnmarshalRescanLiteralMangledUnquote(t *testing.T) {
encoded, err := Marshal(input)
if err != nil {
- t.Fatalf("Marshal unexpected error: %v", err)
+ t.Fatalf("Marshal error: %v", err)
}
var got map[textUnmarshalerString]string
if err := Unmarshal(encoded, &got); err != nil {
- t.Fatalf("Unmarshal unexpected error: %v", err)
+ t.Fatalf("Unmarshal error: %v", err)
}
want := map[textUnmarshalerString]string{"foo": "", `"`: ""}
- if !reflect.DeepEqual(want, got) {
- t.Fatalf("Unexpected roundtrip result:\nwant: %q\ngot: %q", want, got)
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("Marshal/Unmarshal roundtrip:\n\tgot: %q\n\twant: %q", gotT, wantT)
}
}
func TestUnmarshalMaxDepth(t *testing.T) {
- testcases := []struct {
- name string
+ tests := []struct {
+ CaseName
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,
- },
- }
+ }{{
+ CaseName: Name("ArrayUnderMaxNestingDepth"),
+ data: `{"a":` + strings.Repeat(`[`, 10000-1) + strings.Repeat(`]`, 10000-1) + `}`,
+ errMaxDepth: false,
+ }, {
+ CaseName: Name("ArrayOverMaxNestingDepth"),
+ data: `{"a":` + strings.Repeat(`[`, 10000) + strings.Repeat(`]`, 10000) + `}`,
+ errMaxDepth: true,
+ }, {
+ CaseName: Name("ArrayOverStackDepth"),
+ data: `{"a":` + strings.Repeat(`[`, 3000000) + strings.Repeat(`]`, 3000000) + `}`,
+ errMaxDepth: true,
+ }, {
+ CaseName: Name("ObjectUnderMaxNestingDepth"),
+ data: `{"a":` + strings.Repeat(`{"a":`, 10000-1) + `0` + strings.Repeat(`}`, 10000-1) + `}`,
+ errMaxDepth: false,
+ }, {
+ CaseName: Name("ObjectOverMaxNestingDepth"),
+ data: `{"a":` + strings.Repeat(`{"a":`, 10000) + `0` + strings.Repeat(`}`, 10000) + `}`,
+ errMaxDepth: true,
+ }, {
+ CaseName: Name("ObjectOverStackDepth"),
+ data: `{"a":` + strings.Repeat(`{"a":`, 3000000) + `0` + strings.Repeat(`}`, 3000000) + `}`,
+ errMaxDepth: true,
+ }}
targets := []struct {
- name string
+ CaseName
newValue func() any
- }{
- {
- name: "unstructured",
- newValue: func() any {
- var v any
- return &v
- },
+ }{{
+ CaseName: 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
- },
+ }, {
+ CaseName: 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
- },
+ }, {
+ CaseName: 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
- },
+ }, {
+ CaseName: Name("custom unmarshaler"),
+ newValue: func() any {
+ v := unmarshaler{}
+ return &v
},
- }
+ }}
- for _, tc := range testcases {
+ for _, tt := range tests {
for _, target := range targets {
- t.Run(target.name+"-"+tc.name, func(t *testing.T) {
- err := Unmarshal([]byte(tc.data), target.newValue())
- if !tc.errMaxDepth {
+ t.Run(target.Name+"-"+tt.Name, func(t *testing.T) {
+ err := Unmarshal([]byte(tt.data), target.newValue())
+ if !tt.errMaxDepth {
if err != nil {
- t.Errorf("unexpected error: %v", err)
+ t.Errorf("%s: %s: Unmarshal error: %v", tt.Where, target.Where, 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)
+ if err == nil || !strings.Contains(err.Error(), "exceeded max depth") {
+ t.Errorf("%s: %s: Unmarshal error:\n\tgot: %v\n\twant: exceeded max depth", tt.Where, target.Where, err)
}
}
})