pull/171/head
Antonio Nicolás Pina 2015-11-20 13:19:13 +02:00
commit 384cc6617a
18 changed files with 1406 additions and 494 deletions

View File

@ -4,6 +4,8 @@ go:
- 1.1 - 1.1
- 1.2 - 1.2
- 1.3 - 1.3
- 1.4
- 1.5
- tip - tip
script: script:

View File

@ -15,7 +15,7 @@ Features include:
Get started: Get started:
* Install testify with [one line of code](#installation), or [update it with another](#staying-up-to-date) * Install testify with [one line of code](#installation), or [update it with another](#staying-up-to-date)
* For an introduction to writing test code in Go, see our [blog post article](http://blog.stretchr.com/2014/03/05/test-driven-development-specifically-in-golang/) or check out http://golang.org/doc/code.html#Testing * For an introduction to writing test code in Go, see http://golang.org/doc/code.html#Testing
* Check out the API Documentation http://godoc.org/github.com/stretchr/testify * Check out the API Documentation http://godoc.org/github.com/stretchr/testify
* To make your testing life easier, check out our other project, [gorc](http://github.com/stretchr/gorc) * To make your testing life easier, check out our other project, [gorc](http://github.com/stretchr/gorc)
* A little about [Test-Driven Development (TDD)](http://en.wikipedia.org/wiki/Test-driven_development) * A little about [Test-Driven Development (TDD)](http://en.wikipedia.org/wiki/Test-driven_development)
@ -99,8 +99,8 @@ func TestSomething(t *testing.T) {
} }
``` ```
`require` package [`require`](http://godoc.org/github.com/stretchr/testify/require "API documentation") package
------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------
The `require` package provides same global functions as the `assert` package, but instead of returning a boolean result they terminate current test. The `require` package provides same global functions as the `assert` package, but instead of returning a boolean result they terminate current test.
@ -212,7 +212,7 @@ func (suite *ExampleTestSuite) SetupTest() {
// All methods that begin with "Test" are run as tests within a // All methods that begin with "Test" are run as tests within a
// suite. // suite.
func (suite *ExampleTestSuite) TestExample() { func (suite *ExampleTestSuite) TestExample() {
assert.Equal(suite.T(), suite.VariableThatShouldStartAtFive, 5) assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
} }
// In order for 'go test' to run this suite, we need to create // In order for 'go test' to run this suite, we need to create
@ -268,7 +268,8 @@ Installation
To install Testify, use `go get`: To install Testify, use `go get`:
go get github.com/stretchr/testify * Latest version: go get github.com/stretchr/testify
* Specific version: go get gopkg.in/stretchr/testify.v1
This will then make the following packages available to you: This will then make the following packages available to you:
@ -298,9 +299,14 @@ func TestSomething(t *testing.T) {
Staying up to date Staying up to date
================== ==================
To update Testify, use `go get -u`: To update Testify to the latest version, use `go get -u github.com/stretchr/testify`.
go get -u github.com/stretchr/testify ------
Version History
===============
* 1.0 - New package versioning strategy adopted.
------ ------

View File

@ -3,6 +3,7 @@ package assert
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"math" "math"
"reflect" "reflect"
@ -10,6 +11,11 @@ import (
"runtime" "runtime"
"strings" "strings"
"time" "time"
"unicode"
"unicode/utf8"
"github.com/davecgh/go-spew/spew"
"github.com/pmezard/go-difflib/difflib"
) )
// TestingT is an interface wrapper around *testing.T // TestingT is an interface wrapper around *testing.T
@ -33,11 +39,7 @@ func ObjectsAreEqual(expected, actual interface{}) bool {
return expected == actual return expected == actual
} }
if reflect.DeepEqual(expected, actual) { return reflect.DeepEqual(expected, actual)
return true
}
return false
} }
@ -49,12 +51,13 @@ func ObjectsAreEqualValues(expected, actual interface{}) bool {
} }
actualType := reflect.TypeOf(actual) actualType := reflect.TypeOf(actual)
expectedValue := reflect.ValueOf(expected) if actualType == nil {
if expectedValue.Type().ConvertibleTo(actualType) { return false
// Attempt comparison after type conversion
if reflect.DeepEqual(actual, expectedValue.Convert(actualType).Interface()) {
return true
} }
expectedValue := reflect.ValueOf(expected)
if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
// Attempt comparison after type conversion
return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
} }
return false return false
@ -64,28 +67,67 @@ func ObjectsAreEqualValues(expected, actual interface{}) bool {
internally, causing it to print the file:line of the assert method, rather than where internally, causing it to print the file:line of the assert method, rather than where
the problem actually occured in calling code.*/ the problem actually occured in calling code.*/
// CallerInfo returns a string containing the file and line number of the assert call // CallerInfo returns an array of strings containing the file and line number
// that failed. // of each stack frame leading from the current test to the assert call that
func CallerInfo() string { // failed.
func CallerInfo() []string {
pc := uintptr(0)
file := "" file := ""
line := 0 line := 0
ok := false ok := false
name := ""
callers := []string{}
for i := 0; ; i++ { for i := 0; ; i++ {
_, file, line, ok = runtime.Caller(i) pc, file, line, ok = runtime.Caller(i)
if !ok { if !ok {
return "" return nil
} }
// This is a huge edge case, but it will panic if this is the case, see #180
if file == "<autogenerated>" {
break
}
parts := strings.Split(file, "/") parts := strings.Split(file, "/")
dir := parts[len(parts)-2] dir := parts[len(parts)-2]
file = parts[len(parts)-1] file = parts[len(parts)-1]
if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" { if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" {
callers = append(callers, fmt.Sprintf("%s:%d", file, line))
}
f := runtime.FuncForPC(pc)
if f == nil {
break
}
name = f.Name()
// Drop the package
segments := strings.Split(name, ".")
name = segments[len(segments)-1]
if isTest(name, "Test") ||
isTest(name, "Benchmark") ||
isTest(name, "Example") {
break break
} }
} }
return fmt.Sprintf("%s:%d", file, line) return callers
}
// Stolen from the `go test` tool.
// isTest tells whether name looks like a test (or benchmark, according to prefix).
// It is a Test (say) if there is a character after Test that is not a lower-case letter.
// We don't want TesticularCancer.
func isTest(name, prefix string) bool {
if !strings.HasPrefix(name, prefix) {
return false
}
if len(name) == len(prefix) { // "Test" is ok
return true
}
rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
return !unicode.IsLower(rune)
} }
// getWhitespaceString returns a string that is long enough to overwrite the default // getWhitespaceString returns a string that is long enough to overwrite the default
@ -144,19 +186,20 @@ func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
message := messageFromMsgAndArgs(msgAndArgs...) message := messageFromMsgAndArgs(msgAndArgs...)
errorTrace := strings.Join(CallerInfo(), "\n\r\t\t\t")
if len(message) > 0 { if len(message) > 0 {
t.Errorf("\r%s\r\tLocation:\t%s\n"+ t.Errorf("\r%s\r\tError Trace:\t%s\n"+
"\r\tError:%s\n"+ "\r\tError:%s\n"+
"\r\tMessages:\t%s\n\r", "\r\tMessages:\t%s\n\r",
getWhitespaceString(), getWhitespaceString(),
CallerInfo(), errorTrace,
indentMessageLines(failureMessage, 2), indentMessageLines(failureMessage, 2),
message) message)
} else { } else {
t.Errorf("\r%s\r\tLocation:\t%s\n"+ t.Errorf("\r%s\r\tError Trace:\t%s\n"+
"\r\tError:%s\n\r", "\r\tError:%s\n\r",
getWhitespaceString(), getWhitespaceString(),
CallerInfo(), errorTrace,
indentMessageLines(failureMessage, 2)) indentMessageLines(failureMessage, 2))
} }
@ -171,7 +214,7 @@ func Implements(t TestingT, interfaceObject interface{}, object interface{}, msg
interfaceType := reflect.TypeOf(interfaceObject).Elem() interfaceType := reflect.TypeOf(interfaceObject).Elem()
if !reflect.TypeOf(object).Implements(interfaceType) { if !reflect.TypeOf(object).Implements(interfaceType) {
return Fail(t, fmt.Sprintf("Object must implement %v", interfaceType), msgAndArgs...) return Fail(t, fmt.Sprintf("%T must implement %v", object, interfaceType), msgAndArgs...)
} }
return true return true
@ -196,8 +239,9 @@ func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if !ObjectsAreEqual(expected, actual) { if !ObjectsAreEqual(expected, actual) {
diff := diff(expected, actual)
return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+ return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+
" != %#v (actual)", expected, actual), msgAndArgs...) " != %#v (actual)%s", expected, actual, diff), msgAndArgs...)
} }
return true return true
@ -232,7 +276,7 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
bType := reflect.TypeOf(actual) bType := reflect.TypeOf(actual)
if aType != bType { if aType != bType {
return Fail(t, "Types expected to match exactly", "%v != %v", aType, bType) return Fail(t, fmt.Sprintf("Types expected to match exactly\n\r\t%v != %v", aType, bType), msgAndArgs...)
} }
return Equal(t, expected, actual, msgAndArgs...) return Equal(t, expected, actual, msgAndArgs...)
@ -245,24 +289,10 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if !isNil(object) {
success := true return true
if object == nil {
success = false
} else {
value := reflect.ValueOf(object)
kind := value.Kind()
if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() {
success = false
} }
} return Fail(t, "Expected value not to be nil.", msgAndArgs...)
if !success {
Fail(t, "Expected not to be nil.", msgAndArgs...)
}
return success
} }
// isNil checks if a specified object is nil or not, without Failing. // isNil checks if a specified object is nil or not, without Failing.
@ -292,7 +322,7 @@ func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...) return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
} }
var zeros = []interface{}{ var numericZeros = []interface{}{
int(0), int(0),
int8(0), int8(0),
int16(0), int16(0),
@ -318,7 +348,7 @@ func isEmpty(object interface{}) bool {
return true return true
} }
for _, v := range zeros { for _, v := range numericZeros {
if object == v { if object == v {
return true return true
} }
@ -335,6 +365,9 @@ func isEmpty(object interface{}) bool {
} }
case reflect.Ptr: case reflect.Ptr:
{ {
if objValue.IsNil() {
return true
}
switch object.(type) { switch object.(type) {
case *time.Time: case *time.Time:
return object.(*time.Time).IsZero() return object.(*time.Time).IsZero()
@ -450,7 +483,7 @@ func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if ObjectsAreEqual(expected, actual) { if ObjectsAreEqual(expected, actual) {
return Fail(t, "Should not be equal", msgAndArgs...) return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
} }
return true return true
@ -476,6 +509,16 @@ func includeElement(list interface{}, element interface{}) (ok, found bool) {
return true, strings.Contains(listValue.String(), elementValue.String()) return true, strings.Contains(listValue.String(), elementValue.String())
} }
if reflect.TypeOf(list).Kind() == reflect.Map {
mapKeys := listValue.MapKeys()
for i := 0; i < len(mapKeys); i++ {
if ObjectsAreEqual(mapKeys[i].Interface(), element) {
return true, true
}
}
return true, false
}
for i := 0; i < listValue.Len(); i++ { for i := 0; i < listValue.Len(); i++ {
if ObjectsAreEqual(listValue.Index(i).Interface(), element) { if ObjectsAreEqual(listValue.Index(i).Interface(), element) {
return true, true return true, true
@ -485,11 +528,12 @@ func includeElement(list interface{}, element interface{}) (ok, found bool) {
} }
// Contains asserts that the specified string or list(array, slice...) contains the // Contains asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element. // specified substring or element.
// //
// assert.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'") // assert.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
// assert.Contains(t, ["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'") // assert.Contains(t, ["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'")
// assert.Contains(t, {"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
@ -506,11 +550,12 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo
} }
// NotContains asserts that the specified string or list(array, slice...) does NOT contain the // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element. // specified substring or element.
// //
// assert.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'") // assert.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
// assert.NotContains(t, ["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'") // assert.NotContains(t, ["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'")
// assert.NotContains(t, {"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
@ -766,7 +811,7 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
return true return true
} }
return Fail(t, fmt.Sprintf("No error is expected but got %v", err), msgAndArgs...) return Fail(t, fmt.Sprintf("Received unexpected error %q", err), msgAndArgs...)
} }
// Error asserts that a function returned an error (i.e. not `nil`). // Error asserts that a function returned an error (i.e. not `nil`).
@ -800,7 +845,7 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte
return false return false
} }
s := "An error with value \"%s\" is expected but got \"%s\". %s" s := "An error with value \"%s\" is expected but got \"%s\". %s"
return Equal(t, theError.Error(), errString, return Equal(t, errString, theError.Error(),
s, errString, theError.Error(), message) s, errString, theError.Error(), message)
} }
@ -851,3 +896,84 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf
return !match return !match
} }
// Zero asserts that i is the zero value for its type and returns the truth.
func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...)
}
return true
}
// NotZero asserts that i is not the zero value for its type and returns the truth.
func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...)
}
return true
}
// JSONEq asserts that two JSON strings are equivalent.
//
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
//
// Returns whether the assertion was successful (true) or not (false).
func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
var expectedJSONAsInterface, actualJSONAsInterface interface{}
if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil {
return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...)
}
if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil {
return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...)
}
return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
}
func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
t := reflect.TypeOf(v)
k := t.Kind()
if k == reflect.Ptr {
t = t.Elem()
k = t.Kind()
}
return t, k
}
// diff returns a diff of both values as long as both are of the same type and
// are a struct, map, slice or array. Otherwise it returns an empty string.
func diff(expected interface{}, actual interface{}) string {
if expected == nil || actual == nil {
return ""
}
et, ek := typeAndKind(expected)
at, _ := typeAndKind(actual)
if et != at {
return ""
}
if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array {
return ""
}
spew.Config.SortKeys = true
e := spew.Sdump(expected)
a := spew.Sdump(actual)
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
A: difflib.SplitLines(e),
B: difflib.SplitLines(a),
FromFile: "Expected",
FromDate: "",
ToFile: "Actual",
ToDate: "",
Context: 1,
})
return "\n\nDiff:\n" + diff
}

