mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
encoding/json: check exact structure of local error types in tests
During the development of error wrapping (#29934), the tests were modified to stop using reflect.DeepEqual since the prototype for error wrapping at the time included frame information of where the error was created. However, that change diminished the fidelity of the test so that it is no longer as strict, which affects the endeavor to implement v1 in terms of the v2 prototype. For locally declared error types, use reflect.DeepEqual to check that the exact structure of the error value matches. Change-Id: I443d418533866ab8d533bca3785fdc741e2c140e Reviewed-on: https://go-review.googlesource.com/c/go/+/629517 Auto-Submit: Damien Neil <dneil@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Daniel Martí <mvdan@mvdan.cc> Reviewed-by: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
4d6170427f
commit
99dad52816
1 changed files with 37 additions and 40 deletions
|
|
@ -443,7 +443,7 @@ var unmarshalTests = []struct {
|
|||
{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: `{"T": {"X": 23}}`, ptr: new(TOuter), out: TOuter{}, err: &UnmarshalTypeError{"number", reflect.TypeFor[string](), 0, "TOuter", "T.X"}},
|
||||
{CaseName: Name(""), in: `{"T": {"X": 23}}`, ptr: new(TOuter), out: TOuter{}, err: &UnmarshalTypeError{"number", reflect.TypeFor[string](), 8, "TOuter", "T.X"}},
|
||||
{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},
|
||||
|
|
@ -907,7 +907,7 @@ var unmarshalTests = []struct {
|
|||
Struct: "Top",
|
||||
Field: "Embed0a.Level1a",
|
||||
Type: reflect.TypeFor[int](),
|
||||
Offset: 10,
|
||||
Offset: 19,
|
||||
},
|
||||
},
|
||||
|
||||
|
|
@ -1029,7 +1029,7 @@ var unmarshalTests = []struct {
|
|||
Struct: "T",
|
||||
Field: "Ts.Y",
|
||||
Type: reflect.TypeFor[int](),
|
||||
Offset: 29,
|
||||
Offset: 44,
|
||||
},
|
||||
},
|
||||
// #14702
|
||||
|
|
@ -1170,9 +1170,28 @@ func TestMarshalEmbeds(t *testing.T) {
|
|||
}
|
||||
|
||||
func equalError(a, b error) bool {
|
||||
isJSONError := func(err error) bool {
|
||||
switch err.(type) {
|
||||
case
|
||||
*InvalidUTF8Error,
|
||||
*InvalidUnmarshalError,
|
||||
*MarshalerError,
|
||||
*SyntaxError,
|
||||
*UnmarshalFieldError,
|
||||
*UnmarshalTypeError,
|
||||
*UnsupportedTypeError,
|
||||
*UnsupportedValueError:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if a == nil || b == nil {
|
||||
return a == nil && b == nil
|
||||
}
|
||||
if isJSONError(a) || isJSONError(b) {
|
||||
return reflect.DeepEqual(a, b) // safe for locally defined error types
|
||||
}
|
||||
return a.Error() == b.Error()
|
||||
}
|
||||
|
||||
|
|
@ -1217,7 +1236,7 @@ func TestUnmarshal(t *testing.T) {
|
|||
dec.DisallowUnknownFields()
|
||||
}
|
||||
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)
|
||||
t.Fatalf("%s: Decode error:\n\tgot: %#v\n\twant: %#v", tt.Where, err, tt.err)
|
||||
} else if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -2222,49 +2241,27 @@ func TestPrefilled(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInvalidUnmarshal(t *testing.T) {
|
||||
buf := []byte(`{"a":"1"}`)
|
||||
tests := []struct {
|
||||
CaseName
|
||||
in string
|
||||
v any
|
||||
want string
|
||||
wantErr error
|
||||
}{
|
||||
{Name(""), nil, "json: Unmarshal(nil)"},
|
||||
{Name(""), struct{}{}, "json: Unmarshal(non-pointer struct {})"},
|
||||
{Name(""), (*int)(nil), "json: Unmarshal(nil *int)"},
|
||||
{Name(""), `{"a":"1"}`, nil, &InvalidUnmarshalError{}},
|
||||
{Name(""), `{"a":"1"}`, struct{}{}, &InvalidUnmarshalError{reflect.TypeFor[struct{}]()}},
|
||||
{Name(""), `{"a":"1"}`, (*int)(nil), &InvalidUnmarshalError{reflect.TypeFor[*int]()}},
|
||||
{Name(""), `123`, nil, &InvalidUnmarshalError{}},
|
||||
{Name(""), `123`, struct{}{}, &InvalidUnmarshalError{reflect.TypeFor[struct{}]()}},
|
||||
{Name(""), `123`, (*int)(nil), &InvalidUnmarshalError{reflect.TypeFor[*int]()}},
|
||||
{Name(""), `123`, new(net.IP), &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[*net.IP](), Offset: 3}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.Name, func(t *testing.T) {
|
||||
err := Unmarshal(buf, tt.v)
|
||||
if err == nil {
|
||||
switch gotErr := Unmarshal([]byte(tt.in), tt.v); {
|
||||
case gotErr == 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidUnmarshalText(t *testing.T) {
|
||||
buf := []byte(`123`)
|
||||
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)
|
||||
case !reflect.DeepEqual(gotErr, tt.wantErr):
|
||||
t.Errorf("%s: Unmarshal error:\n\tgot: %#v\n\twant: %#v", tt.Where, gotErr, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue