diff --git a/decode_test.go b/decode_test.go index 9c7fdee7e..fc7a16587 100644 --- a/decode_test.go +++ b/decode_test.go @@ -436,317 +436,317 @@ func (self *JsonSyntaxError) err() *json.SyntaxError { 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(json.Number), out: json.Number("2"), useNumber: true}, - // {in: `2`, ptr: new(json.Number), out: json.Number("2")}, - // {in: `2`, ptr: new(interface{}), out: 2.0}, - // {in: `2`, ptr: new(interface{}), out: json.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(interface{}), out: nil}, - // {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &json.UnmarshalTypeError{Value: "array", Type: reflect.TypeOf(""), Offset: 7, Struct: "T", Field: "X"}}, - // {in: `{"X": 23}`, ptr: new(T), out: T{}, err: &json.UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 8, Struct: "T", Field: "X"}}, - // {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: &json.UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(SS("")), Struct: "W", Field: "S"}}, - // {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: json.Number("3")}}, - // {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: json.Number("1"), F2: int32(2), F3: json.Number("3")}, useNumber: true}, - // {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64}, - // {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), 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: (&JsonSyntaxError{"invalid character '}' after object key", 17}).err()}, - // {in: `[1, 2, 3+]`, err: (&JsonSyntaxError{"invalid character '+' after array element", 9}).err()}, - // {in: `{"X":12x}`, err: (&JsonSyntaxError{"invalid character 'x' after object key:value pair", 8}).err(), useNumber: true}, - // {in: `[2, 3`, err: (&JsonSyntaxError{Msg: "unexpected end of JSON input", Offset: 5}).err()}, - // {in: `{"F3": -}`, ptr: new(V), out: V{F3: json.Number("-")}, err: (&JsonSyntaxError{Msg: "invalid character '}' in numeric literal", Offset: 9}).err()}, - - // // raw value errors - // {in: "\x01 42", err: (&JsonSyntaxError{"invalid character '\\x01' looking for beginning of value", 1}).err()}, - // {in: " 42 \x01", err: (&JsonSyntaxError{"invalid character '\\x01' after top-level value", 5}).err()}, - // {in: "\x01 true", err: (&JsonSyntaxError{"invalid character '\\x01' looking for beginning of value", 1}).err()}, - // {in: " false \x01", err: (&JsonSyntaxError{"invalid character '\\x01' after top-level value", 8}).err()}, - // {in: "\x01 1.2", err: (&JsonSyntaxError{"invalid character '\\x01' looking for beginning of value", 1}).err()}, - // {in: " 3.4 \x01", err: (&JsonSyntaxError{"invalid character '\\x01' after top-level value", 6}).err()}, - // {in: "\x01 \"string\"", err: (&JsonSyntaxError{"invalid character '\\x01' looking for beginning of value", 1}).err()}, - // {in: " \"string\" \x01", err: (&JsonSyntaxError{"invalid character '\\x01' after top-level value", 11}).err()}, - - // // 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([]interface{}), out: []interface{}{}}, - // {in: `null`, ptr: new([]interface{}), out: []interface{}(nil)}, - // {in: `{"T":[]}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": []interface{}{}}}, - // {in: `{"T":null}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": interface{}(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: &json.UnmarshalTypeError{Value: "number abc", Type: reflect.TypeOf(0), Offset: 2}, - // }, - // { - // in: `{"256":"abc"}`, - // ptr: new(map[uint8]string), - // err: &json.UnmarshalTypeError{Value: "number 256", Type: reflect.TypeOf(uint8(0)), Offset: 2}, - // }, - // { - // in: `{"128":"abc"}`, - // ptr: new(map[int8]string), - // err: &json.UnmarshalTypeError{Value: "number 128", Type: reflect.TypeOf(int8(0)), Offset: 2}, - // }, - // { - // in: `{"-1":"abc"}`, - // ptr: new(map[uint8]string), - // err: &json.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: &json.UnmarshalTypeError{Value: "number a", Type: reflect.TypeOf(0), Offset: 7}, - // }, - // { - // in: `{"F":{"a":2,"3":4}}`, - // ptr: new(map[string]map[uint]int), - // err: &json.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\xffworld", - // validateString: false, - // }, - // { - // in: "\"hello\xc2\xc2world\"", - // ptr: new(string), - // out: "hello\xc2\xc2world", - // validateString: false, - // }, - // { - // in: "\"hello\xc2\xffworld\"", - // ptr: new(string), - // out: "hello\xc2\xffworld", - // }, - // { - // in: "\"hello\\ud800world\"", - // ptr: new(string), - // out: "hello\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\xed\xa0\x80\xed\xb0\x80world", - // }, - - // // 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: &json.UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[Point]string{}), Offset: 1}, - // }, - // { - // in: `{"asdf": "hello world"}`, - // ptr: new(map[unmarshaler]string), - // err: &json.UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[unmarshaler]string{}), Offset: 1}, - // }, + {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(json.Number), out: json.Number("2"), useNumber: true}, + {in: `2`, ptr: new(json.Number), out: json.Number("2")}, + {in: `2`, ptr: new(interface{}), out: 2.0}, + {in: `2`, ptr: new(interface{}), out: json.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(interface{}), out: nil}, + {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &json.UnmarshalTypeError{Value: "array", Type: reflect.TypeOf(""), Offset: 7, Struct: "T", Field: "X"}}, + {in: `{"X": 23}`, ptr: new(T), out: T{}, err: &json.UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 8, Struct: "T", Field: "X"}}, + {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: &json.UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(SS("")), Struct: "W", Field: "S"}}, + {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: json.Number("3")}}, + {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: json.Number("1"), F2: int32(2), F3: json.Number("3")}, useNumber: true}, + {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64}, + {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), 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: (&JsonSyntaxError{"invalid character '}' after object key", 17}).err()}, + {in: `[1, 2, 3+]`, err: (&JsonSyntaxError{"invalid character '+' after array element", 9}).err()}, + {in: `{"X":12x}`, err: (&JsonSyntaxError{"invalid character 'x' after object key:value pair", 8}).err(), useNumber: true}, + {in: `[2, 3`, err: (&JsonSyntaxError{Msg: "unexpected end of JSON input", Offset: 5}).err()}, + {in: `{"F3": -}`, ptr: new(V), out: V{F3: json.Number("-")}, err: (&JsonSyntaxError{Msg: "invalid character '}' in numeric literal", Offset: 9}).err()}, + + // raw value errors + {in: "\x01 42", err: (&JsonSyntaxError{"invalid character '\\x01' looking for beginning of value", 1}).err()}, + {in: " 42 \x01", err: (&JsonSyntaxError{"invalid character '\\x01' after top-level value", 5}).err()}, + {in: "\x01 true", err: (&JsonSyntaxError{"invalid character '\\x01' looking for beginning of value", 1}).err()}, + {in: " false \x01", err: (&JsonSyntaxError{"invalid character '\\x01' after top-level value", 8}).err()}, + {in: "\x01 1.2", err: (&JsonSyntaxError{"invalid character '\\x01' looking for beginning of value", 1}).err()}, + {in: " 3.4 \x01", err: (&JsonSyntaxError{"invalid character '\\x01' after top-level value", 6}).err()}, + {in: "\x01 \"string\"", err: (&JsonSyntaxError{"invalid character '\\x01' looking for beginning of value", 1}).err()}, + {in: " \"string\" \x01", err: (&JsonSyntaxError{"invalid character '\\x01' after top-level value", 11}).err()}, + + // 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([]interface{}), out: []interface{}{}}, + {in: `null`, ptr: new([]interface{}), out: []interface{}(nil)}, + {in: `{"T":[]}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": []interface{}{}}}, + {in: `{"T":null}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": interface{}(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: &json.UnmarshalTypeError{Value: "number abc", Type: reflect.TypeOf(0), Offset: 2}, + }, + { + in: `{"256":"abc"}`, + ptr: new(map[uint8]string), + err: &json.UnmarshalTypeError{Value: "number 256", Type: reflect.TypeOf(uint8(0)), Offset: 2}, + }, + { + in: `{"128":"abc"}`, + ptr: new(map[int8]string), + err: &json.UnmarshalTypeError{Value: "number 128", Type: reflect.TypeOf(int8(0)), Offset: 2}, + }, + { + in: `{"-1":"abc"}`, + ptr: new(map[uint8]string), + err: &json.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: &json.UnmarshalTypeError{Value: "number a", Type: reflect.TypeOf(0), Offset: 7}, + }, + { + in: `{"F":{"a":2,"3":4}}`, + ptr: new(map[string]map[uint]int), + err: &json.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\xffworld", + validateString: false, + }, + { + in: "\"hello\xc2\xc2world\"", + ptr: new(string), + out: "hello\xc2\xc2world", + validateString: false, + }, + { + in: "\"hello\xc2\xffworld\"", + ptr: new(string), + out: "hello\xc2\xffworld", + }, + { + in: "\"hello\\ud800world\"", + ptr: new(string), + out: "hello\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\xed\xa0\x80\xed\xb0\x80world", + }, + + // 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: &json.UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[Point]string{}), Offset: 1}, + }, + { + in: `{"asdf": "hello world"}`, + ptr: new(map[unmarshaler]string), + err: &json.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, @@ -760,262 +760,262 @@ var unmarshalTests = []unmarshalTest{ 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: &json.UnmarshalTypeError{ - // Value: "string", - // Struct: "V", - // Field: "V.F2", - // Type: reflect.TypeOf(int32(0)), - // Offset: 20, - // }, - // }, - // { - // in: `{"V": {"F4": {}, "F2": "hello"}}`, - // ptr: new(VOuter), - // err: &json.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 - // // json.UnmarshalTypeError without field & struct values - // { - // in: `{"data":{"test1": "bob", "test2": 123}}`, - // ptr: new(mapStringToStringData), - // err: &json.UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 37, Struct: "mapStringToStringData", Field: "data"}, - // }, - // { - // in: `{"data":{"test1": 123, "test2": "bob"}}`, - // ptr: new(mapStringToStringData), - // err: &json.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: &json.UnmarshalTypeError{Value: "array", Type: reflect.TypeOf(&MustNotUnmarshalText{}), Offset: 1}, - // }, - // { - // in: `{"foo": "bar"}`, - // ptr: new(MustNotUnmarshalText), - // err: &json.UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(&MustNotUnmarshalText{}), Offset: 1}, - // }, - // // #22369 - // { - // in: `{"PP": {"T": {"Y": "bad-type"}}}`, - // ptr: new(P), - // err: &json.UnmarshalTypeError{ - // Value: "string", - // Struct: "T", - // Field: "PP.T.Y", - // Type: reflect.TypeOf(0), - // Offset: 29, - // }, - // }, - // { - // in: `{"Ts": [{"Y": 1}, {"Y": 2}, {"Y": "bad-type"}]}`, - // ptr: new(PP), - // err: &json.UnmarshalTypeError{ - // Value: "string", - // Struct: "T", - // Field: "Ts.Y", - // Type: reflect.TypeOf(0), - // Offset: 29, - // }, - // }, - // // #14702 - // { - // in: `invalid`, - // ptr: new(json.Number), - // err: (&JsonSyntaxError{ - // Msg: "invalid character 'i' looking for beginning of value", - // Offset: 1, - // }).err(), - // }, - // { - // in: `"invalid"`, - // ptr: new(json.Number), - // err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), - // }, - // { - // in: `{"A":"invalid"}`, - // ptr: new(struct{ A json.Number }), - // err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), - // }, - // { - // in: `{"A":"invalid"}`, - // ptr: new(struct { - // A json.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]json.Number), - // err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), - // }, - // {in: `\u`, ptr: new(interface{}), err: fmt.Errorf("json: invald char"), validateString: true}, - // {in: `\u`, ptr: new(string), err: fmt.Errorf("json: invald char"), validateString: true}, - - // {in: "\"\x00\"", ptr: new(interface{}), err: fmt.Errorf("json: invald char"), validateString: true}, - // {in: "\"\x00\"", ptr: new(string), err: fmt.Errorf("json: invald char"), validateString: true}, - // {in: "\"\xff\"", ptr: new(interface{}), err: fmt.Errorf("json: invald char"), validateString: true}, - // {in: "\"\xff\"", ptr: new(string), err: fmt.Errorf("json: invald char"), validateString: true}, - // {in: "\"\x00\"", ptr: new(interface{}), out: interface{}("\x00"), validateString: false}, - // {in: "\"\x00\"", ptr: new(string), out: "\x00", validateString: false}, - // {in: "\"\xff\"", ptr: new(interface{}), out: interface{}("\xff"), validateString: false}, - // {in: "\"\xff\"", ptr: new(string), out: "\xff", validateString: false}, + { + 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: &json.UnmarshalTypeError{ + Value: "string", + Struct: "V", + Field: "V.F2", + Type: reflect.TypeOf(int32(0)), + Offset: 20, + }, + }, + { + in: `{"V": {"F4": {}, "F2": "hello"}}`, + ptr: new(VOuter), + err: &json.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 + // json.UnmarshalTypeError without field & struct values + { + in: `{"data":{"test1": "bob", "test2": 123}}`, + ptr: new(mapStringToStringData), + err: &json.UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 37, Struct: "mapStringToStringData", Field: "data"}, + }, + { + in: `{"data":{"test1": 123, "test2": "bob"}}`, + ptr: new(mapStringToStringData), + err: &json.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: &json.UnmarshalTypeError{Value: "array", Type: reflect.TypeOf(&MustNotUnmarshalText{}), Offset: 1}, + }, + { + in: `{"foo": "bar"}`, + ptr: new(MustNotUnmarshalText), + err: &json.UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(&MustNotUnmarshalText{}), Offset: 1}, + }, + // #22369 + { + in: `{"PP": {"T": {"Y": "bad-type"}}}`, + ptr: new(P), + err: &json.UnmarshalTypeError{ + Value: "string", + Struct: "T", + Field: "PP.T.Y", + Type: reflect.TypeOf(0), + Offset: 29, + }, + }, + { + in: `{"Ts": [{"Y": 1}, {"Y": 2}, {"Y": "bad-type"}]}`, + ptr: new(PP), + err: &json.UnmarshalTypeError{ + Value: "string", + Struct: "T", + Field: "Ts.Y", + Type: reflect.TypeOf(0), + Offset: 29, + }, + }, + // #14702 + { + in: `invalid`, + ptr: new(json.Number), + err: (&JsonSyntaxError{ + Msg: "invalid character 'i' looking for beginning of value", + Offset: 1, + }).err(), + }, + { + in: `"invalid"`, + ptr: new(json.Number), + err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), + }, + { + in: `{"A":"invalid"}`, + ptr: new(struct{ A json.Number }), + err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), + }, + { + in: `{"A":"invalid"}`, + ptr: new(struct { + A json.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]json.Number), + err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), + }, + {in: `\u`, ptr: new(interface{}), err: fmt.Errorf("json: invald char"), validateString: true}, + {in: `\u`, ptr: new(string), err: fmt.Errorf("json: invald char"), validateString: true}, + + {in: "\"\x00\"", ptr: new(interface{}), err: fmt.Errorf("json: invald char"), validateString: true}, + {in: "\"\x00\"", ptr: new(string), err: fmt.Errorf("json: invald char"), validateString: true}, + {in: "\"\xff\"", ptr: new(interface{}), err: fmt.Errorf("json: invald char"), validateString: true}, + {in: "\"\xff\"", ptr: new(string), err: fmt.Errorf("json: invald char"), validateString: true}, + {in: "\"\x00\"", ptr: new(interface{}), out: interface{}("\x00"), validateString: false}, + {in: "\"\x00\"", ptr: new(string), out: "\x00", validateString: false}, + {in: "\"\xff\"", ptr: new(interface{}), out: interface{}("\xff"), validateString: false}, + {in: "\"\xff\"", ptr: new(string), out: "\xff", validateString: false}, } func trim(b []byte) []byte { diff --git a/decoder/assembler_amd64_go116.go b/decoder/assembler_amd64_go116.go index e9a3d59cc..865016b07 100644 --- a/decoder/assembler_amd64_go116.go +++ b/decoder/assembler_amd64_go116.go @@ -356,7 +356,8 @@ func (self *_Assembler) prologue() { self.Emit("MOVQ", jit.Imm(_MaxDigitNums), _VAR_st_Dc) // MOVQ $_MaxDigitNums, ss.Dcap self.Emit("LEAQ", jit.Ptr(_ST, _DbufOffset), _AX) // LEAQ _DbufOffset(ST), AX self.Emit("MOVQ", _AX, _VAR_st_Db) // MOVQ AX, ss.Dbuf - self.Emit("MOVQ", jit.Imm(0), _VAR_et) // MOVQ AX, ss.Dp + self.Emit("XORL", _AX, _AX) // XORL AX, AX + self.Emit("MOVQ", _AX, _VAR_et) // MOVQ AX, ss.Dp } /** Function Calling Helpers **/ @@ -477,8 +478,9 @@ func (self *_Assembler) mismatch_error() { } func (self *_Assembler) _asm_OP_dismatch_err(p *_Instr) { - self.Emit("MOVQ", _IC, _VAR_ic) - self.Emit("MOVQ", jit.Type(p.vt()), _VAR_et) + self.Emit("MOVQ", _IC, _VAR_ic) + self.Emit("MOVQ", jit.Type(p.vt()), _ET)) + self.Emit("MOVQ", _ET, _VAR_et) } func (self *_Assembler) _asm_OP_go_skip(p *_Instr) { @@ -640,7 +642,8 @@ func (self *_Assembler) check_err(vt reflect.Type) { if vt != nil { self.Sjmp("JNS" , "_check_err_{n}") // JNE _parsing_error_v self.Emit("MOVQ", _BP, _VAR_ic) - self.Emit("MOVQ", jit.Type(vt), _VAR_et) + self.Emit("MOVQ", jit.Type(vt), _ET) + self.Emit("MOVQ", _ET, _VAR_et) self.Byte(0x4c , 0x8d, 0x0d) // LEAQ (PC), R9 self.Sref("_check_err_{n}", 4) self.Emit("MOVQ", _R9, _VAR_pc) @@ -1221,7 +1224,8 @@ func (self *_Assembler) _asm_OP_bool(_ *_Instr) { // try to skip the value self.Emit("MOVQ", _IC, _VAR_ic) - self.Emit("MOVQ", _T_bool, _VAR_et) + self.Emit("MOVQ", _T_bool, _ET) + self.Emit("MOVQ", _ET, _VAR_et) self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9 self.Sref("_end_{n}", 4) self.Emit("MOVQ", _R9, _VAR_pc) @@ -1261,7 +1265,8 @@ func (self *_Assembler) _asm_OP_num(_ *_Instr) { /* call skip one */ self.Emit("MOVQ", _BP, _VAR_ic) - self.Emit("MOVQ", _T_number, _VAR_et) + self.Emit("MOVQ", _T_number, _ET) + self.Emit("MOVQ", _ET, _VAR_et) self.Byte(0x4c, 0x8d, 0x0d) self.Sref("_num_end_{n}", 4) self.Emit("MOVQ", _R9, _VAR_pc) diff --git a/decoder/assembler_amd64_go117.go b/decoder/assembler_amd64_go117.go index f658ebd49..65b4df6f2 100644 --- a/decoder/assembler_amd64_go117.go +++ b/decoder/assembler_amd64_go117.go @@ -196,8 +196,8 @@ var _VAR_fl = jit.Ptr(_SP, _FP_fargs + _FP_saves + 112) var ( _VAR_et = jit.Ptr(_SP, _FP_fargs + _FP_saves + 120) // save dismatched type - _VAR_ic = jit.Ptr(_SP, _FP_fargs + _FP_saves + 128) // save dismatched position - _VAR_pc = jit.Ptr(_SP, _FP_fargs + _FP_saves + 136) // save skip return pc + _VAR_pc = jit.Ptr(_SP, _FP_fargs + _FP_saves + 128) // save skip return pc + _VAR_ic = jit.Ptr(_SP, _FP_fargs + _FP_saves + 136) // save dismatched position ) type _Assembler struct { @@ -305,6 +305,11 @@ var _OpFuncTab = [256]func(*_Assembler, *_Instr) { _OP_dismatch_err : (*_Assembler)._asm_OP_dismatch_err, _OP_go_skip : (*_Assembler)._asm_OP_go_skip, _OP_add : (*_Assembler)._asm_OP_add, + _OP_debug : (*_Assembler)._asm_OP_debug, +} + +func (self *_Assembler) _asm_OP_debug(_ *_Instr) { + self.Byte(0xcc) } func (self *_Assembler) instr(v *_Instr) { @@ -566,13 +571,15 @@ func (self *_Assembler) parsing_error() { } func (self *_Assembler) _asm_OP_dismatch_err(p *_Instr) { - self.Emit("MOVQ", _IC, _VAR_ic) - self.Emit("MOVQ", jit.Type(p.vt()), _VAR_et) + self.Emit("MOVQ", _IC, _VAR_ic) + self.Emit("MOVQ", jit.Type(p.vt()), _ET) + self.Emit("MOVQ", _ET, _VAR_et) } func (self *_Assembler) _asm_OP_go_skip(p *_Instr) { self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9 self.Xref(p.vi(), 4) + // self.Byte(0xcc) self.Emit("MOVQ", _R9, _VAR_pc) self.Sjmp("JMP" , _LB_skip_one) // JMP _skip_one } @@ -584,6 +591,7 @@ func (self *_Assembler) skip_one() { self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v self.Emit("MOVQ" , _VAR_pc, _R9) // MOVQ pc, R9 + // self.Byte(0xcc) self.Rjmp("JMP" , _R9) // JMP (R9) } @@ -643,7 +651,8 @@ func (self *_Assembler) check_err(vt reflect.Type) { if vt != nil { self.Sjmp("JNS" , "_check_err_{n}") // JNE _parsing_error_v self.Emit("MOVQ", _BX, _VAR_ic) - self.Emit("MOVQ", jit.Type(vt), _VAR_et) + self.Emit("MOVQ", jit.Type(vt), _ET) + self.Emit("MOVQ", _ET, _VAR_et) self.Byte(0x4c , 0x8d, 0x0d) // LEAQ (PC), R9 self.Sref("_check_err_{n}", 4) self.Emit("MOVQ", _R9, _VAR_pc) @@ -1208,7 +1217,8 @@ func (self *_Assembler) _asm_OP_bool(_ *_Instr) { self.Sjmp("JE" , "_bool_true_{n}") // try to skip the value self.Emit("MOVQ", _IC, _VAR_ic) - self.Emit("MOVQ", _T_bool, _VAR_et) + self.Emit("MOVQ", _T_bool, _ET) + self.Emit("MOVQ", _ET, _VAR_et) self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9 self.Sref("_end_{n}", 4) self.Emit("MOVQ", _R9, _VAR_pc) @@ -1252,7 +1262,8 @@ func (self *_Assembler) _asm_OP_num(_ *_Instr) { /* call skip one */ self.Emit("MOVQ", _BX, _VAR_ic) - self.Emit("MOVQ", _T_number, _VAR_et) + self.Emit("MOVQ", _T_number, _ET) + self.Emit("MOVQ", _ET, _VAR_et) self.Byte(0x4c, 0x8d, 0x0d) self.Sref("_num_end_{n}", 4) self.Emit("MOVQ", _R9, _VAR_pc) diff --git a/decoder/compiler.go b/decoder/compiler.go index 9da1c7237..7c9b9428d 100644 --- a/decoder/compiler.go +++ b/decoder/compiler.go @@ -98,6 +98,7 @@ const ( _OP_dismatch_err _OP_go_skip _OP_add + _OP_debug ) const ( @@ -951,7 +952,7 @@ func (self *_Compiler) compileStructFieldStr(p *_Program, sp int, vt reflect.Typ n0 := p.pc() p.add(_OP_is_null) - skip := self.checkIfSkip(p, vt, '"') + skip := self.checkIfSkip(p, stringType, '"') /* also check for inner "null" */ n1 = p.pc() @@ -1108,7 +1109,7 @@ func (self *_Compiler) checkIfSkip(p *_Program, vt reflect.Type, c byte) int { p.chr(_OP_check_char_0, c) p.rtt(_OP_dismatch_err, vt) s := p.pc() - p.int(_OP_go_skip, s) + p.add(_OP_go_skip) p.pin(j) p.int(_OP_add, 1) return s