diff options
Diffstat (limited to 'assert/errequal.go')
| -rw-r--r-- | assert/errequal.go | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/assert/errequal.go b/assert/errequal.go new file mode 100644 index 0000000..4752f26 --- /dev/null +++ b/assert/errequal.go @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: 2026 Stefan Majewsky <majewsky@gmx.net> +// SPDX-License-Identifier: Apache-2.0 + +package assert + +import ( + "errors" + "fmt" + "reflect" + "regexp" +) + +// ErrEqual checks if the actual error matches the expectation. +// - If expected is nil, the actual error must be nil. +// - If expected is of type error, the actual error must be exactly equal to it or contain it, as reported by the [errors.Is] function. +// - If expected is of type string, the actual error must have a message exactly equal to it. +// - If expected is of type [*regexp.Regexp], the actual error must have a message matching that regexp. +// - If expected is of any other type, ErrEqual will panic. +func ErrEqual(t TestingTB, actual error, expected any) bool { + // coerce all types that implement `error` into the interface type `error`, + // and also coerce all nil values of concrete `error` types into untyped nil + if expectedErr, ok := expected.(error); ok { + // convert nil values of concrete error types into a generic nil value + if reflect.ValueOf(expectedErr).IsNil() { + expected = nil + } else { + expected = expectedErr + } + } + + switch expected := expected.(type) { + case nil: + if actual == nil { + return true + } else { + t.Errorf("expected no error, but got %q", actual.Error()) + return false + } + case error: + if actual == nil { + t.Errorf("expected %q, but got no error", expected.Error()) + return false + } else if errors.Is(actual, expected) { + return true + } else { + t.Errorf("expected %q, but got %q", expected.Error(), actual.Error()) + return false + } + case string: + if actual == nil { + t.Errorf("expected %q, but got no error", expected) + return false + } else if actual.Error() == expected { + return true + } else { + t.Errorf("expected %q, but got %q", expected, actual.Error()) + return false + } + case *regexp.Regexp: + if actual == nil { + t.Errorf("expected an error matching /%s/, but got no error", expected.String()) + return false + } else if expected.MatchString(actual.Error()) { + return true + } else { + t.Errorf("expected an error matching /%s/, but got %q", expected.String(), actual.Error()) + return false + } + default: + panic(fmt.Sprintf("cannot handle `expected` of type %T", expected)) + } +} |
