Skip to content

Commit ca6698b

Browse files
committed
assert.ErrorAs: log target type
1 parent 7c367bb commit ca6698b

File tree

2 files changed

+99
-37
lines changed

2 files changed

+99
-37
lines changed

assert/assertions.go

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2102,7 +2102,7 @@ func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
21022102
expectedText = target.Error()
21032103
}
21042104

2105-
chain := buildErrorChainString(err)
2105+
chain := buildErrorChainString(err, false)
21062106

21072107
return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+
21082108
"expected: %q\n"+
@@ -2125,7 +2125,7 @@ func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
21252125
expectedText = target.Error()
21262126
}
21272127

2128-
chain := buildErrorChainString(err)
2128+
chain := buildErrorChainString(err, false)
21292129

21302130
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
21312131
"found: %q\n"+
@@ -2143,10 +2143,10 @@ func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{
21432143
return true
21442144
}
21452145

2146-
chain := buildErrorChainString(err)
2146+
chain := buildErrorChainString(err, true)
21472147

21482148
return Fail(t, fmt.Sprintf("Should be in error chain:\n"+
2149-
"expected: %q\n"+
2149+
"expected: %T\n"+
21502150
"in chain: %s", target, chain,
21512151
), msgAndArgs...)
21522152
}
@@ -2161,24 +2161,49 @@ func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interfa
21612161
return true
21622162
}
21632163

2164-
chain := buildErrorChainString(err)
2164+
chain := buildErrorChainString(err, true)
21652165

21662166
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
2167-
"found: %q\n"+
2167+
"found: %T\n"+
21682168
"in chain: %s", target, chain,
21692169
), msgAndArgs...)
21702170
}
21712171

