-
Notifications
You must be signed in to change notification settings - Fork 0
/
error.go
173 lines (145 loc) · 4.37 KB
/
error.go
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package subtest
import (
"bytes"
"errors"
"fmt"
"reflect"
)
const (
msgNotLenType = "type does not support len"
msgNotCapType = "type does not support cap"
msgNotIndexType = "type does not support index operation"
msgNotErrorType = "type is not error"
msgNotSliceArrType = "type is not slice or array"
msgNotTimeType = "type is not time.Time or *time.Time"
msgNotFloat64 = "not convertable to float64"
msgIndexOutOfRange = "index out of range"
msgLessThan = "not less than"
msgLessThanOrEqual = "not less than or equal to"
msgGreaterThan = "not greater than"
msgGreaterThanOrEqual = "not greater than or equal to"
msgNotNumericEqual = "numeric equal"
msgNumericEqual = "not numeric equal"
msgBefore = "time not before"
msgNotBefore = "time before"
msgTimeEqual = "times not equal"
msgNotTimeEqual = "times equal"
msgNotDeepEqual = "deep equal"
msgDeepEqual = "not deep equal"
msgNotCompareEqual = "compare equal"
msgCompareEqual = "not compare equal"
msgNotReflectNil = "typed or untyped nil"
msgReflectNil = "neither typed nor untyped nil"
msgNotRegexpType = "type not matchable by regular expressions"
msgMatchRegexp = "regular expression not matching "
msgContainsMatch = "does not match any elements"
msgNoError = "error is not nil"
msgError = "error is nil"
msgErrorIsNot = "error is matching target error"
msgErrorIs = "error is not matching target error"
msgSchemaMatch = "not matching schema"
)
// Failure is an error type that aid with consistent formatting of test
// failures. In error matching, two Failure instances are considered equal when
// their formatted content is the same.
type Failure struct {
Prefix string
Got string
Expect string
Reject string
next error
}
// Failf formats a plain text failure.
func Failf(format string, v ...interface{}) Failure {
return Failure{Prefix: fmt.Sprintf(format, v...)}
}
// FailExpect formats a failure for content that is not matching some expected
// value. The package type formatter is used.
func FailExpect(prefix string, got, expect interface{}) Failure {
next, _ := got.(error)
return Failure{
Prefix: prefix,
Got: formatIndentedType(got),
Expect: formatIndentedType(expect),
next: next,
}
}
// FailReject formats a failure for content that is matching some rejected
// value. The package type formatter is used.
func FailReject(prefix string, got, reject interface{}) Failure {
next, _ := got.(error)
return Failure{
Prefix: prefix,
Got: formatIndentedType(got),
Reject: formatIndentedType(reject),
next: next,
}
}
// FailGot formats a failure for some unexpected content. The package type
// formatter is used.
func FailGot(prefix string, got interface{}) Failure {
next, _ := got.(error)
return Failure{
Prefix: prefix,
Got: formatIndentedType(got),
next: next,
}
}
func (f Failure) Error() string {
const fmtS = "\n%s: %s"
s := f.Prefix
if f.Got != "" {
s += fmt.Sprintf(fmtS, "got", f.Got)
}
if f.Expect != "" {
s += fmt.Sprintf(fmtS, "want", f.Expect)
}
if f.Reject != "" {
s += fmt.Sprintf(fmtS, "don't want", f.Reject)
}
return s
}
// Unwrap returns the next error in the chain, if any.
func (f Failure) Unwrap() error {
return f.next
}
// Is returns true if f matches target.
func (f Failure) Is(target error) bool {
f2, match := target.(Failure)
match = match && f.Prefix == f2.Prefix
match = match && f.Got == f2.Got
match = match && f.Expect == f2.Expect
match = match && f.Reject == f2.Reject
return match
}
// KeyError returns an error prefixed by a key.
func KeyError(key interface{}, err error) error {
return fmt.Errorf("key %#v: %w", key, err)
}
// Errors combine the output of multiple errors on separate lines.
type Errors []error
func (errs Errors) Error() string {
var buf bytes.Buffer
var s string
fmt.Fprintf(&buf, "%d issue(s)", len(errs))
for i, err := range errs {
if err == nil {
s = "\n (nil)"
} else {
s = "\n" + indentString(err.Error())
}
fmt.Fprintf(&buf, "\nissue #%d:%s", i, s)
}
return buf.String()
}
// Is returns true if target is found within errs or if target deep equals
// errs.
func (errs Errors) Is(target error) bool {
for _, err := range errs {
if errors.Is(err, target) {
return true
}
}
// Cast errs to interface{} to silence the gopls linter.
return reflect.DeepEqual(interface{}(errs), target)
}