diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index f93ba87..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1,22 +0,0 @@
-# Set the default behavior, in case people don't have core.autocrlf set.
-* text=auto
-
-# convert to lf on checkout.
-*.go text eol=lf
-*.mod text eol=lf
-*.sum text eol=lf
-*.md text eol=lf
-*.svg text eol=lf
-*.http text eol=lf
-*.ini text eol=lf
-*.conf text eol=lf
-*.sh text eol=lf
-*.yaml text eol=lf
-*.proto text eol=lf
-*.json text eol=lf
-Dockerfile text eol=lf
-
-# Denote all files that are truly binary and should not be modified.
-*.png binary
-*.jpg binary
-*.jpeg binary
\ No newline at end of file
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 5ea9152..9c7943f 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -9,8 +9,14 @@ jobs:
test-project:
runs-on: ubuntu-20.04
steps:
+ - name: Setup
+ uses: actions/setup-go@v4
+ with:
+ go-version: "1.21"
+ - run: go version
+
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Test
- run: make test
\ No newline at end of file
+ run: make test
diff --git a/HISTORY.md b/HISTORY.md
index f7464e3..7dc09f2 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,5 +1,11 @@
## ✒ 历史版本的特性介绍 (Features in old versions)
+### v0.6.0-alpha
+
+> 此版本发布于 2024-08-09
+
+* 重构,调整使用姿势
+
### v0.5.2
> 此版本发布于 2023-07-27
diff --git a/LICENSE b/LICENSE
index e4875a0..0b0d54b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2022 FishGoddess
+Copyright (c) 2024 FishGoddess
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the "Software"),
diff --git a/Makefile b/Makefile
index e028a99..f4f3057 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,9 @@
-.PHONY: test fmt
+.PHONY: fmt test
-all: test fmt
-
-test:
- go test -cover ./...
+all: fmt test
fmt:
- go fmt ./...
\ No newline at end of file
+ go fmt ./...
+
+test:
+ go test -cover -count=1 -test.cpu=1 ./...
\ No newline at end of file
diff --git a/README.en.md b/README.en.md
index e4d841d..00cadbc 100644
--- a/README.en.md
+++ b/README.en.md
@@ -2,7 +2,7 @@
[](https://pkg.go.dev/github.com/FishGoddess/errors)
[](https://opensource.org/licenses/MIT)
-[](_icons/coverage.svg)
+[](_icons/coverage.svg)

**Errors** is a lib for handling error gracefully in Go.
@@ -25,50 +25,27 @@ import (
"github.com/FishGoddess/errors"
)
-const (
- codeTestError = 10000 // Your error's code
-)
+func main() {
+ // Use wrap function to create an *Error error which has code and message.
+ err := errors.Wrap(1000, "need login")
+ fmt.Println(err)
-// TestError returns a test error.
-func TestError(err error) error {
- return errors.Wrap(err, codeTestError)
-}
+ // You can get code and message of err anytime.
+ fmt.Println(err.Code(), err.Message())
-// IsTestError if err is test error.
-func IsTestError(err error) bool {
- return errors.Is(err, codeTestError)
-}
+ // Try these ways to get code and message!
+ // You will get default code or message if err doesn't have a code or message.
+ fmt.Println(errors.Code(err, 6699), errors.Message(err, "default message"))
+ fmt.Println(errors.Code(io.EOF, 6699), errors.Message(io.EOF, "default message"))
-func main() {
- // We provide three graceful ways to handle error in Go: Wrap() and Unwrap() and Is().
- // Wrap wraps error with a code and Unwrap returns one error with this code.
- // Is returns one error is with the same code or not.
- // As you can see, we define two functions above, and this is the basic way to use this lib.
- err := TestError(errors.New("something wrong"))
- if IsTestError(err) {
- fmt.Println("I got a test error")
- }
-
- // Also, we provide some basic errors for you:
- err = errors.BadRequest(nil) // Classic enough! Ah :)
- err = errors.Forbidden(nil) // Classic enough! Ah :)
- err = errors.NotFound(nil) // Classic enough! Ah :)
- err = errors.RequestTimeout(nil) // Classic enough! Ah :)
- err = errors.InternalServerError(nil) // Classic enough! Ah :)
- err = errors.DBError(nil)
- err = errors.PageTokenInvalid(nil)
-
- // Use WithMsg to carry a message.
- err = errors.Wrap(io.EOF, codeTestError, errors.WithMsg("test"))
- fmt.Println(err.Error())
- fmt.Println(errors.Msg(err))
- fmt.Println(errors.MsgOrDefault(io.EOF, "default error message"))
+ // Also, we provide some useful information carrier for you.
+ err = errors.Wrap(9999, "io timeout").With(io.EOF).WithCaller()
+ fmt.Println(err)
}
```
* [basic](_examples/basic.go)
-* [status](_examples/status.go)
### 👥 Contributing
diff --git a/README.md b/README.md
index 7b43a1a..ec2122e 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
[](https://pkg.go.dev/github.com/FishGoddess/errors)
[](https://opensource.org/licenses/MIT)
-[](_icons/coverage.svg)
+[](_icons/coverage.svg)

**Errors** 是一个用于优雅地处理 Go 中错误的库。
@@ -25,50 +25,27 @@ import (
"github.com/FishGoddess/errors"
)
-const (
- codeTestError = 10000 // Your error's code
-)
+func main() {
+ // Use wrap function to create an *Error error which has code and message.
+ err := errors.Wrap(1000, "need login")
+ fmt.Println(err)
-// TestError returns a test error.
-func TestError(err error) error {
- return errors.Wrap(err, codeTestError)
-}
+ // You can get code and message of err anytime.
+ fmt.Println(err.Code(), err.Message())
-// IsTestError if err is test error.
-func IsTestError(err error) bool {
- return errors.Is(err, codeTestError)
-}
+ // Try these ways to get code and message!
+ // You will get default code or message if err doesn't have a code or message.
+ fmt.Println(errors.Code(err, 6699), errors.Message(err, "default message"))
+ fmt.Println(errors.Code(io.EOF, 6699), errors.Message(io.EOF, "default message"))
-func main() {
- // We provide three graceful ways to handle error in Go: Wrap() and Unwrap() and Is().
- // Wrap wraps error with a code and Unwrap returns one error with this code.
- // Is returns one error is with the same code or not.
- // As you can see, we define two functions above, and this is the basic way to use this lib.
- err := TestError(errors.New("something wrong"))
- if IsTestError(err) {
- fmt.Println("I got a test error")
- }
-
- // Also, we provide some basic errors for you:
- err = errors.BadRequest(nil) // Classic enough! Ah :)
- err = errors.Forbidden(nil) // Classic enough! Ah :)
- err = errors.NotFound(nil) // Classic enough! Ah :)
- err = errors.RequestTimeout(nil) // Classic enough! Ah :)
- err = errors.InternalServerError(nil) // Classic enough! Ah :)
- err = errors.DBError(nil)
- err = errors.PageTokenInvalid(nil)
-
- // Use WithMsg to carry a message.
- err = errors.Wrap(io.EOF, codeTestError, errors.WithMsg("test"))
- fmt.Println(err.Error())
- fmt.Println(errors.Msg(err))
- fmt.Println(errors.MsgOrDefault(io.EOF, "default error message"))
+ // Also, we provide some useful information carrier for you.
+ err = errors.Wrap(9999, "io timeout").With(io.EOF).WithCaller()
+ fmt.Println(err)
}
```
* [basic](_examples/basic.go)
-* [status](_examples/status.go)
### 👥 贡献者
diff --git a/_examples/basic.go b/_examples/basic.go
index 7014bf7..c4f0f78 100644
--- a/_examples/basic.go
+++ b/_examples/basic.go
@@ -1,4 +1,4 @@
-// Copyright 2022 FishGoddess. All rights reserved.
+// Copyright 2024 FishGoddess. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
@@ -11,42 +11,20 @@ import (
"github.com/FishGoddess/errors"
)
-const (
- codeTestError = 10000 // Your error's code
-)
-
-// TestError returns a test error.
-func TestError(err error) error {
- return errors.Wrap(err, codeTestError)
-}
-
-// IsTestError if err is test error.
-func IsTestError(err error) bool {
- return errors.Is(err, codeTestError)
-}
-
func main() {
- // We provide three graceful ways to handle error in Go: Wrap() and Unwrap() and Is().
- // Wrap wraps error with a code and Unwrap returns one error with this code.
- // Is returns one error is with the same code or not.
- // As you can see, we define two functions above, and this is the basic way to use this lib.
- err := TestError(errors.New("something wrong"))
- if IsTestError(err) {
- fmt.Println("I got a test error")
- }
+ // Use wrap function to create an *Error error which has code and message.
+ err := errors.Wrap(1000, "need login")
+ fmt.Println(err)
+
+ // You can get code and message of err anytime.
+ fmt.Println(err.Code(), err.Message())
- // Also, we provide some basic errors for you:
- err = errors.BadRequest(nil) // Classic enough! Ah :)
- err = errors.Forbidden(nil) // Classic enough! Ah :)
- err = errors.NotFound(nil) // Classic enough! Ah :)
- err = errors.RequestTimeout(nil) // Classic enough! Ah :)
- err = errors.InternalServerError(nil) // Classic enough! Ah :)
- err = errors.DBError(nil)
- err = errors.PageTokenInvalid(nil)
+ // Try these ways to get code and message!
+ // You will get default code or message if err doesn't have a code or message.
+ fmt.Println(errors.Code(err, 6699), errors.Message(err, "default message"))
+ fmt.Println(errors.Code(io.EOF, 6699), errors.Message(io.EOF, "default message"))
- // Use WithMsg to carry a message.
- err = errors.Wrap(io.EOF, codeTestError, errors.WithMsg("test"))
- fmt.Println(err.Error())
- fmt.Println(errors.Msg(err))
- fmt.Println(errors.MsgOrDefault(io.EOF, "default error message"))
+ // Also, we provide some useful information carrier for you.
+ err = errors.Wrap(9999, "io timeout").With(io.EOF).WithCaller()
+ fmt.Println(err)
}
diff --git a/_examples/status.go b/_examples/status.go
deleted file mode 100644
index 1bb482c..0000000
--- a/_examples/status.go
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2023 FishGoddess. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "fmt"
- "io"
-
- "github.com/FishGoddess/errors"
- "github.com/FishGoddess/errors/status"
-)
-
-var (
- errAuthFailed = errors.New("auth failed")
-)
-
-func isAuthFailed(err error) bool {
- return err == errAuthFailed
-}
-
-func main() {
- // We provide a way to transfer errors to status.
- // A status can be used by a server like grpc server with google.status.
- // For example, we have an auth failed error which will be returned by service.
- // However, we usually return a status code represents it in server,
- // and we usually return a human-being readable msg instead of the error msg.
- // So it has a gap between service error and server status.
- // You can register a status with server code and msg, then use Parse to restore them.
- authFailedStatus := status.New(1000, "you should check auth", isAuthFailed)
- status.RegisterStatus(authFailedStatus)
-
- // Get code and msg from error.
- code, msg := status.Parse(errAuthFailed)
- fmt.Println(code, msg)
-
- // Of course, you can use errors.Wrap to get an error with msg.
- // Then register a status about it.
- errCode := int32(123456)
- err := errors.Wrap(io.EOF, errCode, errors.WithMsg("hello"))
-
- isError := func(err error) bool {
- return errors.Is(err, errCode)
- }
-
- // As you can see, the error code and status code don't need to be the same.
- statusCode := int32(654321)
- status.RegisterStatus(status.New(statusCode, "i am status", isError))
-
- // The msg will be the one set to error using WithMsg.
- // The registered msg would be used only if the error doesn't have a set msg.
- // Try to remove errors.WithMsg("hello") above and run again.
- code, msg = status.Parse(err)
- fmt.Println(code, msg)
-
- // Also, you can register many statuses at one time by RegisterStatuses.
- status.RegisterStatuses(
- status.New(123, "abc", nil),
- status.New(666, "xxx", nil),
- )
-}
diff --git a/_icons/coverage.svg b/_icons/coverage.svg
index 417699f..64d796b 100644
--- a/_icons/coverage.svg
+++ b/_icons/coverage.svg
@@ -10,7 +10,7 @@
coverage
coverage
- 85%
- 85%
+ 79%
+ 79%
\ No newline at end of file
diff --git a/errors.go b/errors.go
index 8a8bd4c..8b35dad 100644
--- a/errors.go
+++ b/errors.go
@@ -1,4 +1,4 @@
-// Copyright 2023 FishGoddess. All rights reserved.
+// Copyright 2024 FishGoddess. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
@@ -6,15 +6,28 @@ package errors
import (
"errors"
- "fmt"
)
-// New returns a string error.
func New(text string) error {
return errors.New(text)
}
-// Newf returns a string error formatted with params.
-func Newf(text string, params ...interface{}) error {
- return fmt.Errorf(text, params...)
+// Is is a shortcut of errors.Is.
+func Is(err, target error) bool {
+ return errors.Is(err, target)
+}
+
+// As is a shortcut of errors.As.
+func As(err error, target any) bool {
+ return errors.As(err, target)
+}
+
+// Unwrap is a shortcut of errors.Unwrap.
+func Unwrap(err error) error {
+ return errors.Unwrap(err)
+}
+
+// Join is a shortcut of errors.Join.
+func Join(errs ...error) error {
+ return errors.Join(errs...)
}
diff --git a/errors_test.go b/errors_test.go
index 7123ee4..ec64686 100644
--- a/errors_test.go
+++ b/errors_test.go
@@ -1,25 +1,164 @@
-// Copyright 2023 FishGoddess. All rights reserved.
+// Copyright 2024 FishGoddess. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package errors
import (
+ "errors"
+ "io"
+ "os"
"testing"
)
-// go test -v -cover -run=^TestNew$
-func TestNew(t *testing.T) {
- err := New("test")
- if err.Error() != "test" {
- t.Errorf("err.Error() %s != 'test'", err.Error())
+type testError struct {
+ reason string
+}
+
+func (te *testError) Code() int32 {
+ return 500
+}
+
+func (te *testError) Error() string {
+ return te.reason
+}
+
+// go test -v -cover -count=1 -test.cpu=1 -run=^TestIs$
+func TestIs(t *testing.T) {
+ testErr := &testError{reason: "test error"}
+ wrapErr := Wrap(-1000, "wrap test error").With(testErr)
+
+ testCases := []struct {
+ err error
+ cause error
+ }{
+ {
+ err: io.EOF,
+ cause: io.EOF,
+ },
+ {
+ err: Wrap(1000, "wow").With(testErr),
+ cause: testErr,
+ },
+ {
+ err: Wrap(1000, "wow too").With(wrapErr),
+ cause: testErr,
+ },
+ }
+
+ for _, testCase := range testCases {
+ if ok := Is(testCase.err, testCase.cause); !ok {
+ t.Errorf("testCase.err %+v isn't testCase.cause %+v", testCase.err, testCase.cause)
+ }
}
}
-// go test -v -cover -run=^TestNewf$
-func TestNewf(t *testing.T) {
- err := Newf("test %d %.2f", 123, 3.14)
- if err.Error() != "test 123 3.14" {
- t.Errorf("err.Error() %s != 'test 123 3.14'", err.Error())
+// go test -v -cover -count=1 -test.cpu=1 -run=^TestAs$
+func TestAs(t *testing.T) {
+ testErr := &testError{reason: "test error"}
+ wrapErr := Wrap(-1000, "wrap test error").With(testErr)
+
+ targetTestErr := &testError{}
+ targetTestErr2 := &testError{}
+ targetPathErr := &os.PathError{}
+
+ testCases := []struct {
+ err error
+ target any
+ ok bool
+ want any
+ }{
+ {
+ err: Wrap(1000, "wow").With(testErr),
+ target: &targetTestErr,
+ ok: true,
+ want: &testErr,
+ },
+ {
+ err: Wrap(1000, "wow too").With(wrapErr),
+ target: &targetTestErr2,
+ ok: true,
+ want: &testErr,
+ },
+ {
+ err: Wrap(1000, "no"),
+ target: &targetPathErr,
+ ok: false,
+ want: nil,
+ },
+ }
+
+ for _, testCase := range testCases {
+ ok := As(testCase.err, testCase.target)
+ if ok != testCase.ok {
+ t.Errorf("err %+v ok %+v != err %+v testCase.ok %+v", testCase.err, testCase.target, ok, testCase.ok)
+ }
+ }
+}
+
+// go test -v -cover -count=1 -test.cpu=1 -run=^TestUnwrap$
+func TestUnwrap(t *testing.T) {
+ testErr := &testError{reason: "test error"}
+ wrapErr := Wrap(-1000, "wrap test error").With(testErr)
+
+ testCases := []struct {
+ err error
+ cause error
+ }{
+ {
+ err: testErr,
+ cause: nil,
+ },
+ {
+ err: Wrap(1000, "wow").With(testErr),
+ cause: testErr,
+ },
+ {
+ err: Wrap(1000, "wow too").With(wrapErr),
+ cause: wrapErr,
+ },
+ }
+
+ for _, testCase := range testCases {
+ if Unwrap(testCase.err) != testCase.cause {
+ t.Errorf("Unwrap(testCase.err) %+v != testCase.cause %+v", Unwrap(testCase.err), testCase.cause)
+ }
+ }
+}
+
+// go test -v -cover -count=1 -test.cpu=1 -run=^TestJoin$
+func TestJoin(t *testing.T) {
+ testCases := []struct {
+ errs []error
+ }{
+ {
+ errs: nil,
+ },
+ {
+ errs: []error{nil, nil},
+ },
+ {
+ errs: []error{io.EOF, &testError{}},
+ },
+ {
+ errs: []error{io.EOF, nil},
+ },
+ }
+
+ for _, testCase := range testCases {
+ got := Join(testCase.errs...)
+ want := errors.Join(testCase.errs...)
+
+ if got != nil && want != nil {
+ if got.Error() != want.Error() {
+ t.Errorf("got %+v != want %+v", got, want)
+ }
+
+ continue
+ }
+
+ if got != want {
+ t.Errorf("got %+v != want %+v", got, want)
+ }
}
}
diff --git a/extension.go b/extension.go
deleted file mode 100644
index fe41b24..0000000
--- a/extension.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2023 FishGoddess. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-
-package errors
-
-const (
- codeDBError = 1100
- codePageTokenInvalid = 1200
-)
-
-// DBError returns a db error.
-func DBError(err error, opts ...Option) error {
- return Wrap(err, codeDBError, opts...)
-}
-
-// IsDBError if err is db error.
-func IsDBError(err error) bool {
- return Is(err, codeDBError)
-}
-
-// UnwrapDBError if err is db error.
-func UnwrapDBError(err error) (error, bool) {
- return Unwrap(err, codeDBError)
-}
-
-// PageTokenInvalid returns a page token invalid error.
-func PageTokenInvalid(err error, opts ...Option) error {
- return Wrap(err, codePageTokenInvalid, opts...)
-}
-
-// IsPageTokenInvalid if err is page token invalid.
-func IsPageTokenInvalid(err error) bool {
- return Is(err, codePageTokenInvalid)
-}
-
-// UnwrapPageTokenInvalid if err is page token invalid.
-func UnwrapPageTokenInvalid(err error) (error, bool) {
- return Unwrap(err, codePageTokenInvalid)
-}
diff --git a/extension_test.go b/extension_test.go
deleted file mode 100644
index 5d3988e..0000000
--- a/extension_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2022 FishGoddess. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-
-package errors
-
-import (
- "errors"
- "testing"
-)
-
-// go test -v -cover -run=^TestDBError$
-func TestDBError(t *testing.T) {
- err := DBError(nil)
- if err != nil {
- t.Error("DBError is wrong", err)
- }
-
- err = DBError(errors.New("db error"))
- if !IsDBError(err) {
- t.Error("IsDBError is wrong", err)
- }
-
- if e, ok := UnwrapDBError(err); !ok || e.Error() != "db error" {
- t.Error("DBError or UnwrapDBError is wrong", err)
- }
-}
-
-// go test -v -cover -run=^TestPageTokenInvalid$
-func TestPageTokenInvalid(t *testing.T) {
- err := PageTokenInvalid(nil)
- if err != nil {
- t.Error("PageTokenInvalid is wrong", err)
- }
-
- err = PageTokenInvalid(errors.New("page token invalid"))
- if !IsPageTokenInvalid(err) {
- t.Error("IsPageTokenInvalid is wrong", err)
- }
-
- if e, ok := UnwrapPageTokenInvalid(err); !ok || e.Error() != "page token invalid" {
- t.Error("PageTokenInvalid or UnwrapPageTokenInvalid is wrong", err)
- }
-}
diff --git a/option.go b/option.go
deleted file mode 100644
index f0f0710..0000000
--- a/option.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2023 FishGoddess. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-
-package errors
-
-import "fmt"
-
-type Option func(e *Error)
-
-func (o Option) Apply(e *Error) {
- o(e)
-}
-
-func applyOptions(e *Error, opts []Option) {
- for _, opt := range opts {
- opt.Apply(e)
- }
-}
-
-// WithMsg sets msg to e.
-func WithMsg(msg string, params ...interface{}) Option {
- return func(e *Error) {
- if len(params) > 0 {
- msg = fmt.Sprintf(msg, params...)
- }
-
- e.msg = msg
- }
-}
diff --git a/option_test.go b/option_test.go
deleted file mode 100644
index c2e2966..0000000
--- a/option_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2023 FishGoddess. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-
-package errors
-
-import (
- "net/http"
- "testing"
-)
-
-// go test -v -cover -run=^TestOptionApply$
-func TestOptionApply(t *testing.T) {
- opt := Option(func(e *Error) {
- e.code = http.StatusOK
- })
-
- got := &Error{code: 0}
- expect := &Error{code: http.StatusOK}
-
- opt.Apply(got)
- if got.String() != expect.String() {
- t.Errorf("got %s != expect %s", got.String(), expect.String())
- }
-}
-
-// go test -v -cover -run=^TestWithMsg$
-func TestWithMsg(t *testing.T) {
- got := &Error{msg: ""}
- expect := &Error{msg: "ok"}
-
- WithMsg("ok")(got)
- if got.String() != expect.String() {
- t.Errorf("got %s != expect %s", got.String(), expect.String())
- }
-
- got = &Error{msg: ""}
- expect = &Error{msg: "ok123"}
-
- WithMsg("%s%d", "ok", 123)(got)
- if got.String() != expect.String() {
- t.Errorf("got %s != expect %s", got.String(), expect.String())
- }
-}
diff --git a/x/runtime.go b/runtime.go
similarity index 89%
rename from x/runtime.go
rename to runtime.go
index 64f9be6..d2ef404 100644
--- a/x/runtime.go
+++ b/runtime.go
@@ -10,7 +10,7 @@ import (
)
func Caller() string {
- _, file, line, ok := runtime.Caller(1)
+ _, file, line, ok := runtime.Caller(2)
if !ok {
return ""
}
@@ -20,7 +20,7 @@ func Caller() string {
func Callers() []string {
var pcs [16]uintptr
- n := runtime.Callers(2, pcs[:])
+ n := runtime.Callers(3, pcs[:])
frames := runtime.CallersFrames(pcs[:n])
var callers []string
diff --git a/x/runtime_test.go b/runtime_test.go
similarity index 100%
rename from x/runtime_test.go
rename to runtime_test.go
diff --git a/standard.go b/standard.go
deleted file mode 100644
index c9b2660..0000000
--- a/standard.go
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2022 FishGoddess. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-
-package errors
-
-import (
- "net/http"
-)
-
-const (
- _ = http.StatusTeapot // :)
-)
-
-const (
- codeBadRequest = http.StatusBadRequest // Classic...
- codeForbidden = http.StatusForbidden // Classic...
- codeNotFound = http.StatusNotFound // Classic...
- codeRequestTimeout = http.StatusRequestTimeout // Classic...
- codeInternalServerError = http.StatusInternalServerError // Classic...
-)
-
-// BadRequest returns a bad request error.
-func BadRequest(err error, opts ...Option) error {
- return Wrap(err, codeBadRequest, opts...)
-}
-
-// IsBadRequest if err is bad request.
-func IsBadRequest(err error) bool {
- return Is(err, codeBadRequest)
-}
-
-// UnwrapBadRequest if err is bad request.
-func UnwrapBadRequest(err error) (error, bool) {
- return Unwrap(err, codeBadRequest)
-}
-
-// Forbidden returns a forbidden error.
-func Forbidden(err error, opts ...Option) error {
- return Wrap(err, codeForbidden, opts...)
-}
-
-// IsForbidden if err is forbidden.
-func IsForbidden(err error) bool {
- return Is(err, codeForbidden)
-}
-
-// UnwrapForbidden if err is forbidden.
-func UnwrapForbidden(err error) (error, bool) {
- return Unwrap(err, codeForbidden)
-}
-
-// NotFound returns a not found error.
-func NotFound(err error, opts ...Option) error {
- return Wrap(err, codeNotFound, opts...)
-}
-
-// IsNotFound if err is not found.
-func IsNotFound(err error) bool {
- return Is(err, codeNotFound)
-}
-
-// UnwrapNotFound if err is not found.
-func UnwrapNotFound(err error) (error, bool) {
- return Unwrap(err, codeNotFound)
-}
-
-// RequestTimeout returns a request timeout error.
-func RequestTimeout(err error, opts ...Option) error {
- return Wrap(err, codeRequestTimeout, opts...)
-}
-
-// IsRequestTimeout if err is request timeout.
-func IsRequestTimeout(err error) bool {
- return Is(err, codeRequestTimeout)
-}
-
-// UnwrapRequestTimeout if err is request timeout.
-func UnwrapRequestTimeout(err error) (error, bool) {
- return Unwrap(err, codeRequestTimeout)
-}
-
-// InternalServerError returns an internal server error.
-func InternalServerError(err error, opts ...Option) error {
- return Wrap(err, codeInternalServerError, opts...)
-}
-
-// IsInternalServerError if err is an internal server.
-func IsInternalServerError(err error) bool {
- return Is(err, codeInternalServerError)
-}
-
-// UnwrapInternalServerError if err is an internal server.
-func UnwrapInternalServerError(err error) (error, bool) {
- return Unwrap(err, codeInternalServerError)
-}
diff --git a/standard_test.go b/standard_test.go
deleted file mode 100644
index 47f47a7..0000000
--- a/standard_test.go
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2022 FishGoddess. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-
-package errors
-
-import (
- "errors"
- "testing"
-)
-
-// go test -v -cover -run=^TestBadRequest$
-func TestBadRequest(t *testing.T) {
- err := BadRequest(nil)
- if err != nil {
- t.Error("BadRequest is wrong", err)
- }
-
- err = BadRequest(errors.New("bad request"))
- if !IsBadRequest(err) {
- t.Error("IsBadRequest is wrong", err)
- }
-
- if e, ok := UnwrapBadRequest(err); !ok || e.Error() != "bad request" {
- t.Error("BadRequest or UnwrapBadRequest is wrong", err)
- }
-}
-
-// go test -v -cover -run=^TestForbidden$
-func TestForbidden(t *testing.T) {
- err := Forbidden(nil)
- if err != nil {
- t.Error("Forbidden is wrong", err)
- }
-
- err = Forbidden(errors.New("forbidden"))
- if !IsForbidden(err) {
- t.Error("IsForbidden is wrong", err)
- }
-
- if e, ok := UnwrapForbidden(err); !ok || e.Error() != "forbidden" {
- t.Error("Forbidden or UnwrapForbidden is wrong", err)
- }
-}
-
-// go test -v -cover -run=^TestNotFound$
-func TestNotFound(t *testing.T) {
- err := NotFound(nil)
- if err != nil {
- t.Error("NotFound is wrong", err)
- }
-
- err = NotFound(errors.New("not found"))
- if !IsNotFound(err) {
- t.Error("IsNotFound is wrong", err)
- }
-
- if e, ok := UnwrapNotFound(err); !ok || e.Error() != "not found" {
- t.Error("NotFound or UnwrapNotFound is wrong", err)
- }
-}
-
-// go test -v -cover -run=^TestRequestTimeout$
-func TestRequestTimeout(t *testing.T) {
- err := RequestTimeout(nil)
- if err != nil {
- t.Error("RequestTimeout is wrong", err)
- }
-
- err = RequestTimeout(errors.New("request timeout"))
- if !IsRequestTimeout(err) {
- t.Error("IsRequestTimeout is wrong", err)
- }
-
- if e, ok := UnwrapRequestTimeout(err); !ok || e.Error() != "request timeout" {
- t.Error("RequestTimeout or UnwrapRequestTimeout is wrong", err)
- }
-}
-
-// go test -v -cover -run=^TestInternalServerError$
-func TestInternalServerError(t *testing.T) {
- err := InternalServerError(nil)
- if err != nil {
- t.Error("InternalServerError is wrong", err)
- }
-
- err = InternalServerError(errors.New("internal server error"))
- if !IsInternalServerError(err) {
- t.Error("IsInternalServerError is wrong", err)
- }
-
- if e, ok := UnwrapInternalServerError(err); !ok || e.Error() != "internal server error" {
- t.Error("InternalServerError or UnwrapInternalServerError is wrong", err)
- }
-}
diff --git a/status/status.go b/status/status.go
deleted file mode 100644
index 5171600..0000000
--- a/status/status.go
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2023 FishGoddess. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-
-package status
-
-import (
- "net/http"
- "sync"
-
- "github.com/FishGoddess/errors"
-)
-
-var (
- CodeOK int32 = 0
- CodeUnknown int32 = http.StatusInternalServerError
-)
-
-var (
- // MsgUnknown is the default msg returned from Parse if err passed to Parse doesn't have a msg.
- MsgUnknown = "Server is too busy, please try again later."
-)
-
-var (
- statuses = make([]*Status, 0, 8)
- statusesLock sync.RWMutex
-)
-
-// Status wraps code and msg for returning.
-type Status struct {
- code int32
- msg string
- isError func(err error) bool
-}
-
-// New returns a new with given params.
-// isError returns if err belongs to status.
-func New(code int32, msg string, isError func(err error) bool) *Status {
- return &Status{
- code: code,
- msg: msg,
- isError: isError,
- }
-}
-
-func (s *Status) Code() int32 {
- if s == nil {
- return CodeOK
- }
-
- return s.code
-}
-
-func (s *Status) Msg() string {
- if s == nil {
- return ""
- }
-
- return s.msg
-}
-
-func (s *Status) IsError(err error) bool {
- return s.isError != nil && s.isError(err)
-}
-
-// RegisterStatus registers a new status to local statuses so that we can use it in Parse.
-func RegisterStatus(status *Status) {
- statusesLock.Lock()
- statuses = append(statuses, status)
- statusesLock.Unlock()
-}
-
-// RegisterStatuses registers some statuses to local statuses so that we can use it in Parse.
-func RegisterStatuses(registerStatus ...*Status) {
- statusesLock.Lock()
- defer statusesLock.Unlock()
-
- for _, status := range registerStatus {
- statuses = append(statuses, status)
- }
-}
-
-// Parse parses err and returns its code and error created from msg.
-func Parse(err error) (int32, string) {
- return ParseOrDefault(err, CodeUnknown, MsgUnknown)
-}
-
-// ParseOrDefault parses err and returns its code and error created from msg.
-func ParseOrDefault(err error, defaultCode int32, defaultMsg string) (int32, string) {
- if err == nil {
- return CodeOK, ""
- }
-
- statusesLock.RLock()
- defer statusesLock.RUnlock()
-
- for _, status := range statuses {
- if status != nil && status.IsError(err) {
- code := status.Code()
- msg := errors.MsgOrDefault(err, status.Msg())
- return code, msg
- }
- }
-
- msg := errors.MsgOrDefault(err, defaultMsg)
- return defaultCode, msg
-}
diff --git a/status/status_test.go b/status/status_test.go
deleted file mode 100644
index 5c57b98..0000000
--- a/status/status_test.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package status
-
-import (
- "io"
- "net/http"
- "testing"
-
- "github.com/FishGoddess/errors"
-)
-
-// go test -v -cover -run=^TestRegisterStatus$
-func TestRegisterStatus(t *testing.T) {
- registered := New(666, "xxx", nil)
- RegisterStatus(registered)
-
- found := false
- for _, status := range statuses {
- if status == registered {
- found = true
- break
- }
- }
-
- if !found {
- t.Error("registered status not found", statuses)
- }
-}
-
-// go test -v -cover -run=^TestRegisterStatuses$
-func TestRegisterStatuses(t *testing.T) {
- registered := []*Status{
- New(123, "abc", nil),
- New(666, "xxx", nil),
- }
-
- RegisterStatuses(registered...)
-
- for i := range registered {
- found := false
- for _, status := range statuses {
- if status == registered[i] {
- found = true
- break
- }
- }
-
- if !found {
- t.Error("registered status not found", statuses)
- }
- }
-}
-
-// go test -v -cover -run=^TestParse$
-func TestParse(t *testing.T) {
- codeBadRequest := int32(http.StatusBadRequest)
- codeForbidden := int32(http.StatusForbidden)
- codeNotFound := int32(http.StatusNotFound)
- codeRequestTimeout := int32(http.StatusRequestTimeout)
- codeDBError := int32(1100)
- codePageTokenInvalid := int32(1200)
-
- RegisterStatus(New(codeBadRequest, "bad request", errors.IsBadRequest))
- RegisterStatus(New(codeForbidden, "forbidden", errors.IsForbidden))
- RegisterStatus(New(codeNotFound, "not found", errors.IsNotFound))
- RegisterStatus(New(codeRequestTimeout, "request timeout", errors.IsRequestTimeout))
- RegisterStatus(New(codeDBError, "db error", errors.IsDBError))
- RegisterStatus(New(codePageTokenInvalid, "page token invalid", errors.IsPageTokenInvalid))
-
- type parseTestCase struct {
- target error
- code int32
- msg string
- }
-
- parseTestCases := []*parseTestCase{
- {target: errors.BadRequest(nil), code: 0, msg: ""},
- {target: errors.Forbidden(nil), code: 0, msg: ""},
- {target: errors.NotFound(nil), code: 0, msg: ""},
- {target: errors.RequestTimeout(nil), code: 0, msg: ""},
- {target: errors.InternalServerError(nil), code: 0, msg: ""},
- {target: errors.DBError(nil), code: 0, msg: ""},
- {target: errors.PageTokenInvalid(nil), code: 0, msg: ""},
-
- {target: errors.BadRequest(io.EOF), code: codeBadRequest, msg: "bad request"},
- {target: errors.Forbidden(io.EOF), code: codeForbidden, msg: "forbidden"},
- {target: errors.NotFound(io.EOF), code: codeNotFound, msg: "not found"},
- {target: errors.RequestTimeout(io.EOF), code: codeRequestTimeout, msg: "request timeout"},
- {target: errors.InternalServerError(io.EOF), code: CodeUnknown, msg: "Server is too busy, please try again later."},
- {target: errors.DBError(io.EOF), code: codeDBError, msg: "db error"},
- {target: errors.PageTokenInvalid(io.EOF), code: codePageTokenInvalid, msg: "page token invalid"},
-
- {target: errors.BadRequest(io.EOF, errors.WithMsg("BadRequest")), code: codeBadRequest, msg: "BadRequest"},
- {target: errors.Forbidden(io.EOF, errors.WithMsg("Forbidden")), code: codeForbidden, msg: "Forbidden"},
- {target: errors.NotFound(io.EOF, errors.WithMsg("NotFound")), code: codeNotFound, msg: "NotFound"},
- {target: errors.RequestTimeout(io.EOF, errors.WithMsg("RequestTimeout")), code: codeRequestTimeout, msg: "RequestTimeout"},
- {target: errors.InternalServerError(io.EOF, errors.WithMsg("InternalServerError")), code: CodeUnknown, msg: "InternalServerError"},
- {target: errors.DBError(io.EOF, errors.WithMsg("DBError")), code: codeDBError, msg: "DBError"},
- {target: errors.PageTokenInvalid(io.EOF, errors.WithMsg("PageTokenInvalid")), code: codePageTokenInvalid, msg: "PageTokenInvalid"},
- }
-
- for _, parseTestCase := range parseTestCases {
- code, msg := Parse(parseTestCase.target)
- if code != parseTestCase.code {
- t.Errorf("code %d != parseTestCase.code %d", code, parseTestCase.code)
- }
-
- if msg != parseTestCase.msg {
- t.Errorf("msg %s != parseTestCase.msg %s", msg, parseTestCase.msg)
- }
- }
-}
diff --git a/types.go b/types.go
deleted file mode 100644
index 00899e2..0000000
--- a/types.go
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2022 FishGoddess. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-
-package errors
-
-import (
- "errors"
- "fmt"
-)
-
-const (
- nilString = ""
-)
-
-var (
- // FormatError formats e and returns a string in Error().
- FormatError = func(e *Error) string {
- return e.err.Error()
- }
-
- // FormatString formats e and returns a string in String().
- FormatString = func(e *Error) string {
- return fmt.Sprintf("%d (%s)", e.code, e.msg)
- }
-)
-
-// Error wraps err with some information.
-type Error struct {
- err error
-
- code int32
- msg string
-}
-
-func (e *Error) Error() string {
- if e == nil || e.err == nil {
- return nilString
- }
-
- return FormatError(e)
-}
-
-func (e *Error) String() string {
- if e == nil || e.err == nil {
- return nilString
- }
-
- return FormatString(e)
-}
-
-// Is returns if e has the same type of target.
-func (e *Error) Is(target error) bool {
- if e == nil {
- return e == target
- }
-
- err, ok := target.(*Error)
- if !ok {
- return e.err == target
- }
-
- return e.code == err.code
-}
-
-// Unwrap returns err inside.
-func (e *Error) Unwrap() error {
- if e == nil {
- return nil
- }
-
- return e.err
-}
-
-// Wrap wraps err with code
-func Wrap(err error, code int32, opts ...Option) error {
- if err == nil {
- return nil
- }
-
- e := &Error{
- err: err,
- code: code,
- msg: "",
- }
-
- applyOptions(e, opts)
- return e
-}
-
-// Unwrap returns if err is Error and its code == code, and the original error will be returned, too.
-func Unwrap(err error, code int32) (error, bool) {
- for {
- if err == nil {
- return nil, false
- }
-
- e, ok := err.(*Error)
- if !ok {
- return err, false
- }
-
- if e.code == code {
- return err, true
- }
-
- err = errors.Unwrap(err)
- }
-}
-
-// Is returns if err is Error and its code == code.
-func Is(err error, code int32) bool {
- _, ok := Unwrap(err, code)
- return ok
-}
-
-// Msg returns the msg of err and false if err doesn't have a msg.
-func Msg(err error) (string, bool) {
- if err == nil {
- return "", false
- }
-
- e, ok := err.(*Error)
- if !ok {
- return err.Error(), false
- }
-
- return e.msg, e.msg != ""
-}
-
-// MsgOrDefault returns the msg of err or defaultMsg if err doesn't have a msg.
-func MsgOrDefault(err error, defaultMsg string) string {
- if msg, ok := Msg(err); ok {
- return msg
- }
-
- return defaultMsg
-}
diff --git a/types_test.go b/types_test.go
deleted file mode 100644
index 4097861..0000000
--- a/types_test.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2022 FishGoddess. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-
-package errors
-
-import (
- "errors"
- "testing"
-)
-
-// go test -v -cover -run=^TestWrapAndUnwrap$
-func TestWrapAndUnwrap(t *testing.T) {
- code := int32(500)
-
- err := Wrap(nil, code)
- if err != nil {
- t.Errorf("err %+v is wrong", err)
- }
-
- err = Wrap(errors.New("500"), code)
- if e, ok := Unwrap(err, code); !ok || e.Error() != "500" {
- t.Errorf("err %+v is wrong", err)
- }
-}
-
-// go test -v -cover -run=^TestMsg$
-func TestMsg(t *testing.T) {
- code := int32(500)
-
- msg, ok := Msg(Wrap(nil, code))
- if ok {
- t.Error("msg should be not ok")
- }
-
- if msg != "" {
- t.Errorf("msg %s is wrong", msg)
- }
-
- msg, ok = Msg(Wrap(errors.New("500"), code))
- if ok {
- t.Error("msg should be not ok")
- }
-
- if msg != "" {
- t.Errorf("msg %s is wrong", msg)
- }
-
- msg, ok = Msg(Wrap(errors.New("500"), code, WithMsg("internal")))
- if !ok {
- t.Error("msg should be ok")
- }
-
- if msg != "internal" {
- t.Errorf("msg %s is wrong", msg)
- }
-}
-
-// go test -v -cover -run=^TestMsgOrDefault$
-func TestMsgOrDefault(t *testing.T) {
- code := int32(500)
-
- msg := MsgOrDefault(Wrap(nil, code), "xxx")
- if msg != "xxx" {
- t.Errorf("msg %s is wrong", msg)
- }
-
- msg = MsgOrDefault(Wrap(errors.New("500"), code), "abc")
- if msg != "abc" {
- t.Errorf("msg %s is wrong", msg)
- }
-
- msg = MsgOrDefault(Wrap(errors.New("500"), code, WithMsg("internal")), "ignore")
- if msg != "internal" {
- t.Errorf("msg %s is wrong", msg)
- }
-}
diff --git a/x/unwrap.go b/unwrap.go
similarity index 100%
rename from x/unwrap.go
rename to unwrap.go
diff --git a/x/unwrap_test.go b/unwrap_test.go
similarity index 100%
rename from x/unwrap_test.go
rename to unwrap_test.go
diff --git a/x/wrap.go b/wrap.go
similarity index 83%
rename from x/wrap.go
rename to wrap.go
index 118a893..a0c378a 100644
--- a/x/wrap.go
+++ b/wrap.go
@@ -5,6 +5,7 @@
package errors
import (
+ "bytes"
"fmt"
"strings"
)
@@ -14,7 +15,6 @@ type Error struct {
message string
cause error
caller string
- args []any
}
// Wrap returns *Error with code and message formatted with args.
@@ -47,11 +47,6 @@ func (e *Error) WithCallers() *Error {
return e
}
-func (e *Error) WithArgs(args ...any) *Error {
- e.args = append(e.args, args...)
- return e
-}
-
// Code returns the code of *Error.
func (e *Error) Code() int32 {
return e.code
@@ -74,9 +69,16 @@ func (e *Error) Error() string {
// String returns *Error as string.
func (e *Error) String() string {
- if e.cause == nil {
- return fmt.Sprintf("%d: %s", e.code, e.message)
+ var buff bytes.Buffer
+ fmt.Fprintf(&buff, "%d: %s", e.code, e.message)
+
+ if e.caller != "" {
+ fmt.Fprintf(&buff, " [%s]", e.caller)
+ }
+
+ if e.cause != nil {
+ fmt.Fprintf(&buff, " (%+v)", e.cause)
}
- return fmt.Sprintf("%d: %s (%+v)", e.code, e.message, e.cause)
+ return buff.String()
}
diff --git a/x/wrap_test.go b/wrap_test.go
similarity index 100%
rename from x/wrap_test.go
rename to wrap_test.go
diff --git a/x/errors.go b/x/errors.go
deleted file mode 100644
index 8b35dad..0000000
--- a/x/errors.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2024 FishGoddess. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-
-package errors
-
-import (
- "errors"
-)
-
-func New(text string) error {
- return errors.New(text)
-}
-
-// Is is a shortcut of errors.Is.
-func Is(err, target error) bool {
- return errors.Is(err, target)
-}
-
-// As is a shortcut of errors.As.
-func As(err error, target any) bool {
- return errors.As(err, target)
-}
-
-// Unwrap is a shortcut of errors.Unwrap.
-func Unwrap(err error) error {
- return errors.Unwrap(err)
-}
-
-// Join is a shortcut of errors.Join.
-func Join(errs ...error) error {
- return errors.Join(errs...)
-}
diff --git a/x/errors_test.go b/x/errors_test.go
deleted file mode 100644
index 53c644a..0000000
--- a/x/errors_test.go
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2024 FishGoddess. All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-
-package errors
-
-import (
- "io"
- "os"
- "testing"
-)
-
-type testError struct {
- reason string
-}
-
-func (te *testError) Code() int32 {
- return 500
-}
-
-func (te *testError) Error() string {
- return te.reason
-}
-
-// go test -v -cover -count=1 -test.cpu=1 -run=^TestIs$
-func TestIs(t *testing.T) {
- testErr := &testError{reason: "test error"}
- wrapErr := Wrap(-1000, "wrap test error").With(testErr)
-
- testCases := []struct {
- err error
- cause error
- }{
- {
- err: io.EOF,
- cause: io.EOF,
- },
- {
- err: Wrap(1000, "wow").With(testErr),
- cause: testErr,
- },
- {
- err: Wrap(1000, "wow too").With(wrapErr),
- cause: testErr,
- },
- }
-
- for _, testCase := range testCases {
- if ok := Is(testCase.err, testCase.cause); !ok {
- t.Errorf("testCase.err %+v isn't testCase.cause %+v", testCase.err, testCase.cause)
- }
- }
-}
-
-// go test -v -cover -count=1 -test.cpu=1 -run=^TestAs$
-func TestAs(t *testing.T) {
- testErr := &testError{reason: "test error"}
- wrapErr := Wrap(-1000, "wrap test error").With(testErr)
-
- targetTestErr := &testError{}
- targetTestErr2 := &testError{}
- targetPathErr := &os.PathError{}
-
- testCases := []struct {
- err error
- target any
- ok bool
- want any
- }{
- {
- err: Wrap(1000, "wow").With(testErr),
- target: &targetTestErr,
- ok: true,
- want: &testErr,
- },
- {
- err: Wrap(1000, "wow too").With(wrapErr),
- target: &targetTestErr2,
- ok: true,
- want: &testErr,
- },
- {
- err: Wrap(1000, "no"),
- target: &targetPathErr,
- ok: false,
- want: nil,
- },
- }
-
- for _, testCase := range testCases {
- ok := As(testCase.err, testCase.target)
- if ok != testCase.ok {
- t.Errorf("err %+v ok %+v != err %+v testCase.ok %+v", testCase.err, testCase.target, ok, testCase.ok)
- }
- }
-}
-
-// go test -v -cover -count=1 -test.cpu=1 -run=^TestUnwrap$
-func TestUnwrap(t *testing.T) {
- testErr := &testError{reason: "test error"}
- wrapErr := Wrap(-1000, "wrap test error").With(testErr)
-
- testCases := []struct {
- err error
- cause error
- }{
- {
- err: testErr,
- cause: nil,
- },
- {
- err: Wrap(1000, "wow").With(testErr),
- cause: testErr,
- },
- {
- err: Wrap(1000, "wow too").With(wrapErr),
- cause: wrapErr,
- },
- }
-
- for _, testCase := range testCases {
- if Unwrap(testCase.err) != testCase.cause {
- t.Errorf("Unwrap(testCase.err) %+v != testCase.cause %+v", Unwrap(testCase.err), testCase.cause)
- }
- }
-}