View File

@ -2,12 +2,82 @@ package assert
import ( import (
"errors" "errors"
"io"
"math" "math"
"os"
"reflect"
"regexp" "regexp"
"testing" "testing"
"time" "time"
) )
var (
i interface{}
zeros = []interface{}{
false,
byte(0),
complex64(0),
complex128(0),
float32(0),
float64(0),
int(0),
int8(0),
int16(0),
int32(0),
int64(0),
rune(0),
uint(0),
uint8(0),
uint16(0),
uint32(0),
uint64(0),
uintptr(0),
"",
[0]interface{}{},
[]interface{}(nil),
struct{ x int }{},
(*interface{})(nil),
(func())(nil),
nil,
interface{}(nil),
map[interface{}]interface{}(nil),
(chan interface{})(nil),
(<-chan interface{})(nil),
(chan<- interface{})(nil),
}
nonZeros = []interface{}{
true,
byte(1),
complex64(1),
complex128(1),
float32(1),
float64(1),
int(1),
int8(1),
int16(1),
int32(1),
int64(1),
rune(1),
uint(1),
uint8(1),
uint16(1),
uint32(1),
uint64(1),
uintptr(1),
"s",
[1]interface{}{1},
[]interface{}{},
struct{ x int }{1},
(*interface{})(&i),
(func())(func() {}),
interface{}(1),
map[interface{}]interface{}{},
(chan interface{})(make(chan interface{})),
(<-chan interface{})(make(chan interface{})),
(chan<- interface{})(make(chan interface{})),
}
)
// AssertionTesterInterface defines an interface to be used for testing assertion methods // AssertionTesterInterface defines an interface to be used for testing assertion methods
type AssertionTesterInterface interface { type AssertionTesterInterface interface {
TestMethod() TestMethod()
@ -62,6 +132,12 @@ func TestObjectsAreEqual(t *testing.T) {
if !ObjectsAreEqualValues(uint32(10), int32(10)) { if !ObjectsAreEqualValues(uint32(10), int32(10)) {
t.Error("ObjectsAreEqualValues should return true") t.Error("ObjectsAreEqualValues should return true")
} }
if ObjectsAreEqualValues(0, nil) {
t.Fail()
}
if ObjectsAreEqualValues(nil, 0) {
t.Fail()
}
} }
@ -129,6 +205,9 @@ func TestNotNil(t *testing.T) {
if NotNil(mockT, nil) { if NotNil(mockT, nil) {
t.Error("NotNil should return false: object is nil") t.Error("NotNil should return false: object is nil")
} }
if NotNil(mockT, (*struct{})(nil)) {
t.Error("NotNil should return false: object is (*struct{})(nil)")
}
} }
@ -139,6 +218,9 @@ func TestNil(t *testing.T) {
if !Nil(mockT, nil) { if !Nil(mockT, nil) {
t.Error("Nil should return true: object is nil") t.Error("Nil should return true: object is nil")
} }
if !Nil(mockT, (*struct{})(nil)) {
t.Error("Nil should return true: object is (*struct{})(nil)")
}
if Nil(mockT, new(AssertionTesterConformingObject)) { if Nil(mockT, new(AssertionTesterConformingObject)) {
t.Error("Nil should return false: object is not nil") t.Error("Nil should return false: object is not nil")
} }
@ -255,6 +337,7 @@ func TestContains(t *testing.T) {
{"g", "h"}, {"g", "h"},
{"j", "k"}, {"j", "k"},
} }
simpleMap := map[interface{}]interface{}{"Foo": "Bar"}
if !Contains(mockT, "Hello World", "Hello") { if !Contains(mockT, "Hello World", "Hello") {
t.Error("Contains should return true: \"Hello World\" contains \"Hello\"") t.Error("Contains should return true: \"Hello World\" contains \"Hello\"")
@ -275,12 +358,22 @@ func TestContains(t *testing.T) {
if Contains(mockT, complexList, &A{"g", "e"}) { if Contains(mockT, complexList, &A{"g", "e"}) {
t.Error("Contains should return false: complexList contains {\"g\", \"e\"}") t.Error("Contains should return false: complexList contains {\"g\", \"e\"}")
} }
if Contains(mockT, complexList, &A{"g", "e"}) {
t.Error("Contains should return false: complexList contains {\"g\", \"e\"}")
}
if !Contains(mockT, simpleMap, "Foo") {
t.Error("Contains should return true: \"{\"Foo\": \"Bar\"}\" contains \"Foo\"")
}
if Contains(mockT, simpleMap, "Bar") {
t.Error("Contains should return false: \"{\"Foo\": \"Bar\"}\" does not contains \"Bar\"")
}
} }
func TestNotContains(t *testing.T) { func TestNotContains(t *testing.T) {
mockT := new(testing.T) mockT := new(testing.T)
list := []string{"Foo", "Bar"} list := []string{"Foo", "Bar"}
simpleMap := map[interface{}]interface{}{"Foo": "Bar"}
if !NotContains(mockT, "Hello World", "Hello!") { if !NotContains(mockT, "Hello World", "Hello!") {
t.Error("NotContains should return true: \"Hello World\" does not contain \"Hello!\"") t.Error("NotContains should return true: \"Hello World\" does not contain \"Hello!\"")
@ -295,13 +388,19 @@ func TestNotContains(t *testing.T) {
if NotContains(mockT, list, "Foo") { if NotContains(mockT, list, "Foo") {
t.Error("NotContains should return false: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"") t.Error("NotContains should return false: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"")
} }
if NotContains(mockT, simpleMap, "Foo") {
t.Error("Contains should return true: \"{\"Foo\": \"Bar\"}\" contains \"Foo\"")
}
if !NotContains(mockT, simpleMap, "Bar") {
t.Error("Contains should return false: \"{\"Foo\": \"Bar\"}\" does not contains \"Bar\"")
}
} }
func Test_includeElement(t *testing.T) { func Test_includeElement(t *testing.T) {
list1 := []string{"Foo", "Bar"} list1 := []string{"Foo", "Bar"}
list2 := []int{1, 2} list2 := []int{1, 2}
simpleMap := map[interface{}]interface{}{"Foo": "Bar"}
ok, found := includeElement("Hello World", "World") ok, found := includeElement("Hello World", "World")
True(t, ok) True(t, ok)
@ -335,10 +434,17 @@ func Test_includeElement(t *testing.T) {
True(t, ok) True(t, ok)
False(t, found) False(t, found)
ok, found = includeElement(simpleMap, "Foo")
True(t, ok)
True(t, found)
ok, found = includeElement(simpleMap, "Bar")
True(t, ok)
False(t, found)
ok, found = includeElement(1433, "1") ok, found = includeElement(1433, "1")
False(t, ok) False(t, ok)
False(t, found) False(t, found)
} }
func TestCondition(t *testing.T) { func TestCondition(t *testing.T) {
@ -481,6 +587,9 @@ func TestEmpty(t *testing.T) {
mockT := new(testing.T) mockT := new(testing.T)
chWithValue := make(chan struct{}, 1) chWithValue := make(chan struct{}, 1)
chWithValue <- struct{}{} chWithValue <- struct{}{}
var ti *time.Time
var s *string
var f *os.File
True(t, Empty(mockT, ""), "Empty string is empty") True(t, Empty(mockT, ""), "Empty string is empty")
True(t, Empty(mockT, nil), "Nil is empty") True(t, Empty(mockT, nil), "Nil is empty")
@ -488,6 +597,9 @@ func TestEmpty(t *testing.T) {
True(t, Empty(mockT, 0), "Zero int value is empty") True(t, Empty(mockT, 0), "Zero int value is empty")
True(t, Empty(mockT, false), "False value is empty") True(t, Empty(mockT, false), "False value is empty")
True(t, Empty(mockT, make(chan struct{})), "Channel without values is empty") True(t, Empty(mockT, make(chan struct{})), "Channel without values is empty")
True(t, Empty(mockT, s), "Nil string pointer is empty")
True(t, Empty(mockT, f), "Nil os.File pointer is empty")
True(t, Empty(mockT, ti), "Nil time.Time pointer is empty")
False(t, Empty(mockT, "something"), "Non Empty string is not empty") False(t, Empty(mockT, "something"), "Non Empty string is not empty")
False(t, Empty(mockT, errors.New("something")), "Non nil object is not empty") False(t, Empty(mockT, errors.New("something")), "Non nil object is not empty")
@ -789,3 +901,189 @@ func TestRegexp(t *testing.T) {
True(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str)) True(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
} }
} }
func testAutogeneratedFunction() {
defer func() {
if err := recover(); err == nil {
panic("did not panic")
}
CallerInfo()
}()
t := struct {
io.Closer
}{}
var c io.Closer
c = t
c.Close()
}
func TestCallerInfoWithAutogeneratedFunctions(t *testing.T) {
NotPanics(t, func() {
testAutogeneratedFunction()
})
}
func TestZero(t *testing.T) {
mockT := new(testing.T)
for _, test := range zeros {
True(t, Zero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test)))
}
for _, test := range nonZeros {
False(t, Zero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test)))
}
}
func TestNotZero(t *testing.T) {
mockT := new(testing.T)
for _, test := range zeros {
False(t, NotZero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test)))
}
for _, test := range nonZeros {
True(t, NotZero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test)))
}
}
func TestJSONEq_EqualSONString(t *testing.T) {
mockT := new(testing.T)
True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`))
}
func TestJSONEq_EquivalentButNotEqual(t *testing.T) {
mockT := new(testing.T)
True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`))
}
func TestJSONEq_HashOfArraysAndHashes(t *testing.T) {
mockT := new(testing.T)
True(t, JSONEq(mockT, "{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
"{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}"))
}
func TestJSONEq_Array(t *testing.T) {
mockT := new(testing.T)
True(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`))
}
func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) {
mockT := new(testing.T)
False(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`))
}
func TestJSONEq_HashesNotEquivalent(t *testing.T) {
mockT := new(testing.T)
False(t, JSONEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`))
}
func TestJSONEq_ActualIsNotJSON(t *testing.T) {
mockT := new(testing.T)
False(t, JSONEq(mockT, `{"foo": "bar"}`, "Not JSON"))
}
func TestJSONEq_ExpectedIsNotJSON(t *testing.T) {
mockT := new(testing.T)
False(t, JSONEq(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`))
}
func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) {
mockT := new(testing.T)
False(t, JSONEq(mockT, "Not JSON", "Not JSON"))
}
func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) {
mockT := new(testing.T)
False(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`))
}
func TestDiff(t *testing.T) {
expected := `
Diff:
--- Expected
+++ Actual
@@ -1,3 +1,3 @@
(struct { foo string }) {
- foo: (string) (len=5) "hello"
+ foo: (string) (len=3) "bar"
}
`
actual := diff(
struct{ foo string }{"hello"},
struct{ foo string }{"bar"},
)
Equal(t, expected, actual)
expected = `
Diff:
--- Expected
+++ Actual
@@ -2,5 +2,5 @@
(int) 1,
- (int) 2,
(int) 3,
- (int) 4
+ (int) 5,
+ (int) 7
}
`
actual = diff(
[]int{1, 2, 3, 4},
[]int{1, 3, 5, 7},
)
Equal(t, expected, actual)
expected = `
Diff:
--- Expected
+++ Actual
@@ -2,4 +2,4 @@
(int) 1,
- (int) 2,
- (int) 3
+ (int) 3,
+ (int) 5
}
`
actual = diff(
[]int{1, 2, 3, 4}[0:3],
[]int{1, 3, 5, 7}[0:3],
)
Equal(t, expected, actual)
expected = `
Diff:
--- Expected
+++ Actual
@@ -1,6 +1,6 @@
(map[string]int) (len=4) {
- (string) (len=4) "four": (int) 4,
+ (string) (len=4) "five": (int) 5,
(string) (len=3) "one": (int) 1,
- (string) (len=5) "three": (int) 3,
- (string) (len=3) "two": (int) 2
+ (string) (len=5) "seven": (int) 7,
+ (string) (len=5) "three": (int) 3
}
`
actual = diff(
map[string]int{"one": 1, "two": 2, "three": 3, "four": 4},
map[string]int{"one": 1, "three": 3, "five": 5, "seven": 7},
)
Equal(t, expected, actual)
}
func TestDiffEmptyCases(t *testing.T) {
Equal(t, "", diff(nil, nil))
Equal(t, "", diff(struct{ foo string }{}, nil))
Equal(t, "", diff(nil, struct{ foo string }{}))
Equal(t, "", diff(1, 2))
Equal(t, "", diff(1, 2))
Equal(t, "", diff([]int{1}, []bool{true}))
}

View File

@ -17,7 +17,7 @@
// //
// } // }
// //
// if you assert many times, use the below: // if you assert many times, use the format below:
// //
// import ( // import (
// "testing" // "testing"
@ -42,113 +42,4 @@
// //
// Every assertion function also takes an optional string message as the final argument, // Every assertion function also takes an optional string message as the final argument,
// allowing custom error messages to be appended to the message the assertion method outputs. // allowing custom error messages to be appended to the message the assertion method outputs.
//
// Here is an overview of the assert functions:
//
// assert.Equal(t, expected, actual [, message [, format-args]])
//
// assert.EqualValues(t, expected, actual [, message [, format-args]])
//
// assert.NotEqual(t, notExpected, actual [, message [, format-args]])
//
// assert.True(t, actualBool [, message [, format-args]])
//
// assert.False(t, actualBool [, message [, format-args]])
//
// assert.Nil(t, actualObject [, message [, format-args]])
//
// assert.NotNil(t, actualObject [, message [, format-args]])
//
// assert.Empty(t, actualObject [, message [, format-args]])
//
// assert.NotEmpty(t, actualObject [, message [, format-args]])
//
// assert.Len(t, actualObject, expectedLength, [, message [, format-args]])
//
// assert.Error(t, errorObject [, message [, format-args]])
//
// assert.NoError(t, errorObject [, message [, format-args]])
//
// assert.EqualError(t, theError, errString [, message [, format-args]])
//
// assert.Implements(t, (*MyInterface)(nil), new(MyObject) [,message [, format-args]])
//
// assert.IsType(t, expectedObject, actualObject [, message [, format-args]])
//
// assert.Contains(t, stringOrSlice, substringOrElement [, message [, format-args]])
//
// assert.NotContains(t, stringOrSlice, substringOrElement [, message [, format-args]])
//
// assert.Panics(t, func(){
//
// // call code that should panic
//
// } [, message [, format-args]])
//
// assert.NotPanics(t, func(){
//
// // call code that should not panic
//
// } [, message [, format-args]])
//
// assert.WithinDuration(t, timeA, timeB, deltaTime, [, message [, format-args]])
//
// assert.InDelta(t, numA, numB, delta, [, message [, format-args]])
//
// assert.InEpsilon(t, numA, numB, epsilon, [, message [, format-args]])
//
// assert package contains Assertions object. it has assertion methods.
//
// Here is an overview of the assert functions:
// assert.Equal(expected, actual [, message [, format-args]])
//
// assert.EqualValues(expected, actual [, message [, format-args]])
//
// assert.NotEqual(notExpected, actual [, message [, format-args]])
//
// assert.True(actualBool [, message [, format-args]])
//
// assert.False(actualBool [, message [, format-args]])
//
// assert.Nil(actualObject [, message [, format-args]])
//
// assert.NotNil(actualObject [, message [, format-args]])
//
// assert.Empty(actualObject [, message [, format-args]])
//
// assert.NotEmpty(actualObject [, message [, format-args]])
//
// assert.Len(actualObject, expectedLength, [, message [, format-args]])
//
// assert.Error(errorObject [, message [, format-args]])
//
// assert.NoError(errorObject [, message [, format-args]])
//
// assert.EqualError(theError, errString [, message [, format-args]])
//
// assert.Implements((*MyInterface)(nil), new(MyObject) [,message [, format-args]])
//
// assert.IsType(expectedObject, actualObject [, message [, format-args]])
//
// assert.Contains(stringOrSlice, substringOrElement [, message [, format-args]])
//
// assert.NotContains(stringOrSlice, substringOrElement [, message [, format-args]])
//
// assert.Panics(func(){
//
// // call code that should panic
//
// } [, message [, format-args]])
//
// assert.NotPanics(func(){
//
// // call code that should not panic
//
// } [, message [, format-args]])
//
// assert.WithinDuration(timeA, timeB, deltaTime, [, message [, format-args]])
//
// assert.InDelta(numA, numB, delta, [, message [, format-args]])
//
// assert.InEpsilon(numA, numB, epsilon, [, message [, format-args]])
package assert package assert

View File

@ -263,3 +263,22 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
return NotRegexp(a.t, rx, str, msgAndArgs...) return NotRegexp(a.t, rx, str, msgAndArgs...)
} }
// Zero asserts that i is the zero value for its type and returns the truth.
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
return Zero(a.t, i, msgAndArgs...)
}
// NotZero asserts that i is not the zero value for its type and returns the truth.
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {
return NotZero(a.t, i, msgAndArgs...)
}
// JSONEq asserts that two JSON strings are equivalent.
//
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {
return JSONEq(a.t, expected, actual, msgAndArgs...)
}

View File

@ -509,3 +509,103 @@ func TestRegexpWrapper(t *testing.T) {
True(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str)) True(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))
} }
} }
func TestZeroWrapper(t *testing.T) {
assert := New(t)
mockAssert := New(new(testing.T))
for _, test := range zeros {
assert.True(mockAssert.Zero(test), "Zero should return true for %v", test)
}
for _, test := range nonZeros {
assert.False(mockAssert.Zero(test), "Zero should return false for %v", test)
}
}
func TestNotZeroWrapper(t *testing.T) {
assert := New(t)
mockAssert := New(new(testing.T))
for _, test := range zeros {
assert.False(mockAssert.NotZero(test), "Zero should return true for %v", test)
}
for _, test := range nonZeros {
assert.True(mockAssert.NotZero(test), "Zero should return false for %v", test)
}
}
func TestJSONEqWrapper_EqualSONString(t *testing.T) {
assert := New(new(testing.T))
if !assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) {
t.Error("JSONEq should return true")
}
}
func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) {
assert := New(new(testing.T))
if !assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) {
t.Error("JSONEq should return true")
}
}
func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) {
assert := New(new(testing.T))
if !assert.JSONEq("{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
"{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}") {
t.Error("JSONEq should return true")
}
}
func TestJSONEqWrapper_Array(t *testing.T) {
assert := New(new(testing.T))
if !assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) {
t.Error("JSONEq should return true")
}
}
func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
assert := New(new(testing.T))
if assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) {
t.Error("JSONEq should return false")
}
}
func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) {
assert := New(new(testing.T))
if assert.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) {
t.Error("JSONEq should return false")
}
}
func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) {
assert := New(new(testing.T))
if assert.JSONEq(`{"foo": "bar"}`, "Not JSON") {
t.Error("JSONEq should return false")
}
}
func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) {
assert := New(new(testing.T))
if assert.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`) {
t.Error("JSONEq should return false")
}
}
func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) {
assert := New(new(testing.T))
if assert.JSONEq("Not JSON", "Not JSON") {
t.Error("JSONEq should return false")
}
}
func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) {
assert := New(new(testing.T))
if assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`) {
t.Error("JSONEq should return false")
}
}

View File

@ -10,9 +10,9 @@ import (
// httpCode is a helper that returns HTTP code of the response. It returns -1 // httpCode is a helper that returns HTTP code of the response. It returns -1
// if building a new request fails. // if building a new request fails.
func httpCode(handler http.HandlerFunc, mode, url string, values url.Values) int { func httpCode(handler http.HandlerFunc, method, url string, values url.Values) int {
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest(mode, url+"?"+values.Encode(), nil) req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
if err != nil { if err != nil {
return -1 return -1
} }
@ -25,8 +25,8 @@ func httpCode(handler http.HandlerFunc, mode, url string, values url.Values) int
// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) // assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPSuccess(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool { func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {
code := httpCode(handler, mode, url, values) code := httpCode(handler, method, url, values)
if code == -1 { if code == -1 {
return false return false
} }
@ -38,8 +38,8 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, mode, url string, values
// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPRedirect(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool { func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {
code := httpCode(handler, mode, url, values) code := httpCode(handler, method, url, values)
if code == -1 { if code == -1 {
return false return false
} }
@ -51,8 +51,8 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, mode, url string, values
// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPError(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool { func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {
code := httpCode(handler, mode, url, values) code := httpCode(handler, method, url, values)
if code == -1 { if code == -1 {
return false return false
} }
@ -61,9 +61,9 @@ func HTTPError(t TestingT, handler http.HandlerFunc, mode, url string, values ur
// HTTPBody is a helper that returns HTTP body of the response. It returns // HTTPBody is a helper that returns HTTP body of the response. It returns
// empty string if building a new request fails. // empty string if building a new request fails.
func HTTPBody(handler http.HandlerFunc, mode, url string, values url.Values) string { func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest(mode, url+"?"+values.Encode(), nil) req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
if err != nil { if err != nil {
return "" return ""
} }
@ -77,8 +77,8 @@ func HTTPBody(handler http.HandlerFunc, mode, url string, values url.Values) str
// assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") // assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool { func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {
body := HTTPBody(handler, mode, url, values) body := HTTPBody(handler, method, url, values)
contains := strings.Contains(body, fmt.Sprint(str)) contains := strings.Contains(body, fmt.Sprint(str))
if !contains { if !contains {
@ -94,8 +94,8 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, mode, url string, va
// assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") // assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool { func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {
body := HTTPBody(handler, mode, url, values) body := HTTPBody(handler, method, url, values)
contains := strings.Contains(body, fmt.Sprint(str)) contains := strings.Contains(body, fmt.Sprint(str))
if contains { if contains {
@ -114,8 +114,8 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, mode, url string,
// assert.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) // assert.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, mode, url string, values url.Values) bool { func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method, url string, values url.Values) bool {
return HTTPSuccess(a.t, handler, mode, url, values) return HTTPSuccess(a.t, handler, method, url, values)
} }
// HTTPRedirect asserts that a specified handler returns a redirect status code. // HTTPRedirect asserts that a specified handler returns a redirect status code.
@ -123,8 +123,8 @@ func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, mode, url string, val
// assert.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // assert.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, mode, url string, values url.Values) bool { func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method, url string, values url.Values) bool {
return HTTPRedirect(a.t, handler, mode, url, values) return HTTPRedirect(a.t, handler, method, url, values)
} }
// HTTPError asserts that a specified handler returns an error status code. // HTTPError asserts that a specified handler returns an error status code.
@ -132,8 +132,8 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, mode, url string, va
// assert.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // assert.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPError(handler http.HandlerFunc, mode, url string, values url.Values) bool { func (a *Assertions) HTTPError(handler http.HandlerFunc, method, url string, values url.Values) bool {
return HTTPError(a.t, handler, mode, url, values) return HTTPError(a.t, handler, method, url, values)
} }
// HTTPBodyContains asserts that a specified handler returns a // HTTPBodyContains asserts that a specified handler returns a
@ -142,8 +142,8 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, mode, url string, value
// assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") // assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool { func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {
return HTTPBodyContains(a.t, handler, mode, url, values, str) return HTTPBodyContains(a.t, handler, method, url, values, str)
} }
// HTTPBodyNotContains asserts that a specified handler returns a // HTTPBodyNotContains asserts that a specified handler returns a
@ -152,6 +152,6 @@ func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, mode, url string
// assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") // assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool { func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {
return HTTPBodyNotContains(a.t, handler, mode, url, values, str) return HTTPBodyNotContains(a.t, handler, method, url, values, str)
} }

View File

@ -2,13 +2,15 @@ package mock
import ( import (
"fmt" "fmt"
"github.com/stretchr/objx"
"github.com/stretchr/testify/assert"
"reflect" "reflect"
"regexp"
"runtime" "runtime"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/stretchr/objx"
"github.com/stretchr/testify/assert"
) )
// TestingT is an interface wrapper around *testing.T // TestingT is an interface wrapper around *testing.T
@ -24,6 +26,7 @@ type TestingT interface {
// Call represents a method call and is used for setting expectations, // Call represents a method call and is used for setting expectations,
// as well as recording activity. // as well as recording activity.
type Call struct { type Call struct {
Parent *Mock
// The name of the method that was or will be called. // The name of the method that was or will be called.
Method string Method string
@ -46,24 +49,113 @@ type Call struct {
// Holds a handler used to manipulate arguments content that are passed by // Holds a handler used to manipulate arguments content that are passed by
// reference. It's useful when mocking methods such as unmarshalers or // reference. It's useful when mocking methods such as unmarshalers or
// decoders. // decoders.
Run func(Arguments) RunFn func(Arguments)
}
func newCall(parent *Mock, methodName string, methodArguments ...interface{}) *Call {
return &Call{
Parent: parent,
Method: methodName,
Arguments: methodArguments,
ReturnArguments: make([]interface{}, 0),
Repeatability: 0,
WaitFor: nil,
RunFn: nil,
}
}
func (self *Call) lock() {
self.Parent.mutex.Lock()
}
func (self *Call) unlock() {
self.Parent.mutex.Unlock()
}
func (self *Call) Return(returnArguments ...interface{}) *Call {
self.lock()
defer self.unlock()
self.ReturnArguments = returnArguments
return self
}
// Once indicates that that the mock should only return the value once.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
func (self *Call) Once() *Call {
return self.Times(1)
}
// Twice indicates that that the mock should only return the value twice.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()
func (self *Call) Twice() *Call {
return self.Times(2)
}
// Times indicates that that the mock should only return the indicated number
// of times.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5)
func (self *Call) Times(i int) *Call {
self.lock()
defer self.unlock()
self.Repeatability = i
return self
}
// WaitUntil sets the channel that will block the mock's return until its closed
// or a message is received.
//
// Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second))
func (self *Call) WaitUntil(w <-chan time.Time) *Call {
self.lock()
defer self.unlock()
self.WaitFor = w
return self
}
// After sets how long to block until the call returns
//
// Mock.On("MyMethod", arg1, arg2).After(time.Second)
func (self *Call) After(d time.Duration) *Call {
return self.WaitUntil(time.After(d))
}
// Run sets a handler to be called before returning. It can be used when
// mocking a method such as unmarshalers that takes a pointer to a struct and
// sets properties in such struct
//
// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}").Return().Run(function(args Arguments) {
// arg := args.Get(0).(*map[string]interface{})
// arg["foo"] = "bar"
// })
func (self *Call) Run(fn func(Arguments)) *Call {
self.lock()
defer self.unlock()
self.RunFn = fn
return self
}
// On chains a new expectation description onto the mocked interface. This
// allows syntax like.
//
// Mock.
// On("MyMethod", 1).Return(nil).
// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error"))
func (self *Call) On(methodName string, arguments ...interface{}) *Call {
return self.Parent.On(methodName, arguments...)
} }
// Mock is the workhorse used to track activity on another object. // Mock is the workhorse used to track activity on another object.
// For an example of its usage, refer to the "Example Usage" section at the top of this document. // For an example of its usage, refer to the "Example Usage" section at the top
// of this document.
type Mock struct { type Mock struct {
// The method name that is currently
// being referred to by the On method.
onMethodName string
// An array of the arguments that are
// currently being referred to by the On method.
onMethodArguments Arguments
// Represents the calls that are expected of // Represents the calls that are expected of
// an object. // an object.
ExpectedCalls []Call ExpectedCalls []*Call
// Holds the calls that were made to this mocked object. // Holds the calls that were made to this mocked object.
Calls []Call Calls []Call
@ -94,90 +186,33 @@ func (m *Mock) TestData() objx.Map {
// being called. // being called.
// //
// Mock.On("MyMethod", arg1, arg2) // Mock.On("MyMethod", arg1, arg2)
func (m *Mock) On(methodName string, arguments ...interface{}) *Mock { func (self *Mock) On(methodName string, arguments ...interface{}) *Call {
m.onMethodName = methodName
m.onMethodArguments = arguments
for _, arg := range arguments { for _, arg := range arguments {
if v := reflect.ValueOf(arg); v.Kind() == reflect.Func { if v := reflect.ValueOf(arg); v.Kind() == reflect.Func {
panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg)) panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg))
} }
} }
return m self.mutex.Lock()
defer self.mutex.Unlock()
c := newCall(self, methodName, arguments...)
self.ExpectedCalls = append(self.ExpectedCalls, c)
return c
} }
// Return finishes a description of an expectation of the method (and arguments) // /*
// specified in the most recent On method call. // Recording and responding to activity
// // */
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2)
func (m *Mock) Return(returnArguments ...interface{}) *Mock {
m.ExpectedCalls = append(m.ExpectedCalls, Call{m.onMethodName, m.onMethodArguments, returnArguments, 0, nil, nil})
return m
}
// Once indicates that that the mock should only return the value once.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
func (m *Mock) Once() {
m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 1
}
// Twice indicates that that the mock should only return the value twice.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()
func (m *Mock) Twice() {
m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 2
}
// Times indicates that that the mock should only return the indicated number
// of times.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5)
func (m *Mock) Times(i int) {
m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = i
}
// WaitUntil sets the channel that will block the mock's return until its closed
// or a message is received.
//
// Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second))
func (m *Mock) WaitUntil(w <-chan time.Time) *Mock {
m.ExpectedCalls[len(m.ExpectedCalls)-1].WaitFor = w
return m
}
// After sets how long to block until the call returns
//
// Mock.On("MyMethod", arg1, arg2).After(time.Second)
func (m *Mock) After(d time.Duration) *Mock {
return m.WaitUntil(time.After(d))
}
// Run sets a handler to be called before returning. It can be used when
// mocking a method such as unmarshalers that takes a pointer to a struct and
// sets properties in such struct
//
// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}").Return().Run(function(args Arguments) {
// arg := args.Get(0).(*map[string]interface{})
// arg["foo"] = "bar"
// })
func (m *Mock) Run(fn func(Arguments)) *Mock {
m.ExpectedCalls[len(m.ExpectedCalls)-1].Run = fn
return m
}
/*
Recording and responding to activity
*/
func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) { func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) {
m.mutex.Lock()
defer m.mutex.Unlock()
for i, call := range m.ExpectedCalls { for i, call := range m.ExpectedCalls {
if call.Method == method && call.Repeatability > -1 { if call.Method == method && call.Repeatability > -1 {
_, diffCount := call.Arguments.Diff(arguments) _, diffCount := call.Arguments.Diff(arguments)
if diffCount == 0 { if diffCount == 0 {
return i, &call return i, call
} }
} }
@ -186,17 +221,16 @@ func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *
} }
func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *Call) { func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *Call) {
diffCount := 0 diffCount := 0
var closestCall *Call = nil var closestCall *Call = nil
for _, call := range m.ExpectedCalls { for _, call := range m.expectedCalls() {
if call.Method == method { if call.Method == method {
_, tempDiffCount := call.Arguments.Diff(arguments) _, tempDiffCount := call.Arguments.Diff(arguments)
if tempDiffCount < diffCount || diffCount == 0 { if tempDiffCount < diffCount || diffCount == 0 {
diffCount = tempDiffCount diffCount = tempDiffCount
closestCall = &call closestCall = call
} }
} }
@ -215,7 +249,7 @@ func callString(method string, arguments Arguments, includeArgumentValues bool)
if includeArgumentValues { if includeArgumentValues {
var argVals []string var argVals []string
for argIndex, arg := range arguments { for argIndex, arg := range arguments {
argVals = append(argVals, fmt.Sprintf("%d: %v", argIndex, arg)) argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg))
} }
argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t")) argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t"))
} }
@ -228,22 +262,26 @@ func callString(method string, arguments Arguments, includeArgumentValues bool)
// appropriate .On .Return() calls) // appropriate .On .Return() calls)
// If Call.WaitFor is set, blocks until the channel is closed or receives a message. // If Call.WaitFor is set, blocks until the channel is closed or receives a message.
func (m *Mock) Called(arguments ...interface{}) Arguments { func (m *Mock) Called(arguments ...interface{}) Arguments {
defer m.mutex.Unlock()
m.mutex.Lock()
// get the calling function's name // get the calling function's name
pc, _, _, ok := runtime.Caller(1) pc, _, _, ok := runtime.Caller(1)
if !ok { if !ok {
panic("Couldn't get the caller information") panic("Couldn't get the caller information")
} }
functionPath := runtime.FuncForPC(pc).Name() functionPath := runtime.FuncForPC(pc).Name()
//Next four lines are required to use GCCGO function naming conventions.
//For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock
//uses inteface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree
//With GCCGO we need to remove interface information starting from pN<dd>.
re := regexp.MustCompile("\\.pN\\d+_")
if re.MatchString(functionPath) {
functionPath = re.Split(functionPath, -1)[0]
}
parts := strings.Split(functionPath, ".") parts := strings.Split(functionPath, ".")
functionName := parts[len(parts)-1] functionName := parts[len(parts)-1]
found, call := m.findExpectedCall(functionName, arguments...) found, call := m.findExpectedCall(functionName, arguments...)
switch { if found < 0 {
case found < 0:
// we have to fail here - because we don't know what to do // we have to fail here - because we don't know what to do
// as the return arguments. This is because: // as the return arguments. This is because:
// //
@ -258,16 +296,22 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
} else { } else {
panic(fmt.Sprintf("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", functionName, functionName, callString(functionName, arguments, true), assert.CallerInfo())) panic(fmt.Sprintf("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", functionName, functionName, callString(functionName, arguments, true), assert.CallerInfo()))
} }
} else {
m.mutex.Lock()
switch {
case call.Repeatability == 1: case call.Repeatability == 1:
call.Repeatability = -1 call.Repeatability = -1
m.ExpectedCalls[found] = *call
case call.Repeatability > 1: case call.Repeatability > 1:
call.Repeatability -= 1 call.Repeatability -= 1
m.ExpectedCalls[found] = *call }
m.mutex.Unlock()
} }
// add the call // add the call
m.Calls = append(m.Calls, Call{functionName, arguments, make([]interface{}, 0), 0, nil, nil}) m.mutex.Lock()
m.Calls = append(m.Calls, *newCall(m, functionName, arguments...))
m.mutex.Unlock()
// block if specified // block if specified
if call.WaitFor != nil { if call.WaitFor != nil {
@ -276,12 +320,11 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
m.mutex.Lock() m.mutex.Lock()
} }
if call.Run != nil { if call.RunFn != nil {
call.Run(arguments) call.RunFn(arguments)
} }
return call.ReturnArguments return call.ReturnArguments
} }
/* /*
@ -304,27 +347,30 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
// AssertExpectations asserts that everything specified with On and Return was // AssertExpectations asserts that everything specified with On and Return was
// in fact called as expected. Calls may have occurred in any order. // in fact called as expected. Calls may have occurred in any order.
func (m *Mock) AssertExpectations(t TestingT) bool { func (m *Mock) AssertExpectations(t TestingT) bool {
var somethingMissing bool = false var somethingMissing bool = false
var failedExpectations int = 0 var failedExpectations int = 0
// iterate through each expectation // iterate through each expectation
for _, expectedCall := range m.ExpectedCalls { expectedCalls := m.expectedCalls()
switch { for _, expectedCall := range expectedCalls {
case !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments): if !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) {
somethingMissing = true somethingMissing = true
failedExpectations++ failedExpectations++
t.Logf("\u274C\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String()) t.Logf("\u274C\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
case expectedCall.Repeatability > 0: } else {
m.mutex.Lock()
if expectedCall.Repeatability > 0 {
somethingMissing = true somethingMissing = true
failedExpectations++ failedExpectations++
default: } else {
t.Logf("\u2705\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String()) t.Logf("\u2705\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
} }
m.mutex.Unlock()
}
} }
if somethingMissing { if somethingMissing {
t.Errorf("FAIL: %d out of %d expectation(s) were met.\n\tThe code you are testing needs to make %d more call(s).\n\tat: %s", len(m.ExpectedCalls)-failedExpectations, len(m.ExpectedCalls), failedExpectations, assert.CallerInfo()) t.Errorf("FAIL: %d out of %d expectation(s) were met.\n\tThe code you are testing needs to make %d more call(s).\n\tat: %s", len(expectedCalls)-failedExpectations, len(expectedCalls), failedExpectations, assert.CallerInfo())
} }
return !somethingMissing return !somethingMissing
@ -333,18 +379,18 @@ func (m *Mock) AssertExpectations(t TestingT) bool {
// AssertNumberOfCalls asserts that the method was called expectedCalls times. // AssertNumberOfCalls asserts that the method was called expectedCalls times.
func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool { func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool {
var actualCalls int = 0 var actualCalls int = 0
for _, call := range m.Calls { for _, call := range m.calls() {
if call.Method == methodName { if call.Method == methodName {
actualCalls++ actualCalls++
} }
} }
return assert.Equal(t, actualCalls, expectedCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls)) return assert.Equal(t, expectedCalls, actualCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls))
} }
// AssertCalled asserts that the method was called. // AssertCalled asserts that the method was called.
func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool { func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool {
if !assert.True(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method should have been called with %d argument(s), but was not.", methodName, len(arguments))) { if !assert.True(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method should have been called with %d argument(s), but was not.", methodName, len(arguments))) {
t.Logf("%v", m.ExpectedCalls) t.Logf("%v", m.expectedCalls())
return false return false
} }
return true return true
@ -353,14 +399,14 @@ func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interfac
// AssertNotCalled asserts that the method was not called. // AssertNotCalled asserts that the method was not called.
func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool { func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool {
if !assert.False(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method was called with %d argument(s), but should NOT have been.", methodName, len(arguments))) { if !assert.False(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method was called with %d argument(s), but should NOT have been.", methodName, len(arguments))) {
t.Logf("%v", m.ExpectedCalls) t.Logf("%v", m.expectedCalls())
return false return false
} }
return true return true
} }
func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool { func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {
for _, call := range m.Calls { for _, call := range m.calls() {
if call.Method == methodName { if call.Method == methodName {
_, differences := Arguments(expected).Diff(call.Arguments) _, differences := Arguments(expected).Diff(call.Arguments)
@ -376,6 +422,18 @@ func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {
return false return false
} }
func (m *Mock) expectedCalls() []*Call {
m.mutex.Lock()
defer m.mutex.Unlock()
return append([]*Call{}, m.ExpectedCalls...)
}
func (m *Mock) calls() []Call {
m.mutex.Lock()
defer m.mutex.Unlock()
return append([]Call{}, m.Calls...)
}
/* /*
Arguments Arguments
*/ */

View File

@ -3,6 +3,7 @@ package mock
import ( import (
"errors" "errors"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing" "testing"
"time" "time"
) )
@ -44,6 +45,16 @@ func (i *TestExampleImplementation) TheExampleMethodFunc(fn func(string) error)
return args.Error(0) return args.Error(0)
} }
func (i *TestExampleImplementation) TheExampleMethodVariadic(a ...int) error {
args := i.Called(a)
return args.Error(0)
}
func (i *TestExampleImplementation) TheExampleMethodVariadicInterface(a ...interface{}) error {
args := i.Called(a)
return args.Error(0)
}
type ExampleFuncType func(string) error type ExampleFuncType func(string) error
func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error { func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error {
@ -63,9 +74,7 @@ func Test_Mock_TestData(t *testing.T) {
mockedService.TestData().Set("something", 123) mockedService.TestData().Set("something", 123)
assert.Equal(t, 123, mockedService.TestData().Get("something").Data()) assert.Equal(t, 123, mockedService.TestData().Get("something").Data())
} }
} }
func Test_Mock_On(t *testing.T) { func Test_Mock_On(t *testing.T) {
@ -73,9 +82,36 @@ func Test_Mock_On(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethod"), &mockedService.Mock) c := mockedService.On("TheExampleMethod")
assert.Equal(t, "TheExampleMethod", mockedService.onMethodName) assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, "TheExampleMethod", c.Method)
}
func Test_Mock_Chained_On(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.
On("TheExampleMethod", 1, 2, 3).
Return(0).
On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).
Return(nil)
expectedCalls := []*Call{
&Call{
Parent: &mockedService.Mock,
Method: "TheExampleMethod",
Arguments: []interface{}{1, 2, 3},
ReturnArguments: []interface{}{0},
},
&Call{
Parent: &mockedService.Mock,
Method: "TheExampleMethod3",
Arguments: []interface{}{AnythingOfType("*mock.ExampleType")},
ReturnArguments: []interface{}{nil},
},
}
assert.Equal(t, expectedCalls, mockedService.ExpectedCalls)
} }
func Test_Mock_On_WithArgs(t *testing.T) { func Test_Mock_On_WithArgs(t *testing.T) {
@ -83,12 +119,11 @@ func Test_Mock_On_WithArgs(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethod", 1, 2, 3), &mockedService.Mock) c := mockedService.On("TheExampleMethod", 1, 2, 3, 4)
assert.Equal(t, "TheExampleMethod", mockedService.onMethodName)
assert.Equal(t, 1, mockedService.onMethodArguments[0])
assert.Equal(t, 2, mockedService.onMethodArguments[1])
assert.Equal(t, 3, mockedService.onMethodArguments[2])
assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, "TheExampleMethod", c.Method)
assert.Equal(t, Arguments{1, 2, 3, 4}, c.Arguments)
} }
func Test_Mock_On_WithFuncArg(t *testing.T) { func Test_Mock_On_WithFuncArg(t *testing.T) {
@ -96,12 +131,85 @@ func Test_Mock_On_WithFuncArg(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethodFunc", AnythingOfType("func(string) error")).Return(nil), &mockedService.Mock) c := mockedService.
assert.Equal(t, "TheExampleMethodFunc", mockedService.onMethodName) On("TheExampleMethodFunc", AnythingOfType("func(string) error")).
assert.Equal(t, AnythingOfType("func(string) error"), mockedService.onMethodArguments[0]) Return(nil)
assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, "TheExampleMethodFunc", c.Method)
assert.Equal(t, 1, len(c.Arguments))
assert.Equal(t, AnythingOfType("func(string) error"), c.Arguments[0])
fn := func(string) error { return nil } fn := func(string) error { return nil }
assert.NotPanics(t, func() {
mockedService.TheExampleMethodFunc(fn) mockedService.TheExampleMethodFunc(fn)
})
}
func Test_Mock_On_WithVariadicFunc(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
c := mockedService.
On("TheExampleMethodVariadic", []int{1, 2, 3}).
Return(nil)
assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, 1, len(c.Arguments))
assert.Equal(t, []int{1, 2, 3}, c.Arguments[0])
assert.NotPanics(t, func() {
mockedService.TheExampleMethodVariadic(1, 2, 3)
})
assert.Panics(t, func() {
mockedService.TheExampleMethodVariadic(1, 2)
})
}
func Test_Mock_On_WithVariadicFuncWithInterface(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
c := mockedService.On("TheExampleMethodVariadicInterface", []interface{}{1, 2, 3}).
Return(nil)
assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, 1, len(c.Arguments))
assert.Equal(t, []interface{}{1, 2, 3}, c.Arguments[0])
assert.NotPanics(t, func() {
mockedService.TheExampleMethodVariadicInterface(1, 2, 3)
})
assert.Panics(t, func() {
mockedService.TheExampleMethodVariadicInterface(1, 2)
})
}
func Test_Mock_On_WithVariadicFuncWithEmptyInterfaceArray(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
var expected []interface{}
c := mockedService.
On("TheExampleMethodVariadicInterface", expected).
Return(nil)
assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, 1, len(c.Arguments))
assert.Equal(t, expected, c.Arguments[0])
assert.NotPanics(t, func() {
mockedService.TheExampleMethodVariadicInterface()
})
assert.Panics(t, func() {
mockedService.TheExampleMethodVariadicInterface(1, 2)
})
} }
@ -119,13 +227,18 @@ func Test_Mock_On_WithFuncTypeArg(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethodFuncType", AnythingOfType("mock.ExampleFuncType")).Return(nil), &mockedService.Mock) c := mockedService.
assert.Equal(t, "TheExampleMethodFuncType", mockedService.onMethodName) On("TheExampleMethodFuncType", AnythingOfType("mock.ExampleFuncType")).
assert.Equal(t, AnythingOfType("mock.ExampleFuncType"), mockedService.onMethodArguments[0]) Return(nil)
assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, 1, len(c.Arguments))
assert.Equal(t, AnythingOfType("mock.ExampleFuncType"), c.Arguments[0])
fn := func(string) error { return nil } fn := func(string) error { return nil }
assert.NotPanics(t, func() {
mockedService.TheExampleMethodFuncType(fn) mockedService.TheExampleMethodFuncType(fn)
})
} }
func Test_Mock_Return(t *testing.T) { func Test_Mock_Return(t *testing.T) {
@ -133,10 +246,12 @@ func Test_Mock_Return(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true), &mockedService.Mock) c := mockedService.
On("TheExampleMethod", "A", "B", true).
Return(1, "two", true)
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0] call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "TheExampleMethod", call.Method)
@ -148,9 +263,6 @@ func Test_Mock_Return(t *testing.T) {
assert.Equal(t, true, call.ReturnArguments[2]) assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 0, call.Repeatability) assert.Equal(t, 0, call.Repeatability)
assert.Nil(t, call.WaitFor) assert.Nil(t, call.WaitFor)
}
} }
func Test_Mock_Return_WaitUntil(t *testing.T) { func Test_Mock_Return_WaitUntil(t *testing.T) {
@ -159,11 +271,15 @@ func Test_Mock_Return_WaitUntil(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
ch := time.After(time.Second) ch := time.After(time.Second)
assert.Equal(t, mockedService.Mock.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).WaitUntil(ch), &mockedService.Mock) c := mockedService.Mock.
On("TheExampleMethod", "A", "B", true).
WaitUntil(ch).
Return(1, "two", true)
// ensure the call was created // assert that the call was created
if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) { require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
call := mockedService.Mock.ExpectedCalls[0]
call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0]) assert.Equal(t, "A", call.Arguments[0])
@ -174,9 +290,6 @@ func Test_Mock_Return_WaitUntil(t *testing.T) {
assert.Equal(t, true, call.ReturnArguments[2]) assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 0, call.Repeatability) assert.Equal(t, 0, call.Repeatability)
assert.Equal(t, ch, call.WaitFor) assert.Equal(t, ch, call.WaitFor)
}
} }
func Test_Mock_Return_After(t *testing.T) { func Test_Mock_Return_After(t *testing.T) {
@ -184,10 +297,13 @@ func Test_Mock_Return_After(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.Mock.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).After(time.Second), &mockedService.Mock) c := mockedService.Mock.
On("TheExampleMethod", "A", "B", true).
Return(1, "two", true).
After(time.Second)
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) {
call := mockedService.Mock.ExpectedCalls[0] call := mockedService.Mock.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "TheExampleMethod", call.Method)
@ -200,8 +316,6 @@ func Test_Mock_Return_After(t *testing.T) {
assert.Equal(t, 0, call.Repeatability) assert.Equal(t, 0, call.Repeatability)
assert.NotEqual(t, nil, call.WaitFor) assert.NotEqual(t, nil, call.WaitFor)
}
} }
func Test_Mock_Return_Run(t *testing.T) { func Test_Mock_Return_Run(t *testing.T) {
@ -209,13 +323,18 @@ func Test_Mock_Return_Run(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.Mock.On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).Return(nil).Run(func(args Arguments) { fn := func(args Arguments) {
arg := args.Get(0).(*ExampleType) arg := args.Get(0).(*ExampleType)
arg.ran = true arg.ran = true
}), &mockedService.Mock) }
c := mockedService.Mock.
On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).
Return(nil).
Run(fn)
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) {
call := mockedService.Mock.ExpectedCalls[0] call := mockedService.Mock.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod3", call.Method) assert.Equal(t, "TheExampleMethod3", call.Method)
@ -225,13 +344,35 @@ func Test_Mock_Return_Run(t *testing.T) {
assert.NotEqual(t, nil, call.WaitFor) assert.NotEqual(t, nil, call.WaitFor)
assert.NotNil(t, call.Run) assert.NotNil(t, call.Run)
}
et := ExampleType{} et := ExampleType{}
assert.Equal(t, false, et.ran) assert.Equal(t, false, et.ran)
mockedService.TheExampleMethod3(&et) mockedService.TheExampleMethod3(&et)
assert.Equal(t, true, et.ran) assert.Equal(t, true, et.ran)
}
func Test_Mock_Return_Run_Out_Of_Order(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
f := func(args Arguments) {
arg := args.Get(0).(*ExampleType)
arg.ran = true
}
c := mockedService.Mock.
On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).
Run(f).
Return(nil)
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
call := mockedService.Mock.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod3", call.Method)
assert.Equal(t, AnythingOfType("*mock.ExampleType"), call.Arguments[0])
assert.Equal(t, nil, call.ReturnArguments[0])
assert.Equal(t, 0, call.Repeatability)
assert.NotEqual(t, nil, call.WaitFor)
assert.NotNil(t, call.Run)
} }
func Test_Mock_Return_Once(t *testing.T) { func Test_Mock_Return_Once(t *testing.T) {
@ -239,10 +380,12 @@ func Test_Mock_Return_Once(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).Once() c := mockedService.On("TheExampleMethod", "A", "B", true).
Return(1, "two", true).
Once()
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0] call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "TheExampleMethod", call.Method)
@ -254,9 +397,6 @@ func Test_Mock_Return_Once(t *testing.T) {
assert.Equal(t, true, call.ReturnArguments[2]) assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 1, call.Repeatability) assert.Equal(t, 1, call.Repeatability)
assert.Nil(t, call.WaitFor) assert.Nil(t, call.WaitFor)
}
} }
func Test_Mock_Return_Twice(t *testing.T) { func Test_Mock_Return_Twice(t *testing.T) {
@ -264,10 +404,13 @@ func Test_Mock_Return_Twice(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).Twice() c := mockedService.
On("TheExampleMethod", "A", "B", true).
Return(1, "two", true).
Twice()
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0] call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "TheExampleMethod", call.Method)
@ -279,9 +422,6 @@ func Test_Mock_Return_Twice(t *testing.T) {
assert.Equal(t, true, call.ReturnArguments[2]) assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 2, call.Repeatability) assert.Equal(t, 2, call.Repeatability)
assert.Nil(t, call.WaitFor) assert.Nil(t, call.WaitFor)
}
} }
func Test_Mock_Return_Times(t *testing.T) { func Test_Mock_Return_Times(t *testing.T) {
@ -289,10 +429,13 @@ func Test_Mock_Return_Times(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).Times(5) c := mockedService.
On("TheExampleMethod", "A", "B", true).
Return(1, "two", true).
Times(5)
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0] call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "TheExampleMethod", call.Method)
@ -304,9 +447,6 @@ func Test_Mock_Return_Times(t *testing.T) {
assert.Equal(t, true, call.ReturnArguments[2]) assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 5, call.Repeatability) assert.Equal(t, 5, call.Repeatability)
assert.Nil(t, call.WaitFor) assert.Nil(t, call.WaitFor)
}
} }
func Test_Mock_Return_Nothing(t *testing.T) { func Test_Mock_Return_Nothing(t *testing.T) {
@ -314,10 +454,12 @@ func Test_Mock_Return_Nothing(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethod", "A", "B", true).Return(), &mockedService.Mock) c := mockedService.
On("TheExampleMethod", "A", "B", true).
Return()
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0] call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "TheExampleMethod", call.Method)
@ -325,9 +467,6 @@ func Test_Mock_Return_Nothing(t *testing.T) {
assert.Equal(t, "B", call.Arguments[1]) assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2]) assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 0, len(call.ReturnArguments)) assert.Equal(t, 0, len(call.ReturnArguments))
}
} }
func Test_Mock_findExpectedCall(t *testing.T) { func Test_Mock_findExpectedCall(t *testing.T) {
@ -452,8 +591,13 @@ func Test_Mock_Called_For_Bounded_Repeatability(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3).Return(5, "6", true).Once() mockedService.
mockedService.On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3).Return(-1, "hi", false) On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3).
Return(5, "6", true).
Once()
mockedService.
On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3).
Return(-1, "hi", false)
returnArguments1 := mockedService.Called(1, 2, 3) returnArguments1 := mockedService.Called(1, 2, 3)
returnArguments2 := mockedService.Called(1, 2, 3) returnArguments2 := mockedService.Called(1, 2, 3)
@ -651,7 +795,9 @@ func Test_Mock_AssertCalled_WithAnythingOfTypeArgument(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("Test_Mock_AssertCalled_WithAnythingOfTypeArgument", Anything, Anything, Anything).Return() mockedService.
On("Test_Mock_AssertCalled_WithAnythingOfTypeArgument", Anything, Anything, Anything).
Return()
mockedService.Called(1, "two", []uint8("three")) mockedService.Called(1, "two", []uint8("three"))

View File

@ -24,54 +24,4 @@
// //
// Every assertion function also takes an optional string message as the final argument, // Every assertion function also takes an optional string message as the final argument,
// allowing custom error messages to be appended to the message the assertion method outputs. // allowing custom error messages to be appended to the message the assertion method outputs.
//
// Here is an overview of the assert functions:
//
// require.Equal(t, expected, actual [, message [, format-args])
//
// require.NotEqual(t, notExpected, actual [, message [, format-args]])
//
// require.True(t, actualBool [, message [, format-args]])
//
// require.False(t, actualBool [, message [, format-args]])
//
// require.Nil(t, actualObject [, message [, format-args]])
//
// require.NotNil(t, actualObject [, message [, format-args]])
//
// require.Empty(t, actualObject [, message [, format-args]])
//
// require.NotEmpty(t, actualObject [, message [, format-args]])
//
// require.Error(t, errorObject [, message [, format-args]])
//
// require.NoError(t, errorObject [, message [, format-args]])
//
// require.EqualError(t, theError, errString [, message [, format-args]])
//
// require.Implements(t, (*MyInterface)(nil), new(MyObject) [,message [, format-args]])
//
// require.IsType(t, expectedObject, actualObject [, message [, format-args]])
//
// require.Contains(t, string, substring [, message [, format-args]])
//
// require.NotContains(t, string, substring [, message [, format-args]])
//
// require.Panics(t, func(){
//
// // call code that should panic
//
// } [, message [, format-args]])
//
// require.NotPanics(t, func(){
//
// // call code that should not panic
//
// } [, message [, format-args]])
//
// require.WithinDuration(t, timeA, timeB, deltaTime, [, message [, format-args]])
//
// require.InDelta(t, numA, numB, delta, [, message [, format-args]])
//
// require.InEpsilon(t, numA, numB, epsilon, [, message [, format-args]])
package require package require

View File

@ -209,3 +209,22 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
NotRegexp(a.t, rx, str, msgAndArgs...) NotRegexp(a.t, rx, str, msgAndArgs...)
} }
// Zero asserts that i is the zero value for its type and returns the truth.
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
Zero(a.t, i, msgAndArgs...)
}
// NotZero asserts that i is not the zero value for its type and returns the truth.
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {
NotZero(a.t, i, msgAndArgs...)
}
// JSONEq asserts that two JSON strings are equivalent.
//
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) {
JSONEq(a.t, expected, actual, msgAndArgs...)
}

View File

@ -258,3 +258,128 @@ func TestInDeltaWrapper(t *testing.T) {
t.Error("Check should fail") t.Error("Check should fail")
} }
} }
func TestZeroWrapper(t *testing.T) {
require := New(t)
require.Zero(0)
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.Zero(1)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNotZeroWrapper(t *testing.T) {
require := New(t)
require.NotZero(1)
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.NotZero(0)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestJSONEqWrapper_EqualSONString(t *testing.T) {
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)
if mockT.Failed {
t.Error("Check should pass")
}
}
func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) {
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
if mockT.Failed {
t.Error("Check should pass")
}
}
func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) {
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.JSONEq("{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
"{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}")
if mockT.Failed {
t.Error("Check should pass")
}
}
func TestJSONEqWrapper_Array(t *testing.T) {
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)
if mockT.Failed {
t.Error("Check should pass")
}
}
func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) {
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) {
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.JSONEq(`{"foo": "bar"}`, "Not JSON")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) {
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) {
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.JSONEq("Not JSON", "Not JSON")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) {
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`)
if !mockT.Failed {
t.Error("Check should fail")
}
}