2172-
func buildErrorChainString(err error) string {
2172+
func unwrapAll(err error) (errs []error) {
2173+
errs = append(errs, err)
2174+
switch x := err.(type) {
2175+
case interface{ Unwrap() error }:
2176+
err = x.Unwrap()
2177+
if err == nil {
2178+
return
2179+
}
2180+
errs = append(errs, unwrapAll(err)...)
2181+
case interface{ Unwrap() []error }:
2182+
for _, err := range x.Unwrap() {
2183+
errs = append(errs, unwrapAll(err)...)
2184+
}
2185+
return
2186+
default:
2187+
return
2188+
}
2189+
return
2190+
}
2191+
2192+
func buildErrorChainString(err error, withType bool) string {
21732193
if err == nil {
21742194
return ""
21752195
}
21762196

2177-
e := errors.Unwrap(err)
2178-
chain := fmt.Sprintf("%q", err.Error())
2179-
for e != nil {
2180-
chain += fmt.Sprintf("\n\t%q", e.Error())
2181-
e = errors.Unwrap(e)
2197+
var chain string
2198+
errs := unwrapAll(err)
2199+
for i := range errs {
2200+
if i != 0 {
2201+
chain += "\n\t"
2202+
}
2203+
chain += fmt.Sprintf("%q", errs[i].Error())
2204+
if withType {
2205+
chain += fmt.Sprintf(" (%T)", errs[i])
2206+
}
21822207
}
21832208
return chain
21842209
}

assert/assertions_test.go

Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3175,11 +3175,13 @@ func parseLabeledOutput(output string) []labeledContent {
31753175
}
31763176

31773177
type captureTestingT struct {
3178-
msg string
3178+
failed bool
3179+
msg string
31793180
}
31803181

31813182
func (ctt *captureTestingT) Errorf(format string, args ...interface{}) {
31823183
ctt.msg = fmt.Sprintf(format, args...)
3184+
ctt.failed = true
31833185
}
31843186

31853187
func (ctt *captureTestingT) checkResultAndErrMsg(t *testing.T, expectedRes, res bool, expectedErrMsg string) {
@@ -3188,6 +3190,9 @@ func (ctt *captureTestingT) checkResultAndErrMsg(t *testing.T, expectedRes, res
31883190
t.Errorf("Should return %t", expectedRes)
31893191
return
31903192
}
3193+
if res == ctt.failed {
3194+
t.Errorf("The test result (%t) should be reflected in the testing.T type (%t)", res, !ctt.failed)
3195+
}
31913196
contents := parseLabeledOutput(ctt.msg)
31923197
if res == true {
31933198
if contents != nil {
@@ -3348,50 +3353,82 @@ func TestNotErrorIs(t *testing.T) {
33483353

33493354
func TestErrorAs(t *testing.T) {
33503355
tests := []struct {
3351-
err error
3352-
result bool
3356+
err error
3357+
result bool
3358+
resultErrMsg string
33533359
}{
3354-
{fmt.Errorf("wrap: %w", &customError{}), true},
3355-
{io.EOF, false},
3356-
{nil, false},
3360+
{
3361+
err: fmt.Errorf("wrap: %w", &customError{}),
3362+
result: true,
3363+
},
3364+
{
3365+
err: io.EOF,
3366+
result: false,
3367+
resultErrMsg: "" +
3368+
"Should be in error chain:\n" +
3369+
"expected: **assert.customError\n" +
3370+
"in chain: \"EOF\" (*errors.errorString)\n",
3371+
},
3372+
{
3373+
err: nil,
3374+
result: false,
3375+
resultErrMsg: "" +
3376+
"Should be in error chain:\n" +
3377+
"expected: **assert.customError\n" +
3378+
"in chain: \n",
3379+
},
3380+
{
3381+
err: fmt.Errorf("abc: %w", errors.New("def")),
3382+
result: false,
3383+
resultErrMsg: "" +
3384+
"Should be in error chain:\n" +
3385+
"expected: **assert.customError\n" +
3386+
"in chain: \"abc: def\" (*fmt.wrapError)\n" +
3387+
"\t\"def\" (*errors.errorString)\n",
3388+
},
33573389
}
33583390
for _, tt := range tests {
33593391
tt := tt
33603392
var target *customError
33613393
t.Run(fmt.Sprintf("ErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) {
3362-
mockT := new(testing.T)
3394+
mockT := new(captureTestingT)
33633395
res := ErrorAs(mockT, tt.err, &target)
3364-
if res != tt.result {
3365-
t.Errorf("ErrorAs(%#v,%#v) should return %t", tt.err, target, tt.result)
3366-
}
3367-
if res == mockT.Failed() {
3368-
t.Errorf("The test result (%t) should be reflected in the testing.T type (%t)", res, !mockT.Failed())
3369-
}
3396+
mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg)
33703397
})
33713398
}
33723399
}
33733400

33743401
func TestNotErrorAs(t *testing.T) {
33753402
tests := []struct {
3376-
err error
3377-
result bool
3403+
err error
3404+
result bool
3405+
resultErrMsg string
33783406
}{
3379-
{fmt.Errorf("wrap: %w", &customError{}), false},
3380-
{io.EOF, true},
3381-
{nil, true},
3407+
{
3408+
err: fmt.Errorf("wrap: %w", &customError{}),
3409+
result: false,
3410+
resultErrMsg: "" +
3411+
"Target error should not be in err chain:\n" +
3412+
"found: **assert.customError\n" +
3413+
"in chain: \"wrap: fail\" (*fmt.wrapError)\n" +
3414+
"\t\"fail\" (*assert.customError)\n",
3415+
},
3416+
{
3417+
err: io.EOF,
3418+
result: true,
3419+
},
3420+
{
3421+
err: nil,
3422+
result: true,
3423+
},
33823424
}
33833425
for _, tt := range tests {
33843426
tt := tt
33853427
var target *customError
33863428
t.Run(fmt.Sprintf("NotErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) {
3387-
mockT := new(testing.T)
3429+
mockT := new(captureTestingT)
33883430
res := NotErrorAs(mockT, tt.err, &target)
3389-
if res != tt.result {
3390-
t.Errorf("NotErrorAs(%#v,%#v) should not return %t", tt.err, target, tt.result)
3391-
}
3392-
if res == mockT.Failed() {
3393-
t.Errorf("The test result (%t) should be reflected in the testing.T type (%t)", res, !mockT.Failed())
3394-
}
3431+
mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg)
33953432
})
33963433
}
33973434
}

0 commit comments

Comments
 (0)