From 205e2385ddbee271984851bc5c0b0cb61475420e Mon Sep 17 00:00:00 2001 From: Craig Davison Date: Wed, 26 Jul 2023 15:13:55 -0600 Subject: [PATCH 1/4] TestErrorIs/TestNotErrorIs: check error contents --- assert/assertions_test.go | 202 +++++++++++++++++++++++++++++++++----- 1 file changed, 176 insertions(+), 26 deletions(-) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 9a44f95eb..72908b305 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -2908,52 +2908,202 @@ func Test_truncatingFormat(t *testing.T) { } } +func parseLabeledOutput(output string) []labeledContent { + labelPattern := regexp.MustCompile(`^\t([^\t]*): *\t(.*)$`) + contentPattern := regexp.MustCompile(`^\t *\t(.*)$`) + var contents []labeledContent + lines := strings.Split(output, "\n") + i := -1 + for _, line := range lines { + if line == "" { + // skip blank lines + continue + } + matches := labelPattern.FindStringSubmatch(line) + if len(matches) == 3 { + // a label + contents = append(contents, labeledContent{ + label: matches[1], + content: matches[2] + "\n", + }) + i++ + continue + } + matches = contentPattern.FindStringSubmatch(line) + if len(matches) == 2 { + // just content + if i >= 0 { + contents[i].content += matches[1] + "\n" + continue + } + } + // Couldn't parse output + return nil + } + return contents +} + +type captureTestingT struct { + msg string +} + +func (ctt *captureTestingT) Errorf(format string, args ...interface{}) { + ctt.msg = fmt.Sprintf(format, args...) +} + +func checkResultAndErrMsg(t *testing.T, expectedRes, res bool, expectedErrMsg, rawErrOutput string) { + t.Helper() + if res != expectedRes { + t.Errorf("Should return %t", expectedRes) + return + } + contents := parseLabeledOutput(rawErrOutput) + if res == true { + if contents != nil { + t.Errorf("Should not log an error") + } + return + } + if contents == nil { + t.Errorf("Should log an error. Log output: %v", rawErrOutput) + return + } + for _, content := range contents { + if content.label == "Error" { + if expectedErrMsg == content.content { + return + } + t.Errorf("Logged Error: %v", content.content) + } + } + t.Errorf("Should log Error: %v", expectedErrMsg) +} + func TestErrorIs(t *testing.T) { - mockT := new(testing.T) tests := []struct { - err error - target error - result bool + err error + target error + result bool + resultErrMsg string }{ - {io.EOF, io.EOF, true}, - {fmt.Errorf("wrap: %w", io.EOF), io.EOF, true}, - {io.EOF, io.ErrClosedPipe, false}, - {nil, io.EOF, false}, - {io.EOF, nil, false}, - {nil, nil, true}, + { + err: io.EOF, + target: io.EOF, + result: true, + }, + { + err: fmt.Errorf("wrap: %w", io.EOF), + target: io.EOF, + result: true, + }, + { + err: io.EOF, + target: io.ErrClosedPipe, + result: false, + resultErrMsg: "Target error should be in err chain:\n" + + "expected: \"io: read/write on closed pipe\"\n" + + "in chain: \"EOF\"\n", + }, + { + err: nil, + target: io.EOF, + result: false, + resultErrMsg: "Target error should be in err chain:\n" + + "expected: \"EOF\"\n" + + "in chain: \n", + }, + { + err: io.EOF, + target: nil, + result: false, + resultErrMsg: "Target error should be in err chain:\n" + + "expected: \"\"\n" + + "in chain: \"EOF\"\n", + }, + { + err: nil, + target: nil, + result: true, + }, + { + err: fmt.Errorf("abc: %w", errors.New("def")), + target: io.EOF, + result: false, + resultErrMsg: "Target error should be in err chain:\n" + + "expected: \"EOF\"\n" + + "in chain: \"abc: def\"\n" + + "\t\"def\"\n", + }, } for _, tt := range tests { tt := tt + mockT := new(captureTestingT) t.Run(fmt.Sprintf("ErrorIs(%#v,%#v)", tt.err, tt.target), func(t *testing.T) { res := ErrorIs(mockT, tt.err, tt.target) - if res != tt.result { - t.Errorf("ErrorIs(%#v,%#v) should return %t", tt.err, tt.target, tt.result) - } + checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg, mockT.msg) }) } } func TestNotErrorIs(t *testing.T) { - mockT := new(testing.T) tests := []struct { - err error - target error - result bool + err error + target error + result bool + resultErrMsg string }{ - {io.EOF, io.EOF, false}, - {fmt.Errorf("wrap: %w", io.EOF), io.EOF, false}, - {io.EOF, io.ErrClosedPipe, true}, - {nil, io.EOF, true}, - {io.EOF, nil, true}, - {nil, nil, false}, + { + err: io.EOF, + target: io.EOF, + result: false, + resultErrMsg: "Target error should not be in err chain:\n" + + "found: \"EOF\"\n" + + "in chain: \"EOF\"\n", + }, + { + err: fmt.Errorf("wrap: %w", io.EOF), + target: io.EOF, + result: false, + resultErrMsg: "Target error should not be in err chain:\n" + + "found: \"EOF\"\n" + + "in chain: \"wrap: EOF\"\n" + + "\t\"EOF\"\n", + }, + { + err: io.EOF, + target: io.ErrClosedPipe, + result: true, + }, + { + err: nil, + target: io.EOF, + result: true, + }, + { + err: io.EOF, + target: nil, + result: true, + }, + { + err: nil, + target: nil, + result: false, + resultErrMsg: "Target error should not be in err chain:\n" + + "found: \"\"\n" + + "in chain: \n", + }, + { + err: fmt.Errorf("abc: %w", errors.New("def")), + target: io.EOF, + result: true, + }, } for _, tt := range tests { tt := tt + mockT := new(captureTestingT) t.Run(fmt.Sprintf("NotErrorIs(%#v,%#v)", tt.err, tt.target), func(t *testing.T) { res := NotErrorIs(mockT, tt.err, tt.target) - if res != tt.result { - t.Errorf("NotErrorIs(%#v,%#v) should return %t", tt.err, tt.target, tt.result) - } + checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg, mockT.msg) }) } } From ccf853df9548ee011734cfe073b7db6794267d14 Mon Sep 17 00:00:00 2001 From: Craig Davison Date: Wed, 26 Jul 2023 15:37:34 -0600 Subject: [PATCH 2/4] captureTestingT.checkResultAndErrMsg --- assert/assertions_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 72908b305..81f58977e 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -2951,13 +2951,13 @@ func (ctt *captureTestingT) Errorf(format string, args ...interface{}) { ctt.msg = fmt.Sprintf(format, args...) } -func checkResultAndErrMsg(t *testing.T, expectedRes, res bool, expectedErrMsg, rawErrOutput string) { +func (ctt *captureTestingT) checkResultAndErrMsg(t *testing.T, expectedRes, res bool, expectedErrMsg string) { t.Helper() if res != expectedRes { t.Errorf("Should return %t", expectedRes) return } - contents := parseLabeledOutput(rawErrOutput) + contents := parseLabeledOutput(ctt.msg) if res == true { if contents != nil { t.Errorf("Should not log an error") @@ -2965,7 +2965,7 @@ func checkResultAndErrMsg(t *testing.T, expectedRes, res bool, expectedErrMsg, r return } if contents == nil { - t.Errorf("Should log an error. Log output: %v", rawErrOutput) + t.Errorf("Should log an error. Log output: %v", ctt.msg) return } for _, content := range contents { @@ -3040,7 +3040,7 @@ func TestErrorIs(t *testing.T) { mockT := new(captureTestingT) t.Run(fmt.Sprintf("ErrorIs(%#v,%#v)", tt.err, tt.target), func(t *testing.T) { res := ErrorIs(mockT, tt.err, tt.target) - checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg, mockT.msg) + mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg) }) } } @@ -3103,7 +3103,7 @@ func TestNotErrorIs(t *testing.T) { mockT := new(captureTestingT) t.Run(fmt.Sprintf("NotErrorIs(%#v,%#v)", tt.err, tt.target), func(t *testing.T) { res := NotErrorIs(mockT, tt.err, tt.target) - checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg, mockT.msg) + mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg) }) } } From 2a2e4e0bf352e7bd82a9bf19494851c94eff7b1e Mon Sep 17 00:00:00 2001 From: Craig Davison Date: Mon, 31 Jul 2023 16:41:32 -0600 Subject: [PATCH 3/4] address some review comments --- assert/assertions_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 81f58977e..7021382d9 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -2908,6 +2908,8 @@ func Test_truncatingFormat(t *testing.T) { } } +// parseLabeledOutput does the inverse of labeledOutput - it takes a formatted +// output string and turns it back into a slice of labeledContent. func parseLabeledOutput(output string) []labeledContent { labelPattern := regexp.MustCompile(`^\t([^\t]*): *\t(.*)$`) contentPattern := regexp.MustCompile(`^\t *\t(.*)$`) @@ -3037,8 +3039,8 @@ func TestErrorIs(t *testing.T) { } for _, tt := range tests { tt := tt - mockT := new(captureTestingT) t.Run(fmt.Sprintf("ErrorIs(%#v,%#v)", tt.err, tt.target), func(t *testing.T) { + mockT := new(captureTestingT) res := ErrorIs(mockT, tt.err, tt.target) mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg) }) @@ -3100,8 +3102,8 @@ func TestNotErrorIs(t *testing.T) { } for _, tt := range tests { tt := tt - mockT := new(captureTestingT) t.Run(fmt.Sprintf("NotErrorIs(%#v,%#v)", tt.err, tt.target), func(t *testing.T) { + mockT := new(captureTestingT) res := NotErrorIs(mockT, tt.err, tt.target) mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg) }) From 1dde9553a4cc351c0dcaae920334accab27393ee Mon Sep 17 00:00:00 2001 From: Craig Davison Date: Mon, 30 Oct 2023 23:12:39 -0600 Subject: [PATCH 4/4] Improve readability --- assert/assertions_test.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 7021382d9..d2a25c245 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -3002,7 +3002,8 @@ func TestErrorIs(t *testing.T) { err: io.EOF, target: io.ErrClosedPipe, result: false, - resultErrMsg: "Target error should be in err chain:\n" + + resultErrMsg: "" + + "Target error should be in err chain:\n" + "expected: \"io: read/write on closed pipe\"\n" + "in chain: \"EOF\"\n", }, @@ -3010,7 +3011,8 @@ func TestErrorIs(t *testing.T) { err: nil, target: io.EOF, result: false, - resultErrMsg: "Target error should be in err chain:\n" + + resultErrMsg: "" + + "Target error should be in err chain:\n" + "expected: \"EOF\"\n" + "in chain: \n", }, @@ -3018,7 +3020,8 @@ func TestErrorIs(t *testing.T) { err: io.EOF, target: nil, result: false, - resultErrMsg: "Target error should be in err chain:\n" + + resultErrMsg: "" + + "Target error should be in err chain:\n" + "expected: \"\"\n" + "in chain: \"EOF\"\n", }, @@ -3031,7 +3034,8 @@ func TestErrorIs(t *testing.T) { err: fmt.Errorf("abc: %w", errors.New("def")), target: io.EOF, result: false, - resultErrMsg: "Target error should be in err chain:\n" + + resultErrMsg: "" + + "Target error should be in err chain:\n" + "expected: \"EOF\"\n" + "in chain: \"abc: def\"\n" + "\t\"def\"\n", @@ -3058,7 +3062,8 @@ func TestNotErrorIs(t *testing.T) { err: io.EOF, target: io.EOF, result: false, - resultErrMsg: "Target error should not be in err chain:\n" + + resultErrMsg: "" + + "Target error should not be in err chain:\n" + "found: \"EOF\"\n" + "in chain: \"EOF\"\n", }, @@ -3066,7 +3071,8 @@ func TestNotErrorIs(t *testing.T) { err: fmt.Errorf("wrap: %w", io.EOF), target: io.EOF, result: false, - resultErrMsg: "Target error should not be in err chain:\n" + + resultErrMsg: "" + + "Target error should not be in err chain:\n" + "found: \"EOF\"\n" + "in chain: \"wrap: EOF\"\n" + "\t\"EOF\"\n", @@ -3090,7 +3096,8 @@ func TestNotErrorIs(t *testing.T) { err: nil, target: nil, result: false, - resultErrMsg: "Target error should not be in err chain:\n" + + resultErrMsg: "" + + "Target error should not be in err chain:\n" + "found: \"\"\n" + "in chain: \n", },