diff --git a/README.md b/README.md index bab6f25..8569ca3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![goreportcard](https://goreportcard.com/badge/go-simpler.org/errorsx)](https://goreportcard.com/report/go-simpler.org/errorsx) [![codecov](https://codecov.io/gh/go-simpler/errorsx/branch/main/graph/badge.svg)](https://codecov.io/gh/go-simpler/errorsx) -Extensions for the standard `errors` package +Extensions for the standard `errors` package. ## 📦 Install @@ -21,7 +21,7 @@ A multi-target version of `errors.Is`. ```go if errorsx.IsAny(err, os.ErrNotExist, os.ErrPermission) { - // handle error + fmt.Println(err) } ``` @@ -32,7 +32,7 @@ It is equivalent to `errors.As` without the need to declare the target variable. ```go if errorsx.HasType[*os.PathError](err) { - // handle error + fmt.Println(err) } ``` @@ -43,18 +43,7 @@ If the given error was created differently, `Split` returns nil. ```go if errs := errorsx.Split(err); errs != nil { - // handle errors -} -``` - -### IsTimeout - -Reports whether the error was caused by timeout. -Unlike `os.IsTimeout`, it respects error wrapping. - -```go -if errorsx.IsTimeout(err) { - // handle timeout + fmt.Println(errs) } ``` @@ -63,9 +52,13 @@ if errorsx.IsTimeout(err) { Attempts to close the given `io.Closer` and assigns the returned error (if any) to `err`. ```go -f, err := os.Open("file.txt") -if err != nil { - return err -} -defer errorsx.Close(f, &err) +func() (err error) { + f, err := os.Open("file.txt") + if err != nil { + return err + } + defer errorsx.Close(f, &err) + + return nil +}() ``` diff --git a/errorsx.go b/errorsx.go index d89f8ce..276d83b 100644 --- a/errorsx.go +++ b/errorsx.go @@ -1,4 +1,4 @@ -// Package errorsx provides extensions for the standard [errors] package. +// Package errorsx implements extensions for the standard [errors] package. package errorsx import ( @@ -36,20 +36,9 @@ func Split(err error) []error { return u.Unwrap() } -// IsTimeout reports whether the error was caused by timeout. -// Unlike [os.IsTimeout], it respects error wrapping. -func IsTimeout(err error) bool { - var t interface { - Timeout() bool - } - return errors.As(err, &t) && t.Timeout() -} - // Close attempts to close the given [io.Closer] and assigns the returned error (if any) to err. // If err is already not nil, it will be joined with the [io.Closer]'s error. -// -// NOTE: Close is designed to be used ONLY as a defer statement. -func Close(c io.Closer, err *error) { //nolint:gocritic // ptrToRefParam: false-positive +func Close(c io.Closer, err *error) { //nolint:gocritic // ptrToRefParam: err must be a pointer here. if cerr := c.Close(); cerr != nil { *err = errors.Join(*err, cerr) } diff --git a/errorsx_test.go b/errorsx_test.go index 4ca364d..af000c8 100644 --- a/errorsx_test.go +++ b/errorsx_test.go @@ -3,7 +3,6 @@ package errorsx_test import ( "errors" "fmt" - "os" "slices" "testing" @@ -41,7 +40,7 @@ func TestHasType(t *testing.T) { test("no match", errorsx.HasType[barError], errFoo, false) test("match (exact)", errorsx.HasType[fooError], errFoo, true) test("match (wrapped)", errorsx.HasType[fooError], wrap(errFoo), true) - test("match (interface)", errorsx.HasType[interface{ Timeout() bool }], errTimeout, true) + test("match (interface)", errorsx.HasType[interface{ Error() string }], errFoo, true) } func TestSplit(t *testing.T) { @@ -61,23 +60,6 @@ func TestSplit(t *testing.T) { test("joined errors (fmt.Errorf)", fmt.Errorf("%w; %w", errFoo, errBar), []error{errFoo, errBar}) } -func TestIsTimeout(t *testing.T) { - test := func(name string, fn func(error) bool, err error, want bool) { - t.Helper() - t.Run(name, func(t *testing.T) { - t.Helper() - if got := fn(err); got != want { - t.Errorf("got %t; want %t", got, want) - } - }) - } - - test("os.IsTimeout", os.IsTimeout, errTimeout, true) - test("os.IsTimeout (wrapped)", os.IsTimeout, wrap(errTimeout), false) - test("errorsx.IsTimeout", errorsx.IsTimeout, errTimeout, true) - test("errorsx.IsTimeout (wrapped)", errorsx.IsTimeout, wrap(errTimeout), true) -} - func TestClose(t *testing.T) { test := func(name string, mainErr, closeErr error, wantErrs []error) { t.Helper() @@ -103,9 +85,8 @@ func TestClose(t *testing.T) { } var ( - errFoo fooError - errBar barError - errTimeout timeoutError + errFoo fooError + errBar barError ) type fooError struct{} @@ -116,12 +97,7 @@ type barError struct{} func (barError) Error() string { return "bar" } -type timeoutError struct{} - -func (timeoutError) Error() string { return "timeout" } -func (timeoutError) Timeout() bool { return true } - -func wrap(err error) error { return fmt.Errorf("wrapped: %w", err) } +func wrap(err error) error { return fmt.Errorf("%w", err) } type errCloser struct{ err error } diff --git a/example_test.go b/example_test.go index aae0f44..c2b7889 100644 --- a/example_test.go +++ b/example_test.go @@ -1,6 +1,7 @@ package errorsx_test import ( + "fmt" "os" "go-simpler.org/errorsx" @@ -10,30 +11,25 @@ var err error func ExampleIsAny() { if errorsx.IsAny(err, os.ErrNotExist, os.ErrPermission) { - // handle error + fmt.Println(err) } } func ExampleHasType() { if errorsx.HasType[*os.PathError](err) { - // handle error + fmt.Println(err) } } func ExampleSplit() { if errs := errorsx.Split(err); errs != nil { - // handle errors - } -} - -func ExampleIsTimeout() { - if errorsx.IsTimeout(err) { - // handle timeout + fmt.Println(errs) } } +//nolint:errcheck // this is just an example. func ExampleClose() { - _ = func() (err error) { + func() (err error) { f, err := os.Open("file.txt") if err != nil { return err