mirror of https://github.com/stretchr/testify.git
assert.ErrorAs: log target type
parent
7c367bb7bc
commit
ca6698b8a1
|
@ -2102,7 +2102,7 @@ func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
|
||||||
expectedText = target.Error()
|
expectedText = target.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
chain := buildErrorChainString(err)
|
chain := buildErrorChainString(err, false)
|
||||||
|
|
||||||
return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+
|
return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+
|
||||||
"expected: %q\n"+
|
"expected: %q\n"+
|
||||||
|
@ -2125,7 +2125,7 @@ func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
|
||||||
expectedText = target.Error()
|
expectedText = target.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
chain := buildErrorChainString(err)
|
chain := buildErrorChainString(err, false)
|
||||||
|
|
||||||
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
|
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
|
||||||
"found: %q\n"+
|
"found: %q\n"+
|
||||||
|
@ -2143,10 +2143,10 @@ func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
chain := buildErrorChainString(err)
|
chain := buildErrorChainString(err, true)
|
||||||
|
|
||||||
return Fail(t, fmt.Sprintf("Should be in error chain:\n"+
|
return Fail(t, fmt.Sprintf("Should be in error chain:\n"+
|
||||||
"expected: %q\n"+
|
"expected: %T\n"+
|
||||||
"in chain: %s", target, chain,
|
"in chain: %s", target, chain,
|
||||||
), msgAndArgs...)
|
), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
@ -2161,24 +2161,49 @@ func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interfa
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
chain := buildErrorChainString(err)
|
chain := buildErrorChainString(err, true)
|
||||||
|
|
||||||
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
|
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
|
||||||
"found: %q\n"+
|
"found: %T\n"+
|
||||||
"in chain: %s", target, chain,
|
"in chain: %s", target, chain,
|
||||||
), msgAndArgs...)
|
), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildErrorChainString(err error) string {
|
func unwrapAll(err error) (errs []error) {
|
||||||
|
errs = append(errs, err)
|
||||||
|
switch x := err.(type) {
|
||||||
|
case interface{ Unwrap() error }:
|
||||||
|
err = x.Unwrap()
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errs = append(errs, unwrapAll(err)...)
|
||||||
|
case interface{ Unwrap() []error }:
|
||||||
|
for _, err := range x.Unwrap() {
|
||||||
|
errs = append(errs, unwrapAll(err)...)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildErrorChainString(err error, withType bool) string {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
e := errors.Unwrap(err)
|
var chain string
|
||||||
chain := fmt.Sprintf("%q", err.Error())
|
errs := unwrapAll(err)
|
||||||
for e != nil {
|
for i := range errs {
|
||||||
chain += fmt.Sprintf("\n\t%q", e.Error())
|
if i != 0 {
|
||||||
e = errors.Unwrap(e)
|
chain += "\n\t"
|
||||||
|
}
|
||||||
|
chain += fmt.Sprintf("%q", errs[i].Error())
|
||||||
|
if withType {
|
||||||
|
chain += fmt.Sprintf(" (%T)", errs[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return chain
|
return chain
|
||||||
}
|
}
|
||||||
|
|
|
@ -3175,11 +3175,13 @@ func parseLabeledOutput(output string) []labeledContent {
|
||||||
}
|
}
|
||||||
|
|
||||||
type captureTestingT struct {
|
type captureTestingT struct {
|
||||||
msg string
|
failed bool
|
||||||
|
msg string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctt *captureTestingT) Errorf(format string, args ...interface{}) {
|
func (ctt *captureTestingT) Errorf(format string, args ...interface{}) {
|
||||||
ctt.msg = fmt.Sprintf(format, args...)
|
ctt.msg = fmt.Sprintf(format, args...)
|
||||||
|
ctt.failed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctt *captureTestingT) checkResultAndErrMsg(t *testing.T, expectedRes, res bool, expectedErrMsg string) {
|
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
|
||||||
t.Errorf("Should return %t", expectedRes)
|
t.Errorf("Should return %t", expectedRes)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if res == ctt.failed {
|
||||||
|
t.Errorf("The test result (%t) should be reflected in the testing.T type (%t)", res, !ctt.failed)
|
||||||
|
}
|
||||||
contents := parseLabeledOutput(ctt.msg)
|
contents := parseLabeledOutput(ctt.msg)
|
||||||
if res == true {
|
if res == true {
|
||||||
if contents != nil {
|
if contents != nil {
|
||||||
|
@ -3348,50 +3353,82 @@ func TestNotErrorIs(t *testing.T) {
|
||||||
|
|
||||||
func TestErrorAs(t *testing.T) {
|
func TestErrorAs(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
err error
|
err error
|
||||||
result bool
|
result bool
|
||||||
|
resultErrMsg string
|
||||||
}{
|
}{
|
||||||
{fmt.Errorf("wrap: %w", &customError{}), true},
|
{
|
||||||
{io.EOF, false},
|
err: fmt.Errorf("wrap: %w", &customError{}),
|
||||||
{nil, false},
|
result: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
err: io.EOF,
|
||||||
|
result: false,
|
||||||
|
resultErrMsg: "" +
|
||||||
|
"Should be in error chain:\n" +
|
||||||
|
"expected: **assert.customError\n" +
|
||||||
|
"in chain: \"EOF\" (*errors.errorString)\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
err: nil,
|
||||||
|
result: false,
|
||||||
|
resultErrMsg: "" +
|
||||||
|
"Should be in error chain:\n" +
|
||||||
|
"expected: **assert.customError\n" +
|
||||||
|
"in chain: \n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
err: fmt.Errorf("abc: %w", errors.New("def")),
|
||||||
|
result: false,
|
||||||
|
resultErrMsg: "" +
|
||||||
|
"Should be in error chain:\n" +
|
||||||
|
"expected: **assert.customError\n" +
|
||||||
|
"in chain: \"abc: def\" (*fmt.wrapError)\n" +
|
||||||
|
"\t\"def\" (*errors.errorString)\n",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
tt := tt
|
tt := tt
|
||||||
var target *customError
|
var target *customError
|
||||||
t.Run(fmt.Sprintf("ErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) {
|
t.Run(fmt.Sprintf("ErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) {
|
||||||
mockT := new(testing.T)
|
mockT := new(captureTestingT)
|
||||||
res := ErrorAs(mockT, tt.err, &target)
|
res := ErrorAs(mockT, tt.err, &target)
|
||||||
if res != tt.result {
|
mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg)
|
||||||
t.Errorf("ErrorAs(%#v,%#v) should return %t", tt.err, target, tt.result)
|
|
||||||
}
|
|
||||||
if res == mockT.Failed() {
|
|
||||||
t.Errorf("The test result (%t) should be reflected in the testing.T type (%t)", res, !mockT.Failed())
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNotErrorAs(t *testing.T) {
|
func TestNotErrorAs(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
err error
|
err error
|
||||||
result bool
|
result bool
|
||||||
|
resultErrMsg string
|
||||||
}{
|
}{
|
||||||
{fmt.Errorf("wrap: %w", &customError{}), false},
|
{
|
||||||
{io.EOF, true},
|
err: fmt.Errorf("wrap: %w", &customError{}),
|
||||||
{nil, true},
|
result: false,
|
||||||
|
resultErrMsg: "" +
|
||||||
|
"Target error should not be in err chain:\n" +
|
||||||
|
"found: **assert.customError\n" +
|
||||||
|
"in chain: \"wrap: fail\" (*fmt.wrapError)\n" +
|
||||||
|
"\t\"fail\" (*assert.customError)\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
err: io.EOF,
|
||||||
|
result: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
err: nil,
|
||||||
|
result: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
tt := tt
|
tt := tt
|
||||||
var target *customError
|
var target *customError
|
||||||
t.Run(fmt.Sprintf("NotErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) {
|
t.Run(fmt.Sprintf("NotErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) {
|
||||||
mockT := new(testing.T)
|
mockT := new(captureTestingT)
|
||||||
res := NotErrorAs(mockT, tt.err, &target)
|
res := NotErrorAs(mockT, tt.err, &target)
|
||||||
if res != tt.result {
|
mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg)
|
||||||
t.Errorf("NotErrorAs(%#v,%#v) should not return %t", tt.err, target, tt.result)
|
|
||||||
}
|
|
||||||
if res == mockT.Failed() {
|
|
||||||
t.Errorf("The test result (%t) should be reflected in the testing.T type (%t)", res, !mockT.Failed())
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue