Import errors from personal tmflow repo, and cleanup

This commit is contained in:
Ethan Frey 2017-05-24 20:44:58 +02:00
parent 1307064ce5
commit c130603d10
3 changed files with 150 additions and 0 deletions

20
errors/common.go Normal file
View File

@ -0,0 +1,20 @@
package errors
/**
* Copyright (C) 2017 Ethan Frey
**/
import abci "github.com/tendermint/abci/types"
const (
msgDecoding = "Error decoding input"
msgUnauthorized = "Unauthorized"
)
func DecodingError() TMError {
return New(msgDecoding, abci.CodeType_EncodingError)
}
func Unauthorized() TMError {
return New(msgUnauthorized, abci.CodeType_Unauthorized)
}

91
errors/main.go Normal file
View File

@ -0,0 +1,91 @@
package errors
/**
* Copyright (C) 2017 Ethan Frey
**/
import (
"github.com/pkg/errors"
abci "github.com/tendermint/abci/types"
)
const defaultErrCode = abci.CodeType_InternalError
type stackTracer interface {
error
StackTrace() errors.StackTrace
}
type TMError interface {
stackTracer
ErrorCode() abci.CodeType
Message() string
}
type tmerror struct {
stackTracer
code abci.CodeType
msg string
}
func (t tmerror) ErrorCode() abci.CodeType {
return t.code
}
func (t tmerror) Message() string {
return t.msg
}
// Result converts any error into a abci.Result, preserving as much info
// as possible if it was already a TMError
func Result(err error) abci.Result {
tm := Wrap(err)
return abci.Result{
Code: tm.ErrorCode(),
Log: tm.Message(),
}
}
// Wrap safely takes any error and promotes it to a TMError
func Wrap(err error) TMError {
// nil or TMError are no-ops
if err == nil {
return nil
}
// and check for noop
tm, ok := err.(TMError)
if ok {
return tm
}
return WithCode(err, defaultErrCode)
}
// WithCode adds a stacktrace if necessary and sets the code and msg,
// overriding the state if err was already TMError
func WithCode(err error, code abci.CodeType) TMError {
// add a stack only if not present
st, ok := err.(stackTracer)
if !ok {
st = errors.WithStack(err).(stackTracer)
}
// and then wrap it with TMError info
return tmerror{
stackTracer: st,
code: code,
msg: err.Error(),
}
}
// New adds a stacktrace if necessary and sets the code and msg,
// overriding the state if err was already TMError
func New(msg string, code abci.CodeType) TMError {
// create a new error with stack trace and attach a code
st := errors.New(msg).(stackTracer)
return tmerror{
stackTracer: st,
code: code,
msg: msg,
}
}

39
errors/main_test.go Normal file
View File

@ -0,0 +1,39 @@
package errors
import (
stderr "errors"
"strconv"
"testing"
pkerr "github.com/pkg/errors"
"github.com/stretchr/testify/assert"
abci "github.com/tendermint/abci/types"
)
func TestCreateResult(t *testing.T) {
assert := assert.New(t)
cases := []struct {
err error
msg string
code abci.CodeType
}{
{stderr.New("base"), "base", defaultErrCode},
{pkerr.New("dave"), "dave", defaultErrCode},
{New("nonce", abci.CodeType_BadNonce), "nonce", abci.CodeType_BadNonce},
{Wrap(stderr.New("wrap")), "wrap", defaultErrCode},
{WithCode(stderr.New("coded"), abci.CodeType_BaseInvalidInput), "coded", abci.CodeType_BaseInvalidInput},
{DecodingError(), msgDecoding, abci.CodeType_EncodingError},
{Unauthorized(), msgUnauthorized, abci.CodeType_Unauthorized},
}
for idx, tc := range cases {
i := strconv.Itoa(idx)
res := Result(tc.err)
assert.True(res.IsErr(), i)
assert.Equal(tc.msg, res.Log, i)
assert.Equal(tc.code, res.Code, i)
}
}