1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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))
}
}
|