Skip to content

Commit

Permalink
assert: improve godoc
Browse files Browse the repository at this point in the history
Add examples to godoc that show the failure message.

Improve the failure message for assert.Assert when the argument is an
ast.Ident, or a binary expression.
  • Loading branch information
dnephin committed Apr 15, 2022
1 parent cdc2587 commit 5fe4c1d
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 22 deletions.
45 changes: 31 additions & 14 deletions assert/assert.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
/*Package assert provides assertions for comparing expected values to actual
values. When an assertion fails a helpful error message is printed.
Assert and Check
Assert() and Check() both accept a Comparison, and fail the test when the
comparison fails. The one difference is that Assert() will end the test execution
immediately (using t.FailNow()) whereas Check() will fail the test (using t.Fail()),
return the value of the comparison, then proceed with the rest of the test case.
values in tests. When an assertion fails a helpful error message is printed.
Example usage
The example below shows assert used with some common types.
The example below shows assert used with some common types and the failure
messages it produces.
import (
Expand All @@ -23,30 +17,53 @@ The example below shows assert used with some common types.
func TestEverything(t *testing.T) {
// booleans
assert.Assert(t, ok)
// assertion failed: ok is false
assert.Assert(t, !missing)
// assertion failed: missing is true
// primitives
assert.Equal(t, count, 1)
// assertion failed: 0 (count int) != 1 (int)
assert.Equal(t, msg, "the message")
assert.Assert(t, total != 10) // NotEqual
// assertion failed: my message (msg string) != the message (string)
assert.Assert(t, total != 10) // use Assert for NotEqual
// assertion failed: total is 10
assert.Assert(t, count > 20, "count=%v", count)
// assertion failed: count is <= 20: count=1
// errors
assert.NilError(t, closer.Close())
// assertion failed: error is not nil: close /file: errno 11
assert.Error(t, err, "the exact error message")
// assertion failed: expected error "the exact error message", got "oops"
assert.ErrorContains(t, err, "includes this")
assert.ErrorType(t, err, os.IsNotExist)
// assertion failed: expected error to contain "includes this", got "oops"
assert.ErrorIs(t, err, os.ErrNotExist)
// assertion failed: error is "oops" (err *errors.errorString), not "file does not exist" (os.ErrNotExist *errors.errorString)
// complex types
assert.DeepEqual(t, result, myStruct{Name: "title"})
assert.Assert(t, is.Len(items, 3))
assert.Assert(t, len(sequence) != 0) // NotEmpty
// assertion failed: expected [] (length 0) to have length 3
assert.Assert(t, len(sequence) != 0) // use Assert for NotEmpty
// assertion failed: len(sequence) is 0
assert.Assert(t, is.Contains(mapping, "key"))
// assertion failed: map[other:1] does not contain key
// pointers and interface
assert.Assert(t, is.Nil(ref))
assert.Assert(t, ref != nil) // NotNil
assert.Assert(t, ref == nil)
// assertion failed: ref is not nil
assert.Assert(t, ref != nil) // use Assert for NotNil
// assertion failed: ref is nil
}
Assert and Check
Assert() and Check() both accept a Comparison, and fail the test when the
comparison fails. The one difference is that Assert() will end the test execution
immediately (using t.FailNow()) whereas Check() will fail the test (using t.Fail()),
return the value of the comparison, then proceed with the rest of the test case.
Comparisons
Package http://pkg.go.dev/gotest.tools/v3/assert/cmp provides
Expand Down
46 changes: 40 additions & 6 deletions assert/assert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,46 @@ func (f *fakeTestingT) Log(args ...interface{}) {

func (f *fakeTestingT) Helper() {}

func TestAssertWithBoolFailure(t *testing.T) {
func TestAssert_WithBinaryExpression_Failures(t *testing.T) {
t.Run("equal", func(t *testing.T) {
fakeT := &fakeTestingT{}
Assert(fakeT, 1 == 6)
expectFailNowed(t, fakeT, "assertion failed: 1 is not 6")
})
t.Run("not equal", func(t *testing.T) {
fakeT := &fakeTestingT{}
a := 1
Assert(fakeT, a != 1)
expectFailNowed(t, fakeT, "assertion failed: a is 1")
})
t.Run("greater than", func(t *testing.T) {
fakeT := &fakeTestingT{}
Assert(fakeT, 1 > 5)
expectFailNowed(t, fakeT, "assertion failed: 1 is <= 5")
})
t.Run("less than", func(t *testing.T) {
fakeT := &fakeTestingT{}
Assert(fakeT, 5 < 1)
expectFailNowed(t, fakeT, "assertion failed: 5 is >= 1")
})
t.Run("greater than or equal", func(t *testing.T) {
fakeT := &fakeTestingT{}
Assert(fakeT, 1 >= 5)
expectFailNowed(t, fakeT, "assertion failed: 1 is less than 5")
})
t.Run("less than or equal", func(t *testing.T) {
fakeT := &fakeTestingT{}
Assert(fakeT, 6 <= 2)
expectFailNowed(t, fakeT, "assertion failed: 6 is greater than 2")
})
}

func TestAssertWithBoolIdent(t *testing.T) {
fakeT := &fakeTestingT{}

Assert(fakeT, 1 == 6)
expectFailNowed(t, fakeT, "assertion failed: expression is false: 1 == 6")
var ok bool
Assert(fakeT, ok)
expectFailNowed(t, fakeT, "assertion failed: ok is false")
}

func TestAssertWithBoolFailureNotEqual(t *testing.T) {
Expand All @@ -56,8 +91,7 @@ func TestAssertWithBoolFailureAndExtraMessage(t *testing.T) {
fakeT := &fakeTestingT{}

Assert(fakeT, 1 > 5, "sometimes things fail")
expectFailNowed(t, fakeT,
"assertion failed: expression is false: 1 > 5: sometimes things fail")
expectFailNowed(t, fakeT, "assertion failed: 1 is <= 5: sometimes things fail")
}

func TestAssertWithBoolSuccess(t *testing.T) {
Expand Down Expand Up @@ -187,7 +221,7 @@ func TestCheckFailure(t *testing.T) {
if Check(fakeT, 1 == 2) {
t.Error("expected check to return false on failure")
}
expectFailed(t, fakeT, "assertion failed: expression is false: 1 == 2")
expectFailed(t, fakeT, "assertion failed: 1 is not 2")
}

func TestCheckSuccess(t *testing.T) {
Expand Down
22 changes: 20 additions & 2 deletions internal/assert/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func failureMsgFromError(err error) string {
}

func boolFailureMessage(expr ast.Expr) (string, error) {
if binaryExpr, ok := expr.(*ast.BinaryExpr); ok && binaryExpr.Op == token.NEQ {
if binaryExpr, ok := expr.(*ast.BinaryExpr); ok {
x, err := source.FormatNode(binaryExpr.X)
if err != nil {
return "", err
Expand All @@ -124,7 +124,21 @@ func boolFailureMessage(expr ast.Expr) (string, error) {
if err != nil {
return "", err
}
return x + " is " + y, nil

switch binaryExpr.Op {
case token.NEQ:
return x + " is " + y, nil
case token.EQL:
return x + " is not " + y, nil
case token.GTR:
return x + " is <= " + y, nil
case token.LSS:
return x + " is >= " + y, nil
case token.GEQ:
return x + " is less than " + y, nil
case token.LEQ:
return x + " is greater than " + y, nil
}
}

if unaryExpr, ok := expr.(*ast.UnaryExpr); ok && unaryExpr.Op == token.NOT {
Expand All @@ -135,6 +149,10 @@ func boolFailureMessage(expr ast.Expr) (string, error) {
return x + " is true", nil
}

if ident, ok := expr.(*ast.Ident); ok {
return ident.Name + " is false", nil
}

formatted, err := source.FormatNode(expr)
if err != nil {
return "", err
Expand Down

0 comments on commit 5fe4c1d

Please sign in to comment.