Skip to content

Commit 92da41d

Browse files
committed
internal/jsonrpc2: test WireError.Is and fix nil target panic
WireError.Is backs errors.Is checks used across the SDK against sentinels such as ErrMethodNotFound, ErrRejected, and ErrClientClosing, but had no direct test. Add a table-driven test for it. While doing so, errors.Is(err, (*WireError)(nil)) was found to panic on a nil pointer dereference, because Is read w.Code without a nil check. Guard against a nil *WireError target so the comparison returns false.
1 parent 9576afc commit 92da41d

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

internal/jsonrpc2/wire.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func (err *WireError) Error() string {
8787

8888
func (err *WireError) Is(other error) bool {
8989
w, ok := other.(*WireError)
90-
if !ok {
90+
if !ok || w == nil {
9191
return false
9292
}
9393
return err.Code == w.Code

internal/jsonrpc2/wire_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package jsonrpc2_test
77
import (
88
"bytes"
99
"encoding/json"
10+
"errors"
1011
"reflect"
1112
"testing"
1213

@@ -147,6 +148,29 @@ func TestDecodeIDOnlyMessageIsResponse(t *testing.T) {
147148
}
148149
}
149150

151+
// TestWireErrorIs checks the errors.Is behavior of WireError, including that
152+
// comparing against a typed-nil *WireError does not panic.
153+
func TestWireErrorIs(t *testing.T) {
154+
err := jsonrpc2.NewError(-32600, "invalid request")
155+
for _, test := range []struct {
156+
name string
157+
target error
158+
want bool
159+
}{
160+
{name: "same code", target: jsonrpc2.NewError(-32600, "other message"), want: true},
161+
{name: "different code", target: jsonrpc2.NewError(-32601, "invalid request"), want: false},
162+
{name: "typed nil WireError", target: (*jsonrpc2.WireError)(nil), want: false},
163+
{name: "untyped nil", target: nil, want: false},
164+
{name: "other error type", target: errors.New("invalid request"), want: false},
165+
} {
166+
t.Run(test.name, func(t *testing.T) {
167+
if got := errors.Is(err, test.target); got != test.want {
168+
t.Errorf("errors.Is(%v, %v) = %v, want %v", err, test.target, got, test.want)
169+
}
170+
})
171+
}
172+
}
173+
150174
func checkJSON(t *testing.T, got, want []byte) {
151175
// compare the compact form, to allow for formatting differences
152176
g := &bytes.Buffer{}

0 commit comments

Comments
 (0)