cosmos-sdk/errors/errors_test.go

262 lines
8.2 KiB
Go

package errors
import (
stdlib "errors"
"fmt"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/suite"
)
type errorsTestSuite struct {
suite.Suite
}
func TestErrorsTestSuite(t *testing.T) {
suite.Run(t, new(errorsTestSuite))
}
func (s *errorsTestSuite) SetupSuite() {
s.T().Parallel()
}
func (s *errorsTestSuite) TestCause() {
std := stdlib.New("this is a stdlib error")
cases := map[string]struct {
err error
root error
}{
"Errors are self-causing": {
err: ErrUnauthorized,
root: ErrUnauthorized,
},
"Wrap reveals root cause": {
err: Wrap(ErrUnauthorized, "foo"),
root: ErrUnauthorized,
},
"Cause works for stderr as root": {
err: Wrap(std, "Some helpful text"),
root: std,
},
}
for testName, tc := range cases {
s.Require().Equal(tc.root, errors.Cause(tc.err), testName)
}
}
func (s *errorsTestSuite) TestErrorIs() {
cases := map[string]struct {
a *Error
b error
wantIs bool
}{
"instance of the same error": {
a: ErrUnauthorized,
b: ErrUnauthorized,
wantIs: true,
},
"two different coded errors": {
a: ErrUnauthorized,
b: ErrOutOfGas,
wantIs: false,
},
"successful comparison to a wrapped error": {
a: ErrUnauthorized,
b: errors.Wrap(ErrUnauthorized, "gone"),
wantIs: true,
},
"unsuccessful comparison to a wrapped error": {
a: ErrUnauthorized,
b: errors.Wrap(ErrInsufficientFee, "too big"),
wantIs: false,
},
"not equal to stdlib error": {
a: ErrUnauthorized,
b: fmt.Errorf("stdlib error"),
wantIs: false,
},
"not equal to a wrapped stdlib error": {
a: ErrUnauthorized,
b: errors.Wrap(fmt.Errorf("stdlib error"), "wrapped"),
wantIs: false,
},
"nil is nil": {
a: nil,
b: nil,
wantIs: true,
},
"nil is any error nil": {
a: nil,
b: (*customError)(nil),
wantIs: true,
},
"nil is not not-nil": {
a: nil,
b: ErrUnauthorized,
wantIs: false,
},
"not-nil is not nil": {
a: ErrUnauthorized,
b: nil,
wantIs: false,
},
}
for testName, tc := range cases {
s.Require().Equal(tc.wantIs, tc.a.Is(tc.b), testName)
}
}
func (s *errorsTestSuite) TestIsOf() {
require := s.Require()
var errNil *Error
var err = ErrInvalidAddress
var errW = Wrap(ErrLogic, "more info")
require.False(IsOf(errNil), "nil error should always have no causer")
require.False(IsOf(errNil, err), "nil error should always have no causer")
require.False(IsOf(err))
require.False(IsOf(err, nil))
require.False(IsOf(err, ErrLogic))
require.True(IsOf(errW, ErrLogic))
require.True(IsOf(errW, err, ErrLogic))
require.True(IsOf(errW, nil, errW), "error should much itself")
var err2 = errors.New("other error")
require.True(IsOf(err2, nil, err2), "error should much itself")
}
type customError struct {
}
func (customError) Error() string {
return "custom error"
}
func (s *errorsTestSuite) TestWrapEmpty() {
s.Require().Nil(Wrap(nil, "wrapping <nil>"))
}
func (s *errorsTestSuite) TestWrappedIs() {
require := s.Require()
err := Wrap(ErrTxTooLarge, "context")
require.True(stdlib.Is(err, ErrTxTooLarge))
err = Wrap(err, "more context")
require.True(stdlib.Is(err, ErrTxTooLarge))
err = Wrap(err, "even more context")
require.True(stdlib.Is(err, ErrTxTooLarge))
err = Wrap(ErrInsufficientFee, "...")
require.False(stdlib.Is(err, ErrTxTooLarge))
errs := stdlib.New("other")
require.True(stdlib.Is(errs, errs))
errw := &wrappedError{"msg", errs}
require.True(errw.Is(errw), "should match itself")
require.True(stdlib.Is(ErrInsufficientFee.Wrap("wrapped"), ErrInsufficientFee))
require.True(IsOf(ErrInsufficientFee.Wrap("wrapped"), ErrInsufficientFee))
require.True(stdlib.Is(ErrInsufficientFee.Wrapf("wrapped"), ErrInsufficientFee))
require.True(IsOf(ErrInsufficientFee.Wrapf("wrapped"), ErrInsufficientFee))
}
func (s *errorsTestSuite) TestWrappedIsMultiple() {
var errTest = errors.New("test error")
var errTest2 = errors.New("test error 2")
err := Wrap(errTest2, Wrap(errTest, "some random description").Error())
s.Require().True(stdlib.Is(err, errTest2))
}
func (s *errorsTestSuite) TestWrappedIsFail() {
var errTest = errors.New("test error")
var errTest2 = errors.New("test error 2")
err := Wrap(errTest2, Wrap(errTest, "some random description").Error())
s.Require().False(stdlib.Is(err, errTest))
}
func (s *errorsTestSuite) TestWrappedUnwrap() {
var errTest = errors.New("test error")
err := Wrap(errTest, "some random description")
s.Require().Equal(errTest, stdlib.Unwrap(err))
}
func (s *errorsTestSuite) TestWrappedUnwrapMultiple() {
var errTest = errors.New("test error")
var errTest2 = errors.New("test error 2")
err := Wrap(errTest2, Wrap(errTest, "some random description").Error())
s.Require().Equal(errTest2, stdlib.Unwrap(err))
}
func (s *errorsTestSuite) TestWrappedUnwrapFail() {
var errTest = errors.New("test error")
var errTest2 = errors.New("test error 2")
err := Wrap(errTest2, Wrap(errTest, "some random description").Error())
s.Require().NotEqual(errTest, stdlib.Unwrap(err))
}
func (s *errorsTestSuite) TestABCIError() {
s.Require().Equal("custom: tx parse error", ABCIError(testCodespace, 2, "custom").Error())
s.Require().Equal("custom: unknown", ABCIError("unknown", 1, "custom").Error())
}
func ExampleWrap() {
err1 := Wrap(ErrInsufficientFunds, "90 is smaller than 100")
err2 := errors.Wrap(ErrInsufficientFunds, "90 is smaller than 100")
fmt.Println(err1.Error())
fmt.Println(err2.Error())
// Output:
// 90 is smaller than 100: insufficient funds
// 90 is smaller than 100: insufficient funds
}
func ExampleWrapf() {
err1 := Wrap(ErrInsufficientFunds, "90 is smaller than 100")
err2 := errors.Wrap(ErrInsufficientFunds, "90 is smaller than 100")
fmt.Println(err1.Error())
fmt.Println(err2.Error())
// Output:
// 90 is smaller than 100: insufficient funds
// 90 is smaller than 100: insufficient funds
}
const testCodespace = "testtesttest"
var (
ErrTxDecode = Register(testCodespace, 2, "tx parse error")
ErrInvalidSequence = Register(testCodespace, 3, "invalid sequence")
ErrUnauthorized = Register(testCodespace, 4, "unauthorized")
ErrInsufficientFunds = Register(testCodespace, 5, "insufficient funds")
ErrUnknownRequest = Register(testCodespace, 6, "unknown request")
ErrInvalidAddress = Register(testCodespace, 7, "invalid address")
ErrInvalidPubKey = Register(testCodespace, 8, "invalid pubkey")
ErrUnknownAddress = Register(testCodespace, 9, "unknown address")
ErrInvalidCoins = Register(testCodespace, 10, "invalid coins")
ErrOutOfGas = Register(testCodespace, 11, "out of gas")
ErrInsufficientFee = Register(testCodespace, 13, "insufficient fee")
ErrTooManySignatures = Register(testCodespace, 14, "maximum number of signatures exceeded")
ErrNoSignatures = Register(testCodespace, 15, "no signatures supplied")
ErrJSONMarshal = Register(testCodespace, 16, "failed to marshal JSON bytes")
ErrJSONUnmarshal = Register(testCodespace, 17, "failed to unmarshal JSON bytes")
ErrInvalidRequest = Register(testCodespace, 18, "invalid request")
ErrMempoolIsFull = Register(testCodespace, 20, "mempool is full")
ErrTxTooLarge = Register(testCodespace, 21, "tx too large")
ErrKeyNotFound = Register(testCodespace, 22, "key not found")
ErrorInvalidSigner = Register(testCodespace, 24, "tx intended signer does not match the given signer")
ErrInvalidChainID = Register(testCodespace, 28, "invalid chain-id")
ErrInvalidType = Register(testCodespace, 29, "invalid type")
ErrUnknownExtensionOptions = Register(testCodespace, 31, "unknown extension options")
ErrPackAny = Register(testCodespace, 33, "failed packing protobuf message to Any")
ErrLogic = Register(testCodespace, 35, "internal logic error")
ErrConflict = Register(testCodespace, 36, "conflict")
ErrNotSupported = Register(testCodespace, 37, "feature not supported")
ErrNotFound = Register(testCodespace, 38, "not found")
ErrIO = Register(testCodespace, 39, "Internal IO error")
)