337 lines
5.7 KiB
Go
337 lines
5.7 KiB
Go
package try
|
|
|
|
/*
|
|
try is a fork of lainio's err2 package
|
|
Copyright (c) 2019 Lainio, MIT License
|
|
https://github.com/lainio/err2
|
|
*/
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func throw() (string, error) {
|
|
return "", fmt.Errorf("this is an ERROR")
|
|
}
|
|
|
|
func twoStrNoThrow() (string, string, error) { return "test", "test", nil }
|
|
|
|
func noThrow() (string, error) { return "test", nil }
|
|
|
|
func wrongSignature() (int, int) { return 0, 0 }
|
|
|
|
func recursion(a int) int {
|
|
if a == 0 {
|
|
return 0
|
|
}
|
|
s, err := noThrow()
|
|
Check(err)
|
|
_ = s
|
|
return a + recursion(a-1)
|
|
}
|
|
|
|
func recursionWithErrorCheck(a int) (int, error) {
|
|
if a == 0 {
|
|
return 0, nil
|
|
}
|
|
s, err := noThrow()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
_ = s
|
|
v, err := recursionWithErrorCheck(a - 1)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return a + v, nil
|
|
}
|
|
|
|
func noErr() error {
|
|
return nil
|
|
}
|
|
|
|
func TestAny_noError(t *testing.T) {
|
|
d := Any(noThrow())
|
|
if d[0].(string) != "test" {
|
|
t.Fail()
|
|
}
|
|
|
|
d = Any(twoStrNoThrow())
|
|
if d[0].(string) != "test" || d[1].(string) != "test" {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestDefault_Error(t *testing.T) {
|
|
var err Err
|
|
defer Return(&err)
|
|
|
|
Any(throw())
|
|
|
|
t.Fail() // If everything works we are never here
|
|
}
|
|
|
|
func TestAny_Error(t *testing.T) {
|
|
var err Err
|
|
defer Handle(&err, func() {})
|
|
|
|
Any(throw())
|
|
|
|
t.Fail() // If everything works we are never here
|
|
}
|
|
|
|
func panickingHandle() {
|
|
var err Err
|
|
defer Handle(&err, func() {})
|
|
|
|
Any(wrongSignature())
|
|
}
|
|
|
|
func TestPanickingCarryOn_Handle(t *testing.T) {
|
|
defer func() {
|
|
if recover() == nil {
|
|
t.Error("panics should went thru when not our errors")
|
|
}
|
|
}()
|
|
panickingHandle()
|
|
}
|
|
|
|
func panickingCatchAll() {
|
|
defer CatchAll(func(err Err) {}, func(v interface{}) {})
|
|
|
|
Any(wrongSignature())
|
|
}
|
|
|
|
func TestPanickingCatchAll(t *testing.T) {
|
|
defer func() {
|
|
if recover() != nil {
|
|
t.Error("panics should not fly thru")
|
|
}
|
|
}()
|
|
panickingCatchAll()
|
|
}
|
|
|
|
func panickingReturn() {
|
|
var err Err
|
|
defer Return(&err)
|
|
|
|
Any(wrongSignature())
|
|
}
|
|
|
|
func TestPanicking_Return(t *testing.T) {
|
|
defer func() {
|
|
if recover() == nil {
|
|
t.Error("panics should carry on")
|
|
}
|
|
}()
|
|
panickingReturn()
|
|
}
|
|
|
|
func panickingCatch() {
|
|
defer Catch(func(err Err) {})
|
|
|
|
Any(wrongSignature())
|
|
}
|
|
|
|
func TestPanicking_Catch(t *testing.T) {
|
|
defer func() {
|
|
if recover() == nil {
|
|
t.Error("panics should carry on")
|
|
}
|
|
}()
|
|
panickingCatch()
|
|
}
|
|
|
|
func TestCatch_Error(t *testing.T) {
|
|
defer Catch(func(err Err) {
|
|
// fmt.Printf("error and defer handling:%s\n", err)
|
|
})
|
|
|
|
Any(throw())
|
|
|
|
t.Fail() // If everything works we are never here
|
|
}
|
|
|
|
func TestNewTryErr(t *testing.T) {
|
|
tryErr := NewErr("I f*cked up")
|
|
callStack := tryErr.CallStackString()
|
|
|
|
if !strings.HasPrefix(callStack, "ERROR: I f*cked up\n") {
|
|
fmt.Println("Call stack does not have prefix.\n" + callStack)
|
|
t.Fail()
|
|
}
|
|
|
|
if strings.Count(callStack, "\n") != 9 {
|
|
fmt.Println("Call stack is not 9 lines long.\n" +
|
|
fmt.Sprint(strings.Count(callStack, "\n")))
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestGetData(t *testing.T) {
|
|
tryErr := NewErr("I f*cked up")
|
|
tryErr.Annotate("test1")
|
|
tryErr.Annotate("test2")
|
|
data := tryErr.GetData()
|
|
|
|
if data.Msg != "I f*cked up" {
|
|
fmt.Println("wrong msg")
|
|
t.Fail()
|
|
}
|
|
|
|
if data.Annotations[0] != "test1" {
|
|
fmt.Println("wrong annotation#0")
|
|
t.Fail()
|
|
}
|
|
if data.Annotations[1] != "test2" {
|
|
fmt.Println("wrong annotation#1")
|
|
t.Fail()
|
|
}
|
|
|
|
if len(data.CallStack) != 3 {
|
|
fmt.Println("call stack length != 3, " + fmt.Sprint(len(data.CallStack)))
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestErrCompare(t *testing.T) {
|
|
err := errors.New("TestError")
|
|
tryErr := FromErr(err)
|
|
|
|
if !errors.Is(tryErr, err) {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestReturnStd(t *testing.T) {
|
|
tf := func() (err error) {
|
|
defer ReturnStd(&err)
|
|
String(throw())
|
|
return
|
|
}
|
|
|
|
err := tf()
|
|
|
|
if err.Error() != "this is an ERROR" {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestCheckTryErr(t *testing.T) {
|
|
testErr := NewErr("TestErr")
|
|
|
|
tf := func() (err Err) {
|
|
defer Return(&err)
|
|
Check(testErr)
|
|
return
|
|
}
|
|
|
|
err := tf()
|
|
|
|
if err != testErr {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func ExampleReturn() {
|
|
var err Err
|
|
defer Return(&err)
|
|
Any(noThrow())
|
|
// Output:
|
|
}
|
|
|
|
func ExampleAnnotate() {
|
|
annotated := func() (err Err) {
|
|
defer Annotate(&err, "annotated")
|
|
Any(throw())
|
|
return err
|
|
}
|
|
err := annotated()
|
|
fmt.Printf("%v", err)
|
|
// Output: annotated: this is an ERROR
|
|
}
|
|
|
|
func ExampleAnnotate_deferStack() {
|
|
annotated := func() (err Err) {
|
|
defer Annotate(&err, "annotated 2nd")
|
|
defer Annotate(&err, "annotated 1st")
|
|
Any(throw())
|
|
return err
|
|
}
|
|
err := annotated()
|
|
fmt.Printf("%v", err)
|
|
// Output: annotated 1st: annotated 2nd: this is an ERROR
|
|
}
|
|
|
|
func ExampleHandle() {
|
|
doSomething := func(a, b int) (err Err) {
|
|
defer Handle(&err, func() {
|
|
err.Annotate(fmt.Sprintf("error with (%d, %d)", a, b))
|
|
})
|
|
Any(throw())
|
|
return err
|
|
}
|
|
err := doSomething(1, 2)
|
|
fmt.Printf("%v", err)
|
|
// Output: error with (1, 2): this is an ERROR
|
|
}
|
|
|
|
func BenchmarkOldErrorCheckingWithIfClause(b *testing.B) {
|
|
for n := 0; n < b.N; n++ {
|
|
_, err := noThrow()
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkAny(b *testing.B) {
|
|
for n := 0; n < b.N; n++ {
|
|
Any(noThrow())
|
|
}
|
|
}
|
|
|
|
func BenchmarkAny_ErrVar(b *testing.B) {
|
|
for n := 0; n < b.N; n++ {
|
|
_, err := noThrow()
|
|
Any(err)
|
|
}
|
|
}
|
|
|
|
func BenchmarkCheckInsideCall(b *testing.B) {
|
|
for n := 0; n < b.N; n++ {
|
|
Check(noErr())
|
|
}
|
|
}
|
|
|
|
func BenchmarkCheckVarCall(b *testing.B) {
|
|
for n := 0; n < b.N; n++ {
|
|
err := noErr()
|
|
Check(err)
|
|
}
|
|
}
|
|
|
|
func BenchmarkCheck_ErrVar(b *testing.B) {
|
|
for n := 0; n < b.N; n++ {
|
|
_, err := noThrow()
|
|
Check(err)
|
|
}
|
|
}
|
|
|
|
func BenchmarkRecursionNoCheck_NotRelated(b *testing.B) {
|
|
for n := 0; n < b.N; n++ {
|
|
_ = recursion(100)
|
|
}
|
|
}
|
|
|
|
func BenchmarkRecursionWithErrorCheck_NotRelated(b *testing.B) {
|
|
for n := 0; n < b.N; n++ {
|
|
_, err := recursionWithErrorCheck(100)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
}
|