feat: error wrapper

This commit is contained in:
Suyono 2023-02-23 14:15:51 +11:00
parent a8310b5dc8
commit d92cace9c8
7 changed files with 262 additions and 0 deletions

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

9
.idea/errors.iml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/errors.iml" filepath="$PROJECT_DIR$/.idea/errors.iml" />
</modules>
</component>
</project>

1
.tool-versions Normal file
View File

@ -0,0 +1 @@
golang 1.16

131
errors.go Normal file
View File

@ -0,0 +1,131 @@
package errors
import (
"errors"
"fmt"
"runtime"
)
type ErrorWithStatus interface {
error
ExitStatus() int
IsSkipPrintMessage() bool
SetError(err error) ErrorWithStatus
SkipMessage() ErrorWithStatus
SetPrintMessage() ErrorWithStatus
SetExitStatus(status int) ErrorWithStatus
}
type errorWithStatus struct {
err error
status int
skipMessage bool
frames []frame
}
type frame struct {
file string
line int
function string
}
func NeedExit(err error) (ErrorWithStatus, bool) {
if err != nil {
if esw, ok := err.(ErrorWithStatus); ok {
return esw, esw.ExitStatus() != 0
}
}
return nil, false
}
func NewErrorWithStatus(err error, status int, skipMessage bool) ErrorWithStatus {
return &errorWithStatus{
err: err,
status: status,
skipMessage: skipMessage,
}
}
func NewError() ErrorWithStatus {
return &errorWithStatus{
err: errors.New("error"),
status: -1,
skipMessage: false,
}
}
func NewErrorWithFrames(err error) ErrorWithStatus {
pcs := make([]uintptr, 0)
npc := runtime.Callers(0, pcs)
returnValue := &errorWithStatus{
err: err,
status: -1,
skipMessage: false,
}
if npc > 0 {
frs := runtime.CallersFrames(pcs)
more := true
var fr runtime.Frame
for more {
fr, more = frs.Next()
returnValue.frames = append(returnValue.frames, frame{
file: fr.File,
function: fr.Function,
line: fr.Line,
})
}
}
return returnValue
}
func NewErrorfStatus(status int, str string, v ...interface{}) ErrorWithStatus {
return &errorWithStatus{
err: fmt.Errorf(str, v...),
status: status,
skipMessage: false,
}
}
func NewErrorf(str string, v ...interface{}) ErrorWithStatus {
return NewErrorfStatus(-1, str, v...)
}
func (e *errorWithStatus) Error() string {
var s string
for _, fr := range e.frames {
s += fmt.Sprintf("\n%v", fr)
}
return e.err.Error() + s
}
func (e *errorWithStatus) ExitStatus() int {
return e.status
}
func (e *errorWithStatus) IsSkipPrintMessage() bool {
return e.skipMessage
}
func (e *errorWithStatus) SetError(err error) ErrorWithStatus {
e.err = err
return e
}
func (e *errorWithStatus) SkipMessage() ErrorWithStatus {
e.skipMessage = true
return e
}
func (e *errorWithStatus) SetPrintMessage() ErrorWithStatus {
e.skipMessage = false
return e
}
func (e *errorWithStatus) SetExitStatus(status int) ErrorWithStatus {
e.status = status
return e
}

102
errors_test.go Normal file
View File

@ -0,0 +1,102 @@
package errors
import (
"errors"
"reflect"
"testing"
)
func TestManual(t *testing.T) {
t.Logf("default: %v\n", NewError())
}
func TestNeedExit(t *testing.T) {
type args struct {
err error
}
simpleCaseErr := NewError()
CaseNoExitErr := NewError().SetExitStatus(0)
tests := []struct {
name string
args args
want ErrorWithStatus
want1 bool
}{
{
name: "simple",
args: args{
err: simpleCaseErr,
},
want: simpleCaseErr,
want1: true,
},
{
name: "nil input",
args: args{
err: nil,
},
want: nil,
want1: false,
},
{
name: "not ErrorWithStatus",
args: args{
err: errors.New("test"),
},
want: nil,
want1: false,
},
{
name: "error but no exit",
args: args{
err: CaseNoExitErr,
},
want: CaseNoExitErr,
want1: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := NeedExit(tt.args.err)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("NeedExit() got = %v, want %v", got, tt.want)
}
if got1 != tt.want1 {
t.Errorf("NeedExit() got1 = %v, want %v", got1, tt.want1)
}
})
}
}
func TestNewErrorWithFrames(t *testing.T) {
type args struct {
err error
}
simplecase := errors.New("test")
tests := []struct {
name string
args args
want ErrorWithStatus
}{
// TODO: Add test cases.
{
name: "simple",
args: args{
err: simplecase,
},
want: NewErrorWithFrames(simplecase),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewErrorWithFrames(tt.args.err); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewErrorWithFrames() = %v, want %v", got, tt.want)
} else {
t.Log("check", got)
}
})
}
}

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module gitea.suyono.dev/go/errors
go 1.16