View File

@ -1,6 +1,7 @@
package require package require
import ( import (
"encoding/json"
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -136,9 +137,12 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{
} }
} }
// Contains asserts that the specified string contains the specified substring. // Contains asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element.
// //
// require.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'") // require.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
// require.Contains(t, ["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'")
// require.Contains(t, {"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'")
func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) { func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) {
if !assert.Contains(t, s, contains, msgAndArgs...) { if !assert.Contains(t, s, contains, msgAndArgs...) {
t.FailNow() t.FailNow()
@ -228,6 +232,25 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf
} }
} }
// JSONEq asserts that two JSON strings are equivalent.
//
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
//
// Returns whether the assertion was successful (true) or not (false).
func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
var expectedJSONAsInterface, actualJSONAsInterface interface{}
if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil {
t.FailNow()
}
if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil {
t.FailNow()
}
Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
}
/* /*
Errors Errors
*/ */
@ -269,3 +292,17 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte
t.FailNow() t.FailNow()
} }
} }
// Zero asserts that i is the zero value for its type and returns the truth.
func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
if !assert.Zero(t, i, msgAndArgs...) {
t.FailNow()
}
}
// NotZero asserts that i is not the zero value for its type and returns the truth.
func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
if !assert.NotZero(t, i, msgAndArgs...) {
t.FailNow()
}
}

