diff options
| author | Joe Tsai <joetsai@digital-static.net> | 2024-11-18 17:34:06 -0800 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2024-11-19 18:48:19 +0000 |
| commit | 99dad5281660c4e644602e0c8790dd24b3eb45f3 (patch) | |
| tree | 873d59b65580dc1a0e51ba351b4aba2740f7a5f0 /src/encoding/json | |
| parent | 4d6170427f4d02e79454b25391b56e7d1c5ceb39 (diff) | |
| download | go-99dad5281660c4e644602e0c8790dd24b3eb45f3.tar.xz | |
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>
Diffstat (limited to 'src/encoding/json')
| -rw-r--r-- | src/encoding/json/decode_test.go | 77 |
1 files changed, 37 insertions, 40 deletions
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index 71895a9bb1..de09fae50f 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -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 - v any - want string + in string + v any + 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) } }) } |
