Skip to content

Commit

Permalink
Add errors handling functions
Browse files Browse the repository at this point in the history
  • Loading branch information
tiendc committed Oct 25, 2024
1 parent a96da81 commit b571f04
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 1 deletion.
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@ go get github.com/tiendc/gofn
- [RandChoice](#randchoice)
- [RandChoiceMaker](#randchoicemaker)

**Error handling**
- [ErrWrap / ErrWrapL](#errwrap--errwrapl)
- [ErrUnwrap](#errunwrap)
- [ErrUnwrapToRoot](#errunwraptoroot)

**Utility**
- [FirstNonEmpty](#firstnonempty)
- [Coalesce](#coalesce)
Expand Down Expand Up @@ -1249,6 +1254,50 @@ for {
}
```

### Error handling
---

#### ErrWrap / ErrWrapL

Convenient functions to wrap a single error with a single message.

```go
// shortcut call of fmt.Errorf("%w: %s")
e := ErrWrap(err, "failed to do something")

// shortcut call of fmt.Errorf("%s: %w")
e := ErrWrapL("failed to do something", err)
```

#### ErrUnWrap

Unwraps an error into a slice of errors. This function can unwrap an error created by `errors.Join()` and
`fmt.Errorf(<one or multiple errors passed here>)`.

```go
e1 := errors.New("e1")
e2 := errors.New("e2")
e3 := errors.Join(e1, e2)
e4 := fmt.Errorf("%w, %w", e1, e2)

errs := ErrUnwrap(e1) // errs == []error{e1}
errs := ErrUnwrap(e3) // errs == []error{e1,e2}
errs := ErrUnwrap(e4) // errs == []error{e1,e2}
```

#### ErrUnwrapToRoot

Unwraps an error until the deepest one.

```go
e1 := errors.New("e1")
e2 := fmt.Errorf("e2: %w", e1)
e3 := fmt.Errorf("e3: %w", e2)

e := ErrUnwrapToRoot(e3) // e == e1
e := ErrUnwrapToRoot(e2) // e == e1
```

### Time
---

Expand Down
44 changes: 43 additions & 1 deletion errors.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package gofn

import "errors"
import (
"errors"
"fmt"
)

var (
ErrEmpty = errors.New("container is empty")
Expand All @@ -13,3 +16,42 @@ var (
// Deprecated: use ErrEmpty instead
ErrSliceEmpty = ErrEmpty
)

// ErrWrap wraps an error with a message placed in the right
func ErrWrap(err error, msg string) error {
return fmt.Errorf("%w: %s", err, msg)
}

// ErrWrapL wraps an error with a message placed in the left
func ErrWrapL(msg string, err error) error {
return fmt.Errorf("%s: %w", msg, err)
}

// ErrUnwrap unwraps an error to get a slice.
// This function can unwrap error created by errors.Join() and fmt.Errorf(<multiple errors passed>).
// In case there's only single item wrapped in the input, the slice has only 1 item.
func ErrUnwrap(err error) []error {
if err == nil {
return nil
}
u1, ok := err.(interface{ Unwrap() []error })
if ok {
return u1.Unwrap()
}
if we := errors.Unwrap(err); we != nil {
return []error{we}
}
return nil
}

// ErrUnwrapToRoot unwraps an error until the deepest one
func ErrUnwrapToRoot(err error) error {
rootErr := err
for {
e := errors.Unwrap(rootErr)
if e == nil {
return rootErr
}
rootErr = e
}
}
30 changes: 30 additions & 0 deletions errors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package gofn

import (
"errors"
"fmt"
"testing"

"github.com/stretchr/testify/assert"
)

func Test_ErrUnwrap(t *testing.T) {
e1 := errors.New("e1")
e2 := fmt.Errorf("e2: %w", e1)
e3 := fmt.Errorf("e3: %w - %w", e1, e2) // NOTE: errors.Join() is unavailable in Go prior to 1.20

Check failure on line 14 in errors_test.go

View workflow job for this annotation

GitHub Actions / build (1.18.x)

fmt.Errorf call has more than one error-wrapping directive %w

Check failure on line 14 in errors_test.go

View workflow job for this annotation

GitHub Actions / build (1.18.x)

fmt.Errorf call has more than one error-wrapping directive %w

assert.Equal(t, []error(nil), ErrUnwrap(nil))
assert.Equal(t, []error(nil), ErrUnwrap(e1))
assert.Equal(t, []error{e1}, ErrUnwrap(e2))
assert.Equal(t, []error{e1, e2}, ErrUnwrap(e3))
}

func Test_ErrUnwrapToRoot(t *testing.T) {
e1 := errors.New("e1")
e2 := fmt.Errorf("e2: %w", e1)
e3 := fmt.Errorf("e3: %w", e2)

assert.Equal(t, nil, ErrUnwrapToRoot(nil))
assert.Equal(t, e1, ErrUnwrapToRoot(e2))
assert.Equal(t, e1, ErrUnwrapToRoot(e3))
}

0 comments on commit b571f04

Please sign in to comment.