Skip to content

Commit 009470e

Browse files
committed
AssertableError + ThenPrettyPrintOnFail + misc. changes
1 parent 9a064fa commit 009470e

17 files changed

+256
-51
lines changed

.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ go:
77
- 1.8
88
- 1.9
99
- "1.10"
10+
- 1.11
1011
- tip
1112

1213
env: GO15VENDOREXPERIMENT=1

Makefile

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
GO ?= go
2-
GOFMT ?= gofmt
32
GOIMPORTS ?= goimports
43
ALL_PACKAGES := ./...
54
LOCAL_PACKAGES := `$(GO) list $(ALL_PACKAGES) | grep -v /vendor/`
@@ -8,7 +7,6 @@ LOCAL_PACKAGES_FOLDERS := $(shell find * -maxdepth 0 -type d | grep -v vendor)
87
all: clean check
98

109
check:
11-
$(GOFMT) -s -w $(LOCAL_PACKAGES_FOLDERS)
1210
$(GOIMPORTS) -w $(LOCAL_PACKAGES_FOLDERS)
1311
$(GO) vet $(LOCAL_PACKAGES)
1412
$(GO) test $(LOCAL_PACKAGES)

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import (
4040
func TestDeepThought(t *testing.T) {
4141
computer := NewDeepThoughtComputer()
4242
answer, err := computer.AnswerTheUltimateQuestion()
43-
if assert.For(t).ThatActual(err).IsNil().Passed() {
43+
if assert.For(t).ThatActualError(err).IsNil().Passed() {
4444
assert.For(t).ThatActual(answer).Equals(42)
4545
}
4646
}

assert/assert.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ type TestContext interface {
2222
// expected to meet certain criteria.
2323
ThatActual(value interface{}) AssertableValue
2424

25+
// ThatActualError adapts the specified error to an assertable one that's
26+
// expected to meet certain criteria.
27+
ThatActualError(value error) AssertableError
28+
2529
// ThatActualString adapts the specified string to an assertable one that's
2630
// expected to meet certain criteria.
27-
// TODO rename to ThatActualString
2831
ThatActualString(value string) AssertableString
2932

3033
// ThatType adapts the specified type to an assertable one that's
@@ -64,6 +67,10 @@ func (testContext *testContext) ThatActual(value interface{}) AssertableValue {
6467
return &assertableValue{testContext: testContext, value: value}
6568
}
6669

70+
func (testContext *testContext) ThatActualError(value error) AssertableError {
71+
return &assertableError{testContext: testContext, value: value}
72+
}
73+
6774
func (testContext *testContext) ThatActualString(value string) AssertableString {
6875
return &assertableString{testContext: testContext, value: value}
6976
}
@@ -82,6 +89,14 @@ func PrintDiff(actual interface{}, expected interface{}) {
8289
pretty.Fdiff(os.Stdout, actual, expected)
8390
}
8491

92+
// PrettyPrint pretty-prints the specified actual and expected values,
93+
// in that order.
94+
func PrettyPrint(actual interface{}, expected interface{}) {
95+
printLock.Lock()
96+
defer printLock.Unlock()
97+
pretty.Printf("Pretty:\nActual: %s\nExpected: %s\n", actual, expected)
98+
}
99+
85100
func (testContext *testContext) decoratedErrorf(format string, args ...interface{}) {
86101
file, line := testContext.caller()
87102
testContext.errorf(file, line, format, args...)

assert/assert_test.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import (
66
"testing"
77
)
88

9+
var (
10+
t = &testing.T{}
11+
)
12+
913
func TestHooksAreHidden(t *testing.T) {
1014
For(t).ThatType(reflect.TypeOf(testContext{})).HidesTestHooks()
1115
}
@@ -22,8 +26,6 @@ func pack(elements ...interface{}) []interface{} {
2226
return elements
2327
}
2428

25-
var t = &testing.T{}
26-
2729
// mockTestContextToAssert mocks a test context to use for assertions.
2830
// The optional parameter(s) can be used to identify a specific test case
2931
// in a data-driven test.

assert/call_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
package assert
22

3-
func ExampleAssertableCall_panicsReportingPass() {
3+
func ExampleAssertableCall_PanicsReporting_pass() {
44
For(t).ThatCalling(func() { panic("error") }).PanicsReporting("error")
55
// Output:
66
}
77

8-
func ExampleAssertableCall_panicsReportingFailPanicDidNotOccur() {
8+
func ExampleAssertableCall_PanicsReporting_panicDidNotOccur() {
99
mockTestContextToAssert().ThatCalling(func() {}).PanicsReporting("expected")
1010
// Output:
1111
// file:3: Function call did not panic as expected.
1212
// Expected: expected
1313
}
1414

15-
func ExampleAssertableCall_panicsReportingFailMessageMismatch() {
15+
func ExampleAssertableCall_PanicsReporting_messageMismatch() {
1616
mockTestContextToAssert().ThatCalling(func() { panic("actual") }).PanicsReporting("expected")
1717
// Output:
1818
// file:3: Panic message mismatch.

assert/error.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package assert
2+
3+
// AssertableError represents an under-test error that's expected to meet
4+
// certain criteria.
5+
type AssertableError interface {
6+
// Equals asserts that the specified actual error equals the expected one.
7+
// Returns a ValueAssertionResult that provides post-assert actions.
8+
Equals(expected error) ValueAssertionResult
9+
10+
// IsNil asserts that the specified actual error is nil.
11+
// Returns a ValueAssertionResult that provides post-assert actions.
12+
IsNil() ValueAssertionResult
13+
14+
// IsNotNil asserts that the specified actual error is not nil.
15+
// Returns a ValueAssertionResult that provides post-assert actions.
16+
IsNotNil() ValueAssertionResult
17+
}
18+
19+
type assertableError struct {
20+
testContext *testContext
21+
value error
22+
}
23+
24+
// ErrorString is a trivial implementation of error. It's useful for asserting
25+
// error messages. For example:
26+
//
27+
// assert.For(t).ThatActualError(err).Equals(assert.ErrorString("foo"))
28+
//
29+
// The assert library compares errors by comapring the output of Error().
30+
type ErrorString string
31+
32+
func (err ErrorString) Error() string {
33+
return string(err)
34+
}
35+
36+
func (actual *assertableError) Equals(expected error) ValueAssertionResult {
37+
if expected == nil {
38+
return actual.IsNil()
39+
}
40+
if actual.value == nil {
41+
actual.testContext.decoratedErrorf("Error mismatch.\nActual was <nil>.\nExpected: %v\n", expected)
42+
return &valueAssertionResult{bool: false, actual: actual.value, expected: expected}
43+
}
44+
// We're comparing interfaces — we only care about what Error() returns for both objects
45+
areEqual := actual.value.Error() == expected.Error()
46+
if !areEqual {
47+
actual.testContext.decoratedErrorf("Error mismatch.\nActual: %s\nExpected: %s\n", actual.value, expected)
48+
}
49+
return &valueAssertionResult{bool: areEqual, actual: actual.value, expected: expected}
50+
}
51+
52+
func (actual *assertableError) IsNil() ValueAssertionResult {
53+
if actual.value != nil {
54+
actual.testContext.decoratedErrorf("Actual error was not <nil>.\nActual: %v\n", actual.value)
55+
}
56+
return &valueAssertionResult{bool: actual.value == nil, actual: actual.value, expected: nil}
57+
}
58+
59+
func (actual *assertableError) IsNotNil() ValueAssertionResult {
60+
if actual.value == nil {
61+
actual.testContext.decoratedErrorf("Actual error was <nil>.\n")
62+
}
63+
return &valueAssertionResult{bool: actual.value != nil, actual: actual.value, expected: &anyOtherValue{}}
64+
}

assert/error_test.go

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package assert
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
)
7+
8+
func ExampleAssertableError_Equals_pass() {
9+
cases := []struct {
10+
id string
11+
actual error
12+
expected error
13+
}{
14+
{"both are nil", nil, nil},
15+
{"same type and message", errors.New("foo"), errors.New("foo")},
16+
{"different struct types, same message", ErrorString("foo"), errors.New("foo")},
17+
}
18+
19+
for _, c := range cases {
20+
if For(t, c.id).ThatActualError(c.actual).Equals(c.expected).Passed() {
21+
fmt.Println("Passed: " + c.id)
22+
}
23+
}
24+
// Output:
25+
// Passed: both are nil
26+
// Passed: same type and message
27+
// Passed: different struct types, same message
28+
}
29+
30+
func ExampleAssertableError_Equals_fail() {
31+
cases := []struct {
32+
id string
33+
actual error
34+
expected error
35+
}{
36+
{"expected is nil while actual isn't", ErrorString("foo"), nil},
37+
{"actual is nil while expected isn't", nil, ErrorString("foo")},
38+
{"different messages", ErrorString("foo"), ErrorString("bar")},
39+
}
40+
41+
for _, c := range cases {
42+
if !mockTestContextToAssert(c.id).ThatActualError(c.actual).Equals(c.expected).Passed() {
43+
fmt.Println("Assertion failed successfully!")
44+
}
45+
}
46+
// Output:
47+
// file:3: [expected is nil while actual isn't] Actual error was not <nil>.
48+
// Actual: foo
49+
// Assertion failed successfully!
50+
// file:3: [actual is nil while expected isn't] Error mismatch.
51+
// Actual was <nil>.
52+
// Expected: foo
53+
// Assertion failed successfully!
54+
// file:3: [different messages] Error mismatch.
55+
// Actual: foo
56+
// Expected: bar
57+
// Assertion failed successfully!
58+
}
59+
60+
func ExampleAssertableError_IsNil_pass() {
61+
if For(t).ThatActualError(nil).IsNil().Passed() {
62+
fmt.Println("Passed!")
63+
}
64+
// Output: Passed!
65+
}
66+
67+
func ExampleAssertableError_IsNil_fail() {
68+
if !mockTestContextToAssert().ThatActualError(errors.New("foo")).IsNil().Passed() {
69+
fmt.Println("Assertion failed successfully!")
70+
}
71+
// Output:
72+
// file:3: Actual error was not <nil>.
73+
// Actual: foo
74+
// Assertion failed successfully!
75+
}
76+
77+
func ExampleAssertableError_IsNotNil_pass() {
78+
if For(t).ThatActualError(errors.New("foo")).IsNotNil().Passed() {
79+
fmt.Println("Passed!")
80+
}
81+
// Output: Passed!
82+
}
83+
84+
func ExampleAssertableError_IsNotNil_fail() {
85+
if !mockTestContextToAssert().ThatActualError(nil).IsNotNil().ThenDiffOnFail().Passed() {
86+
fmt.Println("Assertion failed successfully!")
87+
}
88+
// Output:
89+
// file:3: Actual error was <nil>.
90+
// Diff:
91+
// nil != &assert.anyOtherValue{}
92+
// Assertion failed successfully!
93+
}

assert/result.go

+8
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ type ValueAssertionResult interface {
3333
// Returns the current ValueAssertionResult to allow for call-chaining.
3434
ThenDiffOnFail() ValueAssertionResult
3535

36+
// ThenPrettyPrintOnFail pretty-prints asserted values on assertion failure;
37+
// Returns the current ValueAssertionResult to allow for call-chaining.
38+
ThenPrettyPrintOnFail() ValueAssertionResult
39+
3640
// ThenRunOnFail performed the specified action on assertion failure;
3741
// in which case, it passes the actual and expected values used in
3842
// the failed assertion as parameters to the specified function.
@@ -54,6 +58,10 @@ func (result *valueAssertionResult) ThenDiffOnFail() ValueAssertionResult {
5458
return result.ThenRunOnFail(PrintDiff)
5559
}
5660

61+
func (result *valueAssertionResult) ThenPrettyPrintOnFail() ValueAssertionResult {
62+
return result.ThenRunOnFail(PrettyPrint)
63+
}
64+
5765
func (result *valueAssertionResult) ThenRunOnFail(action func(actual, expected interface{})) ValueAssertionResult {
5866
if !result.Passed() {
5967
action(result.actual, result.expected)

assert/result_test.go

+17-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"net/mail"
66
)
77

8-
func ExampleValueAssertionResult_ThenDiffOnFail_whenAssertionFails() {
8+
func ExampleValueAssertionResult_ThenDiffOnFail_assertionFailed() {
99
address := &mail.Address{Name: "Richard Hendricks", Address: "[email protected]"}
1010
expected := &mail.Address{Name: "Erlich Bachman", Address: "[email protected]"}
1111
mockTestContextToAssert().ThatActual(address).Equals(expected).ThenDiffOnFail()
@@ -18,14 +18,27 @@ func ExampleValueAssertionResult_ThenDiffOnFail_whenAssertionFails() {
1818
1919
}
2020

21-
func ExampleValueAssertionResult_ThenDiffOnFail_whenAssertionPasses() {
21+
func ExampleValueAssertionResult_ThenDiffOnFail_assertionPassed() {
2222
if mockTestContextToAssert().ThatActual(42).Equals(42).ThenDiffOnFail().Passed() {
2323
fmt.Println("Passed!")
2424
}
2525
// Output: Passed!
2626
}
2727

28-
func ExampleValueAssertionResult_ThenRunOnFail_whenAssertionFails() {
28+
func ExampleValueAssertionResult_ThenPrettyPrintOnFail_assertionFailed() {
29+
address := &mail.Address{Name: "Richard Hendricks", Address: "[email protected]"}
30+
expected := &mail.Address{Name: "Erlich Bachman", Address: "[email protected]"}
31+
mockTestContextToAssert().ThatActual(address).Equals(expected).ThenPrettyPrintOnFail()
32+
// Output:
33+
// file:3: Value mismatch.
34+
// Actual: &mail.Address{Name:"Richard Hendricks", Address:"[email protected]"}
35+
// Expected: &mail.Address{Name:"Erlich Bachman", Address:"[email protected]"}
36+
// Pretty:
37+
// Actual: "Richard Hendricks" <[email protected]>
38+
// Expected: "Erlich Bachman" <[email protected]>
39+
}
40+
41+
func ExampleValueAssertionResult_ThenRunOnFail_assertionFailed() {
2942
mockTestContextToAssert().ThatActualString("foo").Equals("bar").ThenRunOnFail(func(actual, expected interface{}) {
3043
fmt.Printf("Custom Message: %q != %q", actual, expected)
3144
})
@@ -36,7 +49,7 @@ func ExampleValueAssertionResult_ThenRunOnFail_whenAssertionFails() {
3649
// Custom Message: "foo" != "bar"
3750
}
3851

39-
func ExampleValueAssertionResult_ThenRunOnFail_whenAssertionPasses() {
52+
func ExampleValueAssertionResult_ThenRunOnFail_assertionPassed() {
4053
panicker := func(actual, expected interface{}) { panic("This should have never run!") }
4154
if mockTestContextToAssert().ThatActual(42).Equals(42).ThenRunOnFail(panicker).Passed() {
4255
fmt.Println("Passed!")

assert/string_test.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ package assert
22

33
import "fmt"
44

5-
func ExampleAssertableString_equalsPass() {
5+
func ExampleAssertableString_Equals_pass() {
66
if For(t).ThatActualString("foo").Equals("foo").Passed() {
77
fmt.Println("Passed!")
88
}
99
// Output: Passed!
1010
}
1111

12-
func ExampleAssertableString_equalsFail() {
12+
func ExampleAssertableString_Equals_fail() {
1313
cases := []struct {
1414
id string
1515
actual string
@@ -40,14 +40,14 @@ func ExampleAssertableString_equalsFail() {
4040
// Assertion failed successfully!
4141
}
4242

43-
func ExampleAssertableValue_isEmptyPass() {
43+
func ExampleAssertableString_IsEmpty_pass() {
4444
if For(t).ThatActualString("").IsEmpty().Passed() {
4545
fmt.Println("Passed!")
4646
}
4747
// Output: Passed!
4848
}
4949

50-
func ExampleAssertableValue_isEmptyFail() {
50+
func ExampleAssertableString_IsEmpty_fail() {
5151
if !mockTestContextToAssert().ThatActualString("foo").IsEmpty().ThenDiffOnFail().Passed() {
5252
fmt.Println("Assertion failed successfully!")
5353
}
@@ -59,14 +59,14 @@ func ExampleAssertableValue_isEmptyFail() {
5959
// Assertion failed successfully!
6060
}
6161

62-
func ExampleAssertableValue_isNotEmptyPass() {
62+
func ExampleAssertableString_IsNotEmpty_pass() {
6363
if For(t).ThatActualString(" ").IsNotEmpty().Passed() {
6464
fmt.Println("Passed!")
6565
}
6666
// Output: Passed!
6767
}
6868

69-
func ExampleAssertableValue_isNotEmptyFail() {
69+
func ExampleAssertableString_IsNotEmpty_fail() {
7070
if !mockTestContextToAssert().ThatActualString("").IsNotEmpty().ThenDiffOnFail().Passed() {
7171
fmt.Println("Assertion failed successfully!")
7272
}

0 commit comments

Comments
 (0)