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.2
- 1.3
- 1.4
- 1.5
- tip
script:

View File

@ -15,7 +15,7 @@ Features include:
Get started:
* 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
* 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)
@ -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.
@ -212,7 +212,7 @@ func (suite *ExampleTestSuite) SetupTest() {
// All methods that begin with "Test" are run as tests within a
// suite.
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
@ -268,7 +268,8 @@ Installation
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:
@ -298,9 +299,14 @@ func TestSomething(t *testing.T) {
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 (
"bufio"
"bytes"
"encoding/json"
"fmt"
"math"
"reflect"
@ -10,6 +11,11 @@ import (
"runtime"
"strings"
"time"
"unicode"
"unicode/utf8"
"github.com/davecgh/go-spew/spew"
"github.com/pmezard/go-difflib/difflib"
)
// TestingT is an interface wrapper around *testing.T
@ -33,11 +39,7 @@ func ObjectsAreEqual(expected, actual interface{}) bool {
return expected == actual
}
if reflect.DeepEqual(expected, actual) {
return true
}
return false
return reflect.DeepEqual(expected, actual)
}
@ -49,12 +51,13 @@ func ObjectsAreEqualValues(expected, actual interface{}) bool {
}
actualType := reflect.TypeOf(actual)
if actualType == nil {
return false
}
expectedValue := reflect.ValueOf(expected)
if expectedValue.Type().ConvertibleTo(actualType) {
if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
// Attempt comparison after type conversion
if reflect.DeepEqual(actual, expectedValue.Convert(actualType).Interface()) {
return true
}
return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
}
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
the problem actually occured in calling code.*/
// CallerInfo returns a string containing the file and line number of the assert call
// that failed.
func CallerInfo() string {
// CallerInfo returns an array of strings containing the file and line number
// of each stack frame leading from the current test to the assert call that
// failed.
func CallerInfo() []string {
pc := uintptr(0)
file := ""
line := 0
ok := false
name := ""
callers := []string{}
for i := 0; ; i++ {
_, file, line, ok = runtime.Caller(i)
pc, file, line, ok = runtime.Caller(i)
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, "/")
dir := parts[len(parts)-2]
file = parts[len(parts)-1]
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
}
}
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
@ -144,19 +186,20 @@ func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
message := messageFromMsgAndArgs(msgAndArgs...)
errorTrace := strings.Join(CallerInfo(), "\n\r\t\t\t")
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\tMessages:\t%s\n\r",
getWhitespaceString(),
CallerInfo(),
errorTrace,
indentMessageLines(failureMessage, 2),
message)
} 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",
getWhitespaceString(),
CallerInfo(),
errorTrace,
indentMessageLines(failureMessage, 2))
}
@ -171,7 +214,7 @@ func Implements(t TestingT, interfaceObject interface{}, object interface{}, msg
interfaceType := reflect.TypeOf(interfaceObject).Elem()
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
@ -196,8 +239,9 @@ func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if !ObjectsAreEqual(expected, actual) {
diff := diff(expected, actual)
return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+
" != %#v (actual)", expected, actual), msgAndArgs...)
" != %#v (actual)%s", expected, actual, diff), msgAndArgs...)
}
return true
@ -232,7 +276,7 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
bType := reflect.TypeOf(actual)
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...)
@ -245,24 +289,10 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
//
// Returns whether the assertion was successful (true) or not (false).
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
success := 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
}
if !isNil(object) {
return true
}
if !success {
Fail(t, "Expected not to be nil.", msgAndArgs...)
}
return success
return Fail(t, "Expected value not to be nil.", msgAndArgs...)
}
// 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...)
}
var zeros = []interface{}{
var numericZeros = []interface{}{
int(0),
int8(0),
int16(0),
@ -318,7 +348,7 @@ func isEmpty(object interface{}) bool {
return true
}
for _, v := range zeros {
for _, v := range numericZeros {
if object == v {
return true
}
@ -335,6 +365,9 @@ func isEmpty(object interface{}) bool {
}
case reflect.Ptr:
{
if objValue.IsNil() {
return true
}
switch object.(type) {
case *time.Time:
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 {
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
@ -476,6 +509,16 @@ func includeElement(list interface{}, element interface{}) (ok, found bool) {
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++ {
if ObjectsAreEqual(listValue.Index(i).Interface(), element) {
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.
//
// 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).
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.
//
// 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).
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 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`).
@ -800,7 +845,7 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte
return false
}
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)
}
@ -851,3 +896,84 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf
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 (
"errors"
"io"
"math"
"os"
"reflect"
"regexp"
"testing"
"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
type AssertionTesterInterface interface {
TestMethod()
@ -62,6 +132,12 @@ func TestObjectsAreEqual(t *testing.T) {
if !ObjectsAreEqualValues(uint32(10), int32(10)) {
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) {
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) {
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)) {
t.Error("Nil should return false: object is not nil")
}
@ -255,6 +337,7 @@ func TestContains(t *testing.T) {
{"g", "h"},
{"j", "k"},
}
simpleMap := map[interface{}]interface{}{"Foo": "Bar"}
if !Contains(mockT, "Hello World", "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"}) {
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) {
mockT := new(testing.T)
list := []string{"Foo", "Bar"}
simpleMap := map[interface{}]interface{}{"Foo": "Bar"}
if !NotContains(mockT, "Hello World", "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") {
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) {
list1 := []string{"Foo", "Bar"}
list2 := []int{1, 2}
simpleMap := map[interface{}]interface{}{"Foo": "Bar"}
ok, found := includeElement("Hello World", "World")
True(t, ok)
@ -335,10 +434,17 @@ func Test_includeElement(t *testing.T) {
True(t, ok)
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")
False(t, ok)
False(t, found)
}
func TestCondition(t *testing.T) {
@ -481,6 +587,9 @@ func TestEmpty(t *testing.T) {
mockT := new(testing.T)
chWithValue := make(chan struct{}, 1)
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, 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, false), "False value 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, 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))
}
}
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 (
// "testing"
@ -42,113 +42,4 @@
//
// 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.
//
// 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

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 {
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))
}
}
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
// 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()
req, err := http.NewRequest(mode, url+"?"+values.Encode(), nil)
req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
if err != nil {
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)
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPSuccess(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {
code := httpCode(handler, mode, url, values)
func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {
code := httpCode(handler, method, url, values)
if code == -1 {
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"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPRedirect(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {
code := httpCode(handler, mode, url, values)
func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {
code := httpCode(handler, method, url, values)
if code == -1 {
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"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPError(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {
code := httpCode(handler, mode, url, values)
func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {
code := httpCode(handler, method, url, values)
if code == -1 {
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
// 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()
req, err := http.NewRequest(mode, url+"?"+values.Encode(), nil)
req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
if err != nil {
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")
//
// 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 {
body := HTTPBody(handler, mode, url, values)
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {
body := HTTPBody(handler, method, url, values)
contains := strings.Contains(body, fmt.Sprint(str))
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")
//
// 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 {
body := HTTPBody(handler, mode, url, values)
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {
body := HTTPBody(handler, method, url, values)
contains := strings.Contains(body, fmt.Sprint(str))
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)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, mode, url string, values url.Values) bool {
return HTTPSuccess(a.t, handler, mode, url, values)
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method, url string, values url.Values) bool {
return HTTPSuccess(a.t, handler, method, url, values)
}
// 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"}}
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, mode, url string, values url.Values) bool {
return HTTPRedirect(a.t, handler, mode, url, values)
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method, url string, values url.Values) bool {
return HTTPRedirect(a.t, handler, method, url, values)
}
// 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"}}
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPError(handler http.HandlerFunc, mode, url string, values url.Values) bool {
return HTTPError(a.t, handler, mode, url, values)
func (a *Assertions) HTTPError(handler http.HandlerFunc, method, url string, values url.Values) bool {
return HTTPError(a.t, handler, method, url, values)
}
// 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")
//
// 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 {
return HTTPBodyContains(a.t, handler, mode, url, values, str)
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {
return HTTPBodyContains(a.t, handler, method, url, values, str)
}
// 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")
//
// 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 {
return HTTPBodyNotContains(a.t, handler, mode, url, values, str)
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {
return HTTPBodyNotContains(a.t, handler, method, url, values, str)
}

View File

@ -2,13 +2,15 @@ package mock
import (
"fmt"
"github.com/stretchr/objx"
"github.com/stretchr/testify/assert"
"reflect"
"regexp"
"runtime"
"strings"
"sync"
"time"
"github.com/stretchr/objx"
"github.com/stretchr/testify/assert"
)
// 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,
// as well as recording activity.
type Call struct {
Parent *Mock
// The name of the method that was or will be called.
Method string
@ -46,24 +49,113 @@ type Call struct {
// Holds a handler used to manipulate arguments content that are passed by
// reference. It's useful when mocking methods such as unmarshalers or
// 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.
// 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 {
// 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
// an object.
ExpectedCalls []Call
ExpectedCalls []*Call
// Holds the calls that were made to this mocked object.
Calls []Call
@ -94,90 +186,33 @@ func (m *Mock) TestData() objx.Map {
// being called.
//
// Mock.On("MyMethod", arg1, arg2)
func (m *Mock) On(methodName string, arguments ...interface{}) *Mock {
m.onMethodName = methodName
m.onMethodArguments = arguments
func (self *Mock) On(methodName string, arguments ...interface{}) *Call {
for _, arg := range arguments {
if v := reflect.ValueOf(arg); v.Kind() == reflect.Func {
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.
//
// 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
*/
// /*
// Recording and responding to activity
// */
func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) {
m.mutex.Lock()
defer m.mutex.Unlock()
for i, call := range m.ExpectedCalls {
if call.Method == method && call.Repeatability > -1 {
_, diffCount := call.Arguments.Diff(arguments)
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) {
diffCount := 0
var closestCall *Call = nil
for _, call := range m.ExpectedCalls {
for _, call := range m.expectedCalls() {
if call.Method == method {
_, tempDiffCount := call.Arguments.Diff(arguments)
if tempDiffCount < diffCount || diffCount == 0 {
diffCount = tempDiffCount
closestCall = &call
closestCall = call
}
}
@ -215,7 +249,7 @@ func callString(method string, arguments Arguments, includeArgumentValues bool)
if includeArgumentValues {
var argVals []string
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"))
}
@ -228,22 +262,26 @@ func callString(method string, arguments Arguments, includeArgumentValues bool)
// appropriate .On .Return() calls)
// If Call.WaitFor is set, blocks until the channel is closed or receives a message.
func (m *Mock) Called(arguments ...interface{}) Arguments {
defer m.mutex.Unlock()
m.mutex.Lock()
// get the calling function's name
pc, _, _, ok := runtime.Caller(1)
if !ok {
panic("Couldn't get the caller information")
}
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, ".")
functionName := parts[len(parts)-1]
found, call := m.findExpectedCall(functionName, arguments...)
switch {
case found < 0:
if found < 0 {
// we have to fail here - because we don't know what to do
// as the return arguments. This is because:
//
@ -258,16 +296,22 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
} 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()))
}
case call.Repeatability == 1:
call.Repeatability = -1
m.ExpectedCalls[found] = *call
case call.Repeatability > 1:
call.Repeatability -= 1
m.ExpectedCalls[found] = *call
} else {
m.mutex.Lock()
switch {
case call.Repeatability == 1:
call.Repeatability = -1
case call.Repeatability > 1:
call.Repeatability -= 1
}
m.mutex.Unlock()
}
// 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
if call.WaitFor != nil {
@ -276,12 +320,11 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
m.mutex.Lock()
}
if call.Run != nil {
call.Run(arguments)
if call.RunFn != nil {
call.RunFn(arguments)
}
return call.ReturnArguments
}
/*
@ -304,27 +347,30 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
// AssertExpectations asserts that everything specified with On and Return was
// in fact called as expected. Calls may have occurred in any order.
func (m *Mock) AssertExpectations(t TestingT) bool {
var somethingMissing bool = false
var failedExpectations int = 0
// iterate through each expectation
for _, expectedCall := range m.ExpectedCalls {
switch {
case !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments):
expectedCalls := m.expectedCalls()
for _, expectedCall := range expectedCalls {
if !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) {
somethingMissing = true
failedExpectations++
t.Logf("\u274C\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
case expectedCall.Repeatability > 0:
somethingMissing = true
failedExpectations++
default:
t.Logf("\u2705\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
} else {
m.mutex.Lock()
if expectedCall.Repeatability > 0 {
somethingMissing = true
failedExpectations++
} else {
t.Logf("\u2705\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
}
m.mutex.Unlock()
}
}
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
@ -333,18 +379,18 @@ func (m *Mock) AssertExpectations(t TestingT) bool {
// AssertNumberOfCalls asserts that the method was called expectedCalls times.
func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool {
var actualCalls int = 0
for _, call := range m.Calls {
for _, call := range m.calls() {
if call.Method == methodName {
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.
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))) {
t.Logf("%v", m.ExpectedCalls)
t.Logf("%v", m.expectedCalls())
return false
}
return true
@ -353,14 +399,14 @@ func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interfac
// AssertNotCalled asserts that the method was not called.
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))) {
t.Logf("%v", m.ExpectedCalls)
t.Logf("%v", m.expectedCalls())
return false
}
return true
}
func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {
for _, call := range m.Calls {
for _, call := range m.calls() {
if call.Method == methodName {
_, differences := Arguments(expected).Diff(call.Arguments)
@ -376,6 +422,18 @@ func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {
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
*/

View File

@ -3,6 +3,7 @@ package mock
import (
"errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
"time"
)
@ -44,6 +45,16 @@ func (i *TestExampleImplementation) TheExampleMethodFunc(fn func(string) error)
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
func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error {
@ -63,9 +74,7 @@ func Test_Mock_TestData(t *testing.T) {
mockedService.TestData().Set("something", 123)
assert.Equal(t, 123, mockedService.TestData().Get("something").Data())
}
}
func Test_Mock_On(t *testing.T) {
@ -73,9 +82,36 @@ func Test_Mock_On(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethod"), &mockedService.Mock)
assert.Equal(t, "TheExampleMethod", mockedService.onMethodName)
c := mockedService.On("TheExampleMethod")
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) {
@ -83,12 +119,11 @@ func Test_Mock_On_WithArgs(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethod", 1, 2, 3), &mockedService.Mock)
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])
c := mockedService.On("TheExampleMethod", 1, 2, 3, 4)
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) {
@ -96,12 +131,85 @@ func Test_Mock_On_WithFuncArg(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethodFunc", AnythingOfType("func(string) error")).Return(nil), &mockedService.Mock)
assert.Equal(t, "TheExampleMethodFunc", mockedService.onMethodName)
assert.Equal(t, AnythingOfType("func(string) error"), mockedService.onMethodArguments[0])
c := mockedService.
On("TheExampleMethodFunc", AnythingOfType("func(string) error")).
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 }
mockedService.TheExampleMethodFunc(fn)
assert.NotPanics(t, func() {
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
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethodFuncType", AnythingOfType("mock.ExampleFuncType")).Return(nil), &mockedService.Mock)
assert.Equal(t, "TheExampleMethodFuncType", mockedService.onMethodName)
assert.Equal(t, AnythingOfType("mock.ExampleFuncType"), mockedService.onMethodArguments[0])
c := mockedService.
On("TheExampleMethodFuncType", AnythingOfType("mock.ExampleFuncType")).
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 }
mockedService.TheExampleMethodFuncType(fn)
assert.NotPanics(t, func() {
mockedService.TheExampleMethodFuncType(fn)
})
}
func Test_Mock_Return(t *testing.T) {
@ -133,24 +246,23 @@ func Test_Mock_Return(t *testing.T) {
// make a test impl object
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)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0]
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 0, call.Repeatability)
assert.Nil(t, call.WaitFor)
}
call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 0, call.Repeatability)
assert.Nil(t, call.WaitFor)
}
func Test_Mock_Return_WaitUntil(t *testing.T) {
@ -159,24 +271,25 @@ func Test_Mock_Return_WaitUntil(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
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
if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) {
call := mockedService.Mock.ExpectedCalls[0]
// assert that the call was created
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 0, call.Repeatability)
assert.Equal(t, ch, call.WaitFor)
}
call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 0, call.Repeatability)
assert.Equal(t, ch, call.WaitFor)
}
func Test_Mock_Return_After(t *testing.T) {
@ -184,23 +297,24 @@ func Test_Mock_Return_After(t *testing.T) {
// make a test impl object
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)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) {
call := mockedService.Mock.ExpectedCalls[0]
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 0, call.Repeatability)
assert.NotEqual(t, nil, call.WaitFor)
call := mockedService.Mock.ExpectedCalls[0]
}
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 0, call.Repeatability)
assert.NotEqual(t, nil, call.WaitFor)
}
@ -209,29 +323,56 @@ func Test_Mock_Return_Run(t *testing.T) {
// make a test impl object
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.ran = true
}), &mockedService.Mock)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.Mock.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)
}
c := mockedService.Mock.
On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).
Return(nil).
Run(fn)
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)
et := ExampleType{}
assert.Equal(t, false, et.ran)
mockedService.TheExampleMethod3(&et)
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) {
@ -239,24 +380,23 @@ func Test_Mock_Return_Once(t *testing.T) {
// make a test impl object
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()
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0]
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 1, call.Repeatability)
assert.Nil(t, call.WaitFor)
}
call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 1, call.Repeatability)
assert.Nil(t, call.WaitFor)
}
func Test_Mock_Return_Twice(t *testing.T) {
@ -264,24 +404,24 @@ func Test_Mock_Return_Twice(t *testing.T) {
// make a test impl object
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()
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0]
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 2, call.Repeatability)
assert.Nil(t, call.WaitFor)
}
call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 2, call.Repeatability)
assert.Nil(t, call.WaitFor)
}
func Test_Mock_Return_Times(t *testing.T) {
@ -289,24 +429,24 @@ func Test_Mock_Return_Times(t *testing.T) {
// make a test impl object
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)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0]
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 5, call.Repeatability)
assert.Nil(t, call.WaitFor)
}
call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 5, call.Repeatability)
assert.Nil(t, call.WaitFor)
}
func Test_Mock_Return_Nothing(t *testing.T) {
@ -314,20 +454,19 @@ func Test_Mock_Return_Nothing(t *testing.T) {
// make a test impl object
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()
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0]
require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 0, len(call.ReturnArguments))
}
call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 0, len(call.ReturnArguments))
}
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)
mockedService.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)
mockedService.
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)
returnArguments2 := mockedService.Called(1, 2, 3)
@ -651,7 +795,9 @@ func Test_Mock_AssertCalled_WithAnythingOfTypeArgument(t *testing.T) {
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"))

View File

@ -24,54 +24,4 @@
//
// 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.
//
// 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

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{}) {
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")
}
}
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
import (
"encoding/json"
"time"
"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"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'")
func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) {
if !assert.Contains(t, s, contains, msgAndArgs...) {
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
*/
@ -269,3 +292,17 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte
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")
}
}
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
// // suite.
// func (suite *ExampleTestSuite) TestExample() {
// assert.Equal(suite.T(), suite.VariableThatShouldStartAtFive, 5)
// suite.Equal(suite.VariableThatShouldStartAtFive, 5)
// assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
// suite.Equal(5, suite.VariableThatShouldStartAtFive)
// }
//
// // 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) {
suite.t = t
suite.Assertions = assert.New(t)
suite.require = require.New(t)
}
// Require returns a require context for suite.

View File

@ -9,6 +9,37 @@ import (
"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
// testing-suite-related methods are run. It's also a fully
// functional example of a testing suite, using setup/teardown methods