View File

@ -264,3 +264,106 @@ func TestInDelta(t *testing.T) {
t.Error("Check should fail") t.Error("Check should fail")
} }
} }
func TestZero(t *testing.T) {
Zero(t, "")
mockT := new(MockT)
Zero(mockT, "x")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNotZero(t *testing.T) {
NotZero(t, "x")
mockT := new(MockT)
NotZero(mockT, "")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestJSONEq_EqualSONString(t *testing.T) {
mockT := new(MockT)
JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)
if mockT.Failed {
t.Error("Check should pass")
}
}
func TestJSONEq_EquivalentButNotEqual(t *testing.T) {
mockT := new(MockT)
JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
if mockT.Failed {
t.Error("Check should pass")
}
}
func TestJSONEq_HashOfArraysAndHashes(t *testing.T) {
mockT := new(MockT)
JSONEq(mockT, "{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
"{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}")
if mockT.Failed {
t.Error("Check should pass")
}
}
func TestJSONEq_Array(t *testing.T) {
mockT := new(MockT)
JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)
if mockT.Failed {
t.Error("Check should pass")
}
}
func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) {
mockT := new(MockT)
JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestJSONEq_HashesNotEquivalent(t *testing.T) {
mockT := new(MockT)
JSONEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestJSONEq_ActualIsNotJSON(t *testing.T) {
mockT := new(MockT)
JSONEq(mockT, `{"foo": "bar"}`, "Not JSON")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestJSONEq_ExpectedIsNotJSON(t *testing.T) {
mockT := new(MockT)
JSONEq(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) {
mockT := new(MockT)
JSONEq(mockT, "Not JSON", "Not JSON")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) {
mockT := new(MockT)
JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`)
if !mockT.Failed {
t.Error("Check should fail")
}
}

View File

@ -53,8 +53,8 @@
// // All methods that begin with "Test" are run as tests within a // // All methods that begin with "Test" are run as tests within a
// // suite. // // suite.
// func (suite *ExampleTestSuite) TestExample() { // func (suite *ExampleTestSuite) TestExample() {
// assert.Equal(suite.T(), suite.VariableThatShouldStartAtFive, 5) // assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
// suite.Equal(suite.VariableThatShouldStartAtFive, 5) // suite.Equal(5, suite.VariableThatShouldStartAtFive)
// } // }
// //
// // In order for 'go test' to run this suite, we need to create // // In order for 'go test' to run this suite, we need to create

View File

@ -31,6 +31,7 @@ func (suite *Suite) T() *testing.T {
func (suite *Suite) SetT(t *testing.T) { func (suite *Suite) SetT(t *testing.T) {
suite.t = t suite.t = t
suite.Assertions = assert.New(t) suite.Assertions = assert.New(t)
suite.require = require.New(t)
} }
// Require returns a require context for suite. // Require returns a require context for suite.

View File

@ -9,6 +9,37 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
// SuiteRequireTwice is intended to test the usage of suite.Require in two
// different tests
type SuiteRequireTwice struct{ Suite }
// TestSuiteRequireTwice checks for regressions of issue #149 where
// suite.requirements was not initialised in suite.SetT()
// A regression would result on these tests panicking rather than failing.
func TestSuiteRequireTwice(t *testing.T) {
ok := testing.RunTests(
func(_, _ string) (bool, error) { return true, nil },
[]testing.InternalTest{{
Name: "TestSuiteRequireTwice",
F: func(t *testing.T) {
suite := new(SuiteRequireTwice)
Run(t, suite)
},
}},
)
assert.Equal(t, false, ok)
}
func (s *SuiteRequireTwice) TestRequireOne() {
r := s.Require()
r.Equal(1, 2)
}
func (s *SuiteRequireTwice) TestRequireTwo() {
r := s.Require()
r.Equal(1, 2)
}
// This suite is intended to store values to make sure that only // This suite is intended to store values to make sure that only
// testing-suite-related methods are run. It's also a fully // testing-suite-related methods are run. It's also a fully
// functional example of a testing suite, using setup/teardown methods // functional example of a testing suite, using setup/teardown methods