mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
encoding/json: add struct and field name to UnmarshalTypeError message
The UnmarshalTypeError has two new fields Struct and Field, used when constructing the error message. Fixes #6716. Change-Id: I67da171480a9491960b3ae81893770644180f848 Reviewed-on: https://go-review.googlesource.com/18692 Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Russ Cox <rsc@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
cb986def67
commit
b9fd510cd0
2 changed files with 90 additions and 34 deletions
|
|
@ -112,9 +112,14 @@ type UnmarshalTypeError struct {
|
||||||
Value string // description of JSON value - "bool", "array", "number -5"
|
Value string // description of JSON value - "bool", "array", "number -5"
|
||||||
Type reflect.Type // type of Go value it could not be assigned to
|
Type reflect.Type // type of Go value it could not be assigned to
|
||||||
Offset int64 // error occurred after reading Offset bytes
|
Offset int64 // error occurred after reading Offset bytes
|
||||||
|
Struct string // name of the struct type containing the field
|
||||||
|
Field string // name of the field holding the Go value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *UnmarshalTypeError) Error() string {
|
func (e *UnmarshalTypeError) Error() string {
|
||||||
|
if e.Struct != "" || e.Field != "" {
|
||||||
|
return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String()
|
||||||
|
}
|
||||||
return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
|
return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,10 +253,14 @@ func isValidNumber(s string) bool {
|
||||||
|
|
||||||
// decodeState represents the state while decoding a JSON value.
|
// decodeState represents the state while decoding a JSON value.
|
||||||
type decodeState struct {
|
type decodeState struct {
|
||||||
data []byte
|
data []byte
|
||||||
off int // read offset in data
|
off int // read offset in data
|
||||||
scan scanner
|
scan scanner
|
||||||
nextscan scanner // for calls to nextValue
|
nextscan scanner // for calls to nextValue
|
||||||
|
errorContext struct { // provides context for type errors
|
||||||
|
Struct string
|
||||||
|
Field string
|
||||||
|
}
|
||||||
savedError error
|
savedError error
|
||||||
useNumber bool
|
useNumber bool
|
||||||
}
|
}
|
||||||
|
|
@ -265,22 +274,37 @@ func (d *decodeState) init(data []byte) *decodeState {
|
||||||
d.data = data
|
d.data = data
|
||||||
d.off = 0
|
d.off = 0
|
||||||
d.savedError = nil
|
d.savedError = nil
|
||||||
|
d.errorContext.Struct = ""
|
||||||
|
d.errorContext.Field = ""
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
// error aborts the decoding by panicking with err.
|
// error aborts the decoding by panicking with err.
|
||||||
func (d *decodeState) error(err error) {
|
func (d *decodeState) error(err error) {
|
||||||
panic(err)
|
panic(d.addErrorContext(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// saveError saves the first err it is called with,
|
// saveError saves the first err it is called with,
|
||||||
// for reporting at the end of the unmarshal.
|
// for reporting at the end of the unmarshal.
|
||||||
func (d *decodeState) saveError(err error) {
|
func (d *decodeState) saveError(err error) {
|
||||||
if d.savedError == nil {
|
if d.savedError == nil {
|
||||||
d.savedError = err
|
d.savedError = d.addErrorContext(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addErrorContext returns a new error enhanced with information from d.errorContext
|
||||||
|
func (d *decodeState) addErrorContext(err error) error {
|
||||||
|
if d.errorContext.Struct != "" || d.errorContext.Field != "" {
|
||||||
|
switch err := err.(type) {
|
||||||
|
case *UnmarshalTypeError:
|
||||||
|
err.Struct = d.errorContext.Struct
|
||||||
|
err.Field = d.errorContext.Field
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// next cuts off and returns the next full JSON value in d.data[d.off:].
|
// next cuts off and returns the next full JSON value in d.data[d.off:].
|
||||||
// The next value is known to be an object or array, not a literal.
|
// The next value is known to be an object or array, not a literal.
|
||||||
func (d *decodeState) next() []byte {
|
func (d *decodeState) next() []byte {
|
||||||
|
|
@ -457,7 +481,7 @@ func (d *decodeState) array(v reflect.Value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ut != nil {
|
if ut != nil {
|
||||||
d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)})
|
||||||
d.off--
|
d.off--
|
||||||
d.next()
|
d.next()
|
||||||
return
|
return
|
||||||
|
|
@ -476,7 +500,7 @@ func (d *decodeState) array(v reflect.Value) {
|
||||||
// Otherwise it's invalid.
|
// Otherwise it's invalid.
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)})
|
||||||
d.off--
|
d.off--
|
||||||
d.next()
|
d.next()
|
||||||
return
|
return
|
||||||
|
|
@ -566,7 +590,7 @@ func (d *decodeState) object(v reflect.Value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ut != nil {
|
if ut != nil {
|
||||||
d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)})
|
||||||
d.off--
|
d.off--
|
||||||
d.next() // skip over { } in input
|
d.next() // skip over { } in input
|
||||||
return
|
return
|
||||||
|
|
@ -594,7 +618,7 @@ func (d *decodeState) object(v reflect.Value) {
|
||||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
default:
|
default:
|
||||||
if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) {
|
if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) {
|
||||||
d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)})
|
||||||
d.off--
|
d.off--
|
||||||
d.next() // skip over { } in input
|
d.next() // skip over { } in input
|
||||||
return
|
return
|
||||||
|
|
@ -604,9 +628,9 @@ func (d *decodeState) object(v reflect.Value) {
|
||||||
v.Set(reflect.MakeMap(t))
|
v.Set(reflect.MakeMap(t))
|
||||||
}
|
}
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
|
// ok
|
||||||
default:
|
default:
|
||||||
d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)})
|
||||||
d.off--
|
d.off--
|
||||||
d.next() // skip over { } in input
|
d.next() // skip over { } in input
|
||||||
return
|
return
|
||||||
|
|
@ -671,6 +695,8 @@ func (d *decodeState) object(v reflect.Value) {
|
||||||
}
|
}
|
||||||
subv = subv.Field(i)
|
subv = subv.Field(i)
|
||||||
}
|
}
|
||||||
|
d.errorContext.Field = f.name
|
||||||
|
d.errorContext.Struct = v.Type().Name()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -682,7 +708,6 @@ func (d *decodeState) object(v reflect.Value) {
|
||||||
d.error(errPhase)
|
d.error(errPhase)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read value.
|
|
||||||
if destring {
|
if destring {
|
||||||
switch qv := d.valueQuoted().(type) {
|
switch qv := d.valueQuoted().(type) {
|
||||||
case nil:
|
case nil:
|
||||||
|
|
@ -714,7 +739,7 @@ func (d *decodeState) object(v reflect.Value) {
|
||||||
s := string(key)
|
s := string(key)
|
||||||
n, err := strconv.ParseInt(s, 10, 64)
|
n, err := strconv.ParseInt(s, 10, 64)
|
||||||
if err != nil || reflect.Zero(kt).OverflowInt(n) {
|
if err != nil || reflect.Zero(kt).OverflowInt(n) {
|
||||||
d.saveError(&UnmarshalTypeError{"number " + s, kt, int64(start + 1)})
|
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
kv = reflect.ValueOf(n).Convert(kt)
|
kv = reflect.ValueOf(n).Convert(kt)
|
||||||
|
|
@ -722,7 +747,7 @@ func (d *decodeState) object(v reflect.Value) {
|
||||||
s := string(key)
|
s := string(key)
|
||||||
n, err := strconv.ParseUint(s, 10, 64)
|
n, err := strconv.ParseUint(s, 10, 64)
|
||||||
if err != nil || reflect.Zero(kt).OverflowUint(n) {
|
if err != nil || reflect.Zero(kt).OverflowUint(n) {
|
||||||
d.saveError(&UnmarshalTypeError{"number " + s, kt, int64(start + 1)})
|
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
kv = reflect.ValueOf(n).Convert(kt)
|
kv = reflect.ValueOf(n).Convert(kt)
|
||||||
|
|
@ -741,6 +766,9 @@ func (d *decodeState) object(v reflect.Value) {
|
||||||
if op != scanObjectValue {
|
if op != scanObjectValue {
|
||||||
d.error(errPhase)
|
d.error(errPhase)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.errorContext.Struct = ""
|
||||||
|
d.errorContext.Field = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -767,7 +795,7 @@ func (d *decodeState) convertNumber(s string) (interface{}, error) {
|
||||||
}
|
}
|
||||||
f, err := strconv.ParseFloat(s, 64)
|
f, err := strconv.ParseFloat(s, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)}
|
return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeOf(0.0), Offset: int64(d.off)}
|
||||||
}
|
}
|
||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
@ -800,7 +828,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||||
if fromQuoted {
|
if fromQuoted {
|
||||||
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
||||||
} else {
|
} else {
|
||||||
d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.off)})
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -835,7 +863,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||||
if fromQuoted {
|
if fromQuoted {
|
||||||
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
||||||
} else {
|
} else {
|
||||||
d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.off)})
|
||||||
}
|
}
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
v.SetBool(value)
|
v.SetBool(value)
|
||||||
|
|
@ -843,7 +871,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||||
if v.NumMethod() == 0 {
|
if v.NumMethod() == 0 {
|
||||||
v.Set(reflect.ValueOf(value))
|
v.Set(reflect.ValueOf(value))
|
||||||
} else {
|
} else {
|
||||||
d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.off)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -858,10 +886,10 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||||
}
|
}
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
default:
|
default:
|
||||||
d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.off)})
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
if v.Type().Elem().Kind() != reflect.Uint8 {
|
if v.Type().Elem().Kind() != reflect.Uint8 {
|
||||||
d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.off)})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
|
b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
|
||||||
|
|
@ -877,7 +905,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||||
if v.NumMethod() == 0 {
|
if v.NumMethod() == 0 {
|
||||||
v.Set(reflect.ValueOf(string(s)))
|
v.Set(reflect.ValueOf(string(s)))
|
||||||
} else {
|
} else {
|
||||||
d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.off)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -902,7 +930,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||||
if fromQuoted {
|
if fromQuoted {
|
||||||
d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
||||||
} else {
|
} else {
|
||||||
d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
|
d.error(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.off)})
|
||||||
}
|
}
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
n, err := d.convertNumber(s)
|
n, err := d.convertNumber(s)
|
||||||
|
|
@ -911,7 +939,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if v.NumMethod() != 0 {
|
if v.NumMethod() != 0 {
|
||||||
d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.off)})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.Set(reflect.ValueOf(n))
|
v.Set(reflect.ValueOf(n))
|
||||||
|
|
@ -919,7 +947,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
n, err := strconv.ParseInt(s, 10, 64)
|
n, err := strconv.ParseInt(s, 10, 64)
|
||||||
if err != nil || v.OverflowInt(n) {
|
if err != nil || v.OverflowInt(n) {
|
||||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.off)})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.SetInt(n)
|
v.SetInt(n)
|
||||||
|
|
@ -927,7 +955,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
n, err := strconv.ParseUint(s, 10, 64)
|
n, err := strconv.ParseUint(s, 10, 64)
|
||||||
if err != nil || v.OverflowUint(n) {
|
if err != nil || v.OverflowUint(n) {
|
||||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.off)})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.SetUint(n)
|
v.SetUint(n)
|
||||||
|
|
@ -935,7 +963,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||||
case reflect.Float32, reflect.Float64:
|
case reflect.Float32, reflect.Float64:
|
||||||
n, err := strconv.ParseFloat(s, v.Type().Bits())
|
n, err := strconv.ParseFloat(s, v.Type().Bits())
|
||||||
if err != nil || v.OverflowFloat(n) {
|
if err != nil || v.OverflowFloat(n) {
|
||||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
|
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.off)})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.SetFloat(n)
|
v.SetFloat(n)
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,11 @@ type V struct {
|
||||||
F1 interface{}
|
F1 interface{}
|
||||||
F2 int32
|
F2 int32
|
||||||
F3 Number
|
F3 Number
|
||||||
|
F4 *VOuter
|
||||||
|
}
|
||||||
|
|
||||||
|
type VOuter struct {
|
||||||
|
V V
|
||||||
}
|
}
|
||||||
|
|
||||||
// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and
|
// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and
|
||||||
|
|
@ -389,7 +394,7 @@ var unmarshalTests = []unmarshalTest{
|
||||||
{in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"},
|
{in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"},
|
||||||
{in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
|
{in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
|
||||||
{in: "null", ptr: new(interface{}), out: nil},
|
{in: "null", ptr: new(interface{}), out: nil},
|
||||||
{in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7}},
|
{in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7, "T", "X"}},
|
||||||
{in: `{"x": 1}`, ptr: new(tx), out: tx{}},
|
{in: `{"x": 1}`, ptr: new(tx), out: tx{}},
|
||||||
{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: 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: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
|
||||||
|
|
@ -504,22 +509,22 @@ var unmarshalTests = []unmarshalTest{
|
||||||
{
|
{
|
||||||
in: `{"abc":"abc"}`,
|
in: `{"abc":"abc"}`,
|
||||||
ptr: new(map[int]string),
|
ptr: new(map[int]string),
|
||||||
err: &UnmarshalTypeError{"number abc", reflect.TypeOf(0), 2},
|
err: &UnmarshalTypeError{Value: "number abc", Type: reflect.TypeOf(0), Offset: 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: `{"256":"abc"}`,
|
in: `{"256":"abc"}`,
|
||||||
ptr: new(map[uint8]string),
|
ptr: new(map[uint8]string),
|
||||||
err: &UnmarshalTypeError{"number 256", reflect.TypeOf(uint8(0)), 2},
|
err: &UnmarshalTypeError{Value: "number 256", Type: reflect.TypeOf(uint8(0)), Offset: 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: `{"128":"abc"}`,
|
in: `{"128":"abc"}`,
|
||||||
ptr: new(map[int8]string),
|
ptr: new(map[int8]string),
|
||||||
err: &UnmarshalTypeError{"number 128", reflect.TypeOf(int8(0)), 2},
|
err: &UnmarshalTypeError{Value: "number 128", Type: reflect.TypeOf(int8(0)), Offset: 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: `{"-1":"abc"}`,
|
in: `{"-1":"abc"}`,
|
||||||
ptr: new(map[uint8]string),
|
ptr: new(map[uint8]string),
|
||||||
err: &UnmarshalTypeError{"number -1", reflect.TypeOf(uint8(0)), 2},
|
err: &UnmarshalTypeError{Value: "number -1", Type: reflect.TypeOf(uint8(0)), Offset: 2},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Map keys can be encoding.TextUnmarshalers.
|
// Map keys can be encoding.TextUnmarshalers.
|
||||||
|
|
@ -653,12 +658,12 @@ var unmarshalTests = []unmarshalTest{
|
||||||
{
|
{
|
||||||
in: `{"2009-11-10T23:00:00Z": "hello world"}`,
|
in: `{"2009-11-10T23:00:00Z": "hello world"}`,
|
||||||
ptr: &map[Point]string{},
|
ptr: &map[Point]string{},
|
||||||
err: &UnmarshalTypeError{"object", reflect.TypeOf(map[Point]string{}), 1},
|
err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[Point]string{}), Offset: 1},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: `{"asdf": "hello world"}`,
|
in: `{"asdf": "hello world"}`,
|
||||||
ptr: &map[unmarshaler]string{},
|
ptr: &map[unmarshaler]string{},
|
||||||
err: &UnmarshalTypeError{"object", reflect.TypeOf(map[unmarshaler]string{}), 1},
|
err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[unmarshaler]string{}), Offset: 1},
|
||||||
},
|
},
|
||||||
|
|
||||||
// related to issue 13783.
|
// related to issue 13783.
|
||||||
|
|
@ -750,6 +755,29 @@ var unmarshalTests = []unmarshalTest{
|
||||||
{in: `999999999999999900000`, ptr: new(float64), out: 999999999999999900000.0, golden: true},
|
{in: `999999999999999900000`, ptr: new(float64), out: 999999999999999900000.0, golden: true},
|
||||||
{in: `9007199254740992`, ptr: new(float64), out: 9007199254740992.0, golden: true},
|
{in: `9007199254740992`, ptr: new(float64), out: 9007199254740992.0, golden: true},
|
||||||
{in: `9007199254740993`, ptr: new(float64), out: 9007199254740992.0, golden: false},
|
{in: `9007199254740993`, ptr: new(float64), out: 9007199254740992.0, golden: false},
|
||||||
|
|
||||||
|
{
|
||||||
|
in: `{"V": {"F2": "hello"}}`,
|
||||||
|
ptr: new(VOuter),
|
||||||
|
err: &UnmarshalTypeError{
|
||||||
|
Value: "string",
|
||||||
|
Struct: "V",
|
||||||
|
Field: "F2",
|
||||||
|
Type: reflect.TypeOf(int32(0)),
|
||||||
|
Offset: 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: `{"V": {"F4": {}, "F2": "hello"}}`,
|
||||||
|
ptr: new(VOuter),
|
||||||
|
err: &UnmarshalTypeError{
|
||||||
|
Value: "string",
|
||||||
|
Struct: "V",
|
||||||
|
Field: "F2",
|
||||||
|
Type: reflect.TypeOf(int32(0)),
|
||||||
|
Offset: 30,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMarshal(t *testing.T) {
|
func TestMarshal(t *testing.T) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue