blob: 972c52d00d65e2bb22cb11bb696ce568d994e5a8 [file] [log] [blame]
package multierror
import (
"errors"
"fmt"
"reflect"
"testing"
)
func TestError_Impl(t *testing.T) {
var _ error = new(Error)
}
func TestErrorError_custom(t *testing.T) {
errors := []error{
errors.New("foo"),
errors.New("bar"),
}
fn := func(es []error) string {
return "foo"
}
multi := &Error{Errors: errors, ErrorFormat: fn}
if multi.Error() != "foo" {
t.Fatalf("bad: %s", multi.Error())
}
}
func TestErrorError_default(t *testing.T) {
expected := `2 errors occurred:
* foo
* bar
`
errors := []error{
errors.New("foo"),
errors.New("bar"),
}
multi := &Error{Errors: errors}
if multi.Error() != expected {
t.Fatalf("bad: %s", multi.Error())
}
}
func TestErrorErrorOrNil(t *testing.T) {
err := new(Error)
if err.ErrorOrNil() != nil {
t.Fatalf("bad: %#v", err.ErrorOrNil())
}
err.Errors = []error{errors.New("foo")}
if v := err.ErrorOrNil(); v == nil {
t.Fatal("should not be nil")
} else if !reflect.DeepEqual(v, err) {
t.Fatalf("bad: %#v", v)
}
}
func TestErrorWrappedErrors(t *testing.T) {
errors := []error{
errors.New("foo"),
errors.New("bar"),
}
multi := &Error{Errors: errors}
if !reflect.DeepEqual(multi.Errors, multi.WrappedErrors()) {
t.Fatalf("bad: %s", multi.WrappedErrors())
}
}
func TestErrorUnwrap(t *testing.T) {
t.Run("with errors", func(t *testing.T) {
err := &Error{Errors: []error{
errors.New("foo"),
errors.New("bar"),
errors.New("baz"),
}}
var current error = err
for i := 0; i < len(err.Errors); i++ {
current = errors.Unwrap(current)
if !errors.Is(current, err.Errors[i]) {
t.Fatal("should be next value")
}
}
if errors.Unwrap(current) != nil {
t.Fatal("should be nil at the end")
}
})
t.Run("with no errors", func(t *testing.T) {
err := &Error{Errors: nil}
if errors.Unwrap(err) != nil {
t.Fatal("should be nil")
}
})
t.Run("with nil multierror", func(t *testing.T) {
var err *Error
if errors.Unwrap(err) != nil {
t.Fatal("should be nil")
}
})
}
func TestErrorIs(t *testing.T) {
errBar := errors.New("bar")
t.Run("with errBar", func(t *testing.T) {
err := &Error{Errors: []error{
errors.New("foo"),
errBar,
errors.New("baz"),
}}
if !errors.Is(err, errBar) {
t.Fatal("should be true")
}
})
t.Run("with errBar wrapped by fmt.Errorf", func(t *testing.T) {
err := &Error{Errors: []error{
errors.New("foo"),
fmt.Errorf("errorf: %w", errBar),
errors.New("baz"),
}}
if !errors.Is(err, errBar) {
t.Fatal("should be true")
}
})
t.Run("without errBar", func(t *testing.T) {
err := &Error{Errors: []error{
errors.New("foo"),
errors.New("baz"),
}}
if errors.Is(err, errBar) {
t.Fatal("should be false")
}
})
}
func TestErrorAs(t *testing.T) {
match := &nestedError{}
t.Run("with the value", func(t *testing.T) {
err := &Error{Errors: []error{
errors.New("foo"),
match,
errors.New("baz"),
}}
var target *nestedError
if !errors.As(err, &target) {
t.Fatal("should be true")
}
if target == nil {
t.Fatal("target should not be nil")
}
})
t.Run("with the value wrapped by fmt.Errorf", func(t *testing.T) {
err := &Error{Errors: []error{
errors.New("foo"),
fmt.Errorf("errorf: %w", match),
errors.New("baz"),
}}
var target *nestedError
if !errors.As(err, &target) {
t.Fatal("should be true")
}
if target == nil {
t.Fatal("target should not be nil")
}
})
t.Run("without the value", func(t *testing.T) {
err := &Error{Errors: []error{
errors.New("foo"),
errors.New("baz"),
}}
var target *nestedError
if errors.As(err, &target) {
t.Fatal("should be false")
}
if target != nil {
t.Fatal("target should be nil")
}
})
}
// nestedError implements error and is used for tests.
type nestedError struct{}
func (*nestedError) Error() string { return "" }