Merge pull request #9425 from mesosphere/update-testify-dep

Update github.com/stretchr/testify rev to 7e4a149
This commit is contained in:
krousey 2015-06-09 11:59:00 -07:00
commit dd1f4f392f
10 changed files with 514 additions and 91 deletions

6
Godeps/Godeps.json generated
View File

@ -462,15 +462,15 @@
}, },
{ {
"ImportPath": "github.com/stretchr/testify/assert", "ImportPath": "github.com/stretchr/testify/assert",
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325" "Rev": "7e4a149930b09fe4c2b134c50ce637457ba6e966"
}, },
{ {
"ImportPath": "github.com/stretchr/testify/mock", "ImportPath": "github.com/stretchr/testify/mock",
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325" "Rev": "7e4a149930b09fe4c2b134c50ce637457ba6e966"
}, },
{ {
"ImportPath": "github.com/stretchr/testify/require", "ImportPath": "github.com/stretchr/testify/require",
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325" "Rev": "7e4a149930b09fe4c2b134c50ce637457ba6e966"
}, },
{ {
"ImportPath": "github.com/syndtr/gocapability/capability", "ImportPath": "github.com/syndtr/gocapability/capability",

View File

@ -4,11 +4,14 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"fmt" "fmt"
"math"
"reflect" "reflect"
"regexp" "regexp"
"runtime" "runtime"
"strings" "strings"
"time" "time"
"unicode"
"unicode/utf8"
) )
// TestingT is an interface wrapper around *testing.T // TestingT is an interface wrapper around *testing.T
@ -36,15 +39,12 @@ func ObjectsAreEqual(expected, actual interface{}) bool {
return true return true
} }
// Last ditch effort
if fmt.Sprintf("%#v", expected) == fmt.Sprintf("%#v", actual) {
return true
}
return false return false
} }
// ObjectsAreEqualValues gets whether two objects are equal, or if their
// values are equal.
func ObjectsAreEqualValues(expected, actual interface{}) bool { func ObjectsAreEqualValues(expected, actual interface{}) bool {
if ObjectsAreEqual(expected, actual) { if ObjectsAreEqual(expected, actual) {
return true return true
@ -66,28 +66,62 @@ 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
} }
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
@ -146,19 +180,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))
} }
@ -659,6 +694,14 @@ func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs
return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...) return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...)
} }
if math.IsNaN(af) {
return Fail(t, fmt.Sprintf("Actual must not be NaN"), msgAndArgs...)
}
if math.IsNaN(bf) {
return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...)
}
dt := af - bf dt := af - bf
if dt < -delta || dt > delta { if dt < -delta || dt > delta {
return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...) return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
@ -667,6 +710,27 @@ func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs
return true return true
} }
// InDeltaSlice is the same as InDelta, except it compares two slices.
func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if expected == nil || actual == nil ||
reflect.TypeOf(actual).Kind() != reflect.Slice ||
reflect.TypeOf(expected).Kind() != reflect.Slice {
return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...)
}
actualSlice := reflect.ValueOf(actual)
expectedSlice := reflect.ValueOf(expected)
for i := 0; i < actualSlice.Len(); i++ {
result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta)
if !result {
return result
}
}
return true
}
// min(|expected|, |actual|) * epsilon // min(|expected|, |actual|) * epsilon
func calcEpsilonDelta(expected, actual interface{}, epsilon float64) float64 { func calcEpsilonDelta(expected, actual interface{}, epsilon float64) float64 {
af, aok := toFloat(expected) af, aok := toFloat(expected)
@ -701,6 +765,27 @@ func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAnd
return InDelta(t, expected, actual, delta, msgAndArgs...) return InDelta(t, expected, actual, delta, msgAndArgs...)
} }
// InEpsilonSlice is the same as InEpsilon, except it compares two slices.
func InEpsilonSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if expected == nil || actual == nil ||
reflect.TypeOf(actual).Kind() != reflect.Slice ||
reflect.TypeOf(expected).Kind() != reflect.Slice {
return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...)
}
actualSlice := reflect.ValueOf(actual)
expectedSlice := reflect.ValueOf(expected)
for i := 0; i < actualSlice.Len(); i++ {
result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta)
if !result {
return result
}
}
return true
}
/* /*
Errors Errors
*/ */

View File

@ -2,6 +2,7 @@ package assert
import ( import (
"errors" "errors"
"math"
"regexp" "regexp"
"testing" "testing"
"time" "time"
@ -115,10 +116,6 @@ func TestEqual(t *testing.T) {
if !Equal(mockT, uint64(123), uint64(123)) { if !Equal(mockT, uint64(123), uint64(123)) {
t.Error("Equal should return true") t.Error("Equal should return true")
} }
funcA := func() int { return 42 }
if !Equal(mockT, funcA, funcA) {
t.Error("Equal should return true")
}
} }
@ -406,19 +403,6 @@ func TestNotPanics(t *testing.T) {
} }
func TestEqual_Funcs(t *testing.T) {
type f func() int
f1 := func() int { return 1 }
f2 := func() int { return 2 }
f1Copy := f1
Equal(t, f1Copy, f1, "Funcs are the same and should be considered equal")
NotEqual(t, f1, f2, "f1 and f2 are different")
}
func TestNoError(t *testing.T) { func TestNoError(t *testing.T) {
mockT := new(testing.T) mockT := new(testing.T)
@ -669,6 +653,8 @@ func TestInDelta(t *testing.T) {
False(t, InDelta(mockT, 1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail") False(t, InDelta(mockT, 1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail")
False(t, InDelta(mockT, 2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail") False(t, InDelta(mockT, 2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail")
False(t, InDelta(mockT, "", nil, 1), "Expected non numerals to fail") False(t, InDelta(mockT, "", nil, 1), "Expected non numerals to fail")
False(t, InDelta(mockT, 42, math.NaN(), 0.01), "Expected NaN for actual to fail")
False(t, InDelta(mockT, math.NaN(), 42, 0.01), "Expected NaN for expected to fail")
cases := []struct { cases := []struct {
a, b interface{} a, b interface{}
@ -694,6 +680,27 @@ func TestInDelta(t *testing.T) {
} }
} }
func TestInDeltaSlice(t *testing.T) {
mockT := new(testing.T)
True(t, InDeltaSlice(mockT,
[]float64{1.001, 0.999},
[]float64{1, 1},
0.1), "{1.001, 0.009} is element-wise close to {1, 1} in delta=0.1")
True(t, InDeltaSlice(mockT,
[]float64{1, 2},
[]float64{0, 3},
1), "{1, 2} is element-wise close to {0, 3} in delta=1")
False(t, InDeltaSlice(mockT,
[]float64{1, 2},
[]float64{0, 3},
0.1), "{1, 2} is not element-wise close to {0, 3} in delta=0.1")
False(t, InDeltaSlice(mockT, "", nil, 1), "Expected non numeral slices to fail")
}
func TestInEpsilon(t *testing.T) { func TestInEpsilon(t *testing.T) {
mockT := new(testing.T) mockT := new(testing.T)
@ -733,6 +740,22 @@ func TestInEpsilon(t *testing.T) {
} }
func TestInEpsilonSlice(t *testing.T) {
mockT := new(testing.T)
True(t, InEpsilonSlice(mockT,
[]float64{2.2, 2.0},
[]float64{2.1, 2.1},
0.06), "{2.2, 2.0} is element-wise close to {2.1, 2.1} in espilon=0.06")
False(t, InEpsilonSlice(mockT,
[]float64{2.2, 2.0},
[]float64{2.1, 2.1},
0.04), "{2.2, 2.0} is not element-wise close to {2.1, 2.1} in espilon=0.04")
False(t, InEpsilonSlice(mockT, "", nil, 1), "Expected non numeral slices to fail")
}
func TestRegexp(t *testing.T) { func TestRegexp(t *testing.T) {
mockT := new(testing.T) mockT := new(testing.T)

View File

@ -1,4 +1,4 @@
// A set of comprehensive testing tools for use with the normal Go testing system. // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
// //
// Example Usage // Example Usage
// //
@ -45,7 +45,9 @@
// //
// Here is an overview of the assert functions: // Here is an overview of the assert functions:
// //
// assert.Equal(t, expected, actual [, message [, format-args]) // 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.NotEqual(t, notExpected, actual [, message [, format-args]])
// //
@ -98,7 +100,9 @@
// assert package contains Assertions object. it has assertion methods. // assert package contains Assertions object. it has assertion methods.
// //
// Here is an overview of the assert functions: // Here is an overview of the assert functions:
// assert.Equal(expected, actual [, message [, format-args]) // assert.Equal(expected, actual [, message [, format-args]])
//
// assert.EqualValues(expected, actual [, message [, format-args]])
// //
// assert.NotEqual(notExpected, actual [, message [, format-args]]) // assert.NotEqual(notExpected, actual [, message [, format-args]])
// //

View File

@ -2,10 +2,13 @@ package assert
import "time" import "time"
// Assertions provides assertion methods around the
// TestingT interface.
type Assertions struct { type Assertions struct {
t TestingT t TestingT
} }
// New makes a new Assertions object for the specified TestingT.
func New(t TestingT) *Assertions { func New(t TestingT) *Assertions {
return &Assertions{ return &Assertions{
t: t, t: t,
@ -85,7 +88,7 @@ func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
return Empty(a.t, object, msgAndArgs...) return Empty(a.t, object, msgAndArgs...)
} }
// Empty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or a // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or a
// slice with len == 0. // slice with len == 0.
// //
// if assert.NotEmpty(obj) { // if assert.NotEmpty(obj) {
@ -152,7 +155,7 @@ func (a *Assertions) NotContains(s, contains interface{}, msgAndArgs ...interfac
return NotContains(a.t, s, contains, msgAndArgs...) return NotContains(a.t, s, contains, msgAndArgs...)
} }
// Uses a Comparison to assert a complex condition. // Condition uses a Comparison to assert a complex condition.
func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool { func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
return Condition(a.t, comp, msgAndArgs...) return Condition(a.t, comp, msgAndArgs...)
} }

View File

@ -259,27 +259,12 @@ func TestNotPanicsWrapper(t *testing.T) {
} }
func TestEqualWrapper_Funcs(t *testing.T) {
assert := New(t)
type f func() int
var f1 f = func() int { return 1 }
var f2 f = func() int { return 2 }
var f1_copy f = f1
assert.Equal(f1_copy, f1, "Funcs are the same and should be considered equal")
assert.NotEqual(f1, f2, "f1 and f2 are different")
}
func TestNoErrorWrapper(t *testing.T) { func TestNoErrorWrapper(t *testing.T) {
assert := New(t) assert := New(t)
mockAssert := New(new(testing.T)) mockAssert := New(new(testing.T))
// start with a nil error // start with a nil error
var err error = nil var err error
assert.True(mockAssert.NoError(err), "NoError should return True for nil arg") assert.True(mockAssert.NoError(err), "NoError should return True for nil arg")
@ -295,7 +280,7 @@ func TestErrorWrapper(t *testing.T) {
mockAssert := New(new(testing.T)) mockAssert := New(new(testing.T))
// start with a nil error // start with a nil error
var err error = nil var err error
assert.False(mockAssert.Error(err), "Error should return False for nil arg") assert.False(mockAssert.Error(err), "Error should return False for nil arg")

View File

@ -59,9 +59,9 @@ func HTTPError(t TestingT, handler http.HandlerFunc, mode, url string, values ur
return code >= http.StatusBadRequest return code >= http.StatusBadRequest
} }
// 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, mode, 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(mode, url+"?"+values.Encode(), nil)
if err != nil { if err != nil {
@ -78,7 +78,7 @@ func HttpBody(handler http.HandlerFunc, mode, url string, values url.Values) str
// //
// 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, mode, url string, values url.Values, str interface{}) bool {
body := HttpBody(handler, mode, url, values) body := HTTPBody(handler, mode, url, values)
contains := strings.Contains(body, fmt.Sprint(str)) contains := strings.Contains(body, fmt.Sprint(str))
if !contains { if !contains {
@ -95,7 +95,7 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, mode, url string, va
// //
// 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, mode, url string, values url.Values, str interface{}) bool {
body := HttpBody(handler, mode, url, values) body := HTTPBody(handler, mode, url, values)
contains := strings.Contains(body, fmt.Sprint(str)) contains := strings.Contains(body, fmt.Sprint(str))
if contains { if contains {

View File

@ -2,12 +2,14 @@ package mock
import ( import (
"fmt" "fmt"
"github.com/stretchr/objx"
"github.com/stretchr/testify/assert"
"reflect" "reflect"
"runtime" "runtime"
"strings" "strings"
"sync" "sync"
"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
@ -37,6 +39,15 @@ type Call struct {
// The number of times to return the return arguments when setting // The number of times to return the return arguments when setting
// expectations. 0 means to always return the value. // expectations. 0 means to always return the value.
Repeatability int Repeatability int
// Holds a channel that will be used to block the Return until it either
// recieves a message or is closed. nil means it returns immediately.
WaitFor <-chan time.Time
// 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)
} }
// Mock is the workhorse used to track activity on another object. // Mock is the workhorse used to track activity on another object.
@ -87,6 +98,13 @@ func (m *Mock) TestData() objx.Map {
func (m *Mock) On(methodName string, arguments ...interface{}) *Mock { func (m *Mock) On(methodName string, arguments ...interface{}) *Mock {
m.onMethodName = methodName m.onMethodName = methodName
m.onMethodArguments = arguments m.onMethodArguments = arguments
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 return m
} }
@ -95,7 +113,10 @@ func (m *Mock) On(methodName string, arguments ...interface{}) *Mock {
// //
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2) // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2)
func (m *Mock) Return(returnArguments ...interface{}) *Mock { func (m *Mock) Return(returnArguments ...interface{}) *Mock {
m.ExpectedCalls = append(m.ExpectedCalls, Call{m.onMethodName, m.onMethodArguments, returnArguments, 0}) m.mutex.Lock()
defer m.mutex.Unlock()
m.ExpectedCalls = append(m.ExpectedCalls, Call{m.onMethodName, m.onMethodArguments, returnArguments, 0, nil, nil})
return m return m
} }
@ -103,14 +124,18 @@ func (m *Mock) Return(returnArguments ...interface{}) *Mock {
// //
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once() // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
func (m *Mock) Once() { func (m *Mock) Once() {
m.mutex.Lock()
m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 1 m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 1
m.mutex.Unlock()
} }
// Twice indicates that that the mock should only return the value twice. // Twice indicates that that the mock should only return the value twice.
// //
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice() // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()
func (m *Mock) Twice() { func (m *Mock) Twice() {
m.mutex.Lock()
m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 2 m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 2
m.mutex.Unlock()
} }
// Times indicates that that the mock should only return the indicated number // Times indicates that that the mock should only return the indicated number
@ -118,7 +143,42 @@ func (m *Mock) Twice() {
// //
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5) // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5)
func (m *Mock) Times(i int) { func (m *Mock) Times(i int) {
m.mutex.Lock()
m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = i m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = i
m.mutex.Unlock()
}
// 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.mutex.Lock()
m.ExpectedCalls[len(m.ExpectedCalls)-1].WaitFor = w
m.mutex.Unlock()
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.mutex.Lock()
m.ExpectedCalls[len(m.ExpectedCalls)-1].Run = fn
m.mutex.Unlock()
return m
} }
/* /*
@ -126,7 +186,7 @@ func (m *Mock) Times(i int) {
*/ */
func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) { func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) {
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)
@ -140,11 +200,10 @@ 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)
@ -180,10 +239,8 @@ func callString(method string, arguments Arguments, includeArgumentValues bool)
// Called tells the mock object that a method has been called, and gets an array // Called tells the mock object that a method has been called, and gets an array
// of arguments to return. Panics if the call is unexpected (i.e. not preceeded by // of arguments to return. Panics if the call is unexpected (i.e. not preceeded by
// appropriate .On .Return() calls) // 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 { 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 {
@ -195,8 +252,7 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
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:
// //
@ -211,6 +267,9 @@ 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 m.ExpectedCalls[found] = *call
@ -218,9 +277,22 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
call.Repeatability -= 1 call.Repeatability -= 1
m.ExpectedCalls[found] = *call 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}) m.mutex.Lock()
m.Calls = append(m.Calls, Call{functionName, arguments, make([]interface{}, 0), 0, nil, nil})
m.mutex.Unlock()
// block if specified
if call.WaitFor != nil {
<-call.WaitFor
}
if call.Run != nil {
call.Run(arguments)
}
return call.ReturnArguments return call.ReturnArguments
@ -246,12 +318,12 @@ 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()
for _, expectedCall := range expectedCalls {
switch { switch {
case !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments): case !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments):
somethingMissing = true somethingMissing = true
@ -266,7 +338,7 @@ func (m *Mock) AssertExpectations(t TestingT) bool {
} }
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
@ -275,7 +347,7 @@ 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++
} }
@ -286,7 +358,7 @@ func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls
// 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("%s", m.ExpectedCalls) t.Logf("%v", m.expectedCalls())
return false return false
} }
return true return true
@ -295,14 +367,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("%s", 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)
@ -318,6 +390,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

@ -4,6 +4,7 @@ import (
"errors" "errors"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"testing" "testing"
"time"
) )
/* /*
@ -29,13 +30,37 @@ func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) {
i.Called(yesorno) i.Called(yesorno)
} }
type ExampleType struct{} type ExampleType struct {
ran bool
}
func (i *TestExampleImplementation) TheExampleMethod3(et *ExampleType) error { func (i *TestExampleImplementation) TheExampleMethod3(et *ExampleType) error {
args := i.Called(et) args := i.Called(et)
return args.Error(0) return args.Error(0)
} }
func (i *TestExampleImplementation) TheExampleMethodFunc(fn func(string) error) error {
args := i.Called(fn)
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 {
args := i.Called(fn)
return args.Error(0)
}
/* /*
Mock Mock
*/ */
@ -76,6 +101,98 @@ func Test_Mock_On_WithArgs(t *testing.T) {
} }
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])
fn := func(string) error { return nil }
mockedService.TheExampleMethodFunc(fn)
}
func Test_Mock_On_WithVariadicFunc(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethodVariadic", []int{1, 2, 3}).Return(nil), &mockedService.Mock)
assert.Equal(t, "TheExampleMethodVariadic", mockedService.onMethodName)
assert.Equal(t, []int{1, 2, 3}, mockedService.onMethodArguments[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)
assert.Equal(t, mockedService.On("TheExampleMethodVariadicInterface", []interface{}{1, 2, 3}).Return(nil), &mockedService.Mock)
assert.Equal(t, "TheExampleMethodVariadicInterface", mockedService.onMethodName)
assert.Equal(t, []interface{}{1, 2, 3}, mockedService.onMethodArguments[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{}
assert.Equal(t, mockedService.On("TheExampleMethodVariadicInterface", expected).Return(nil), &mockedService.Mock)
assert.Equal(t, "TheExampleMethodVariadicInterface", mockedService.onMethodName)
assert.Equal(t, expected, mockedService.onMethodArguments[0])
assert.NotPanics(t, func() {
mockedService.TheExampleMethodVariadicInterface()
})
assert.Panics(t, func() {
mockedService.TheExampleMethodVariadicInterface(1, 2)
})
}
func Test_Mock_On_WithFuncPanics(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Panics(t, func() {
mockedService.On("TheExampleMethodFunc", func(string) error { return nil })
})
}
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])
fn := func(string) error { return nil }
mockedService.TheExampleMethodFuncType(fn)
}
func Test_Mock_Return(t *testing.T) { func Test_Mock_Return(t *testing.T) {
// make a test impl object // make a test impl object
@ -95,11 +212,93 @@ func Test_Mock_Return(t *testing.T) {
assert.Equal(t, "two", call.ReturnArguments[1]) assert.Equal(t, "two", call.ReturnArguments[1])
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)
} }
} }
func Test_Mock_Return_WaitUntil(t *testing.T) {
// make a test impl object
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)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) {
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.Equal(t, ch, call.WaitFor)
}
}
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)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) {
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)
}
}
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) {
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)
}
et := ExampleType{}
assert.Equal(t, false, et.ran)
mockedService.TheExampleMethod3(&et)
assert.Equal(t, true, et.ran)
}
func Test_Mock_Return_Once(t *testing.T) { func Test_Mock_Return_Once(t *testing.T) {
// make a test impl object // make a test impl object
@ -119,6 +318,7 @@ func Test_Mock_Return_Once(t *testing.T) {
assert.Equal(t, "two", call.ReturnArguments[1]) assert.Equal(t, "two", call.ReturnArguments[1])
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)
} }
@ -143,6 +343,7 @@ func Test_Mock_Return_Twice(t *testing.T) {
assert.Equal(t, "two", call.ReturnArguments[1]) assert.Equal(t, "two", call.ReturnArguments[1])
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)
} }
@ -167,6 +368,7 @@ func Test_Mock_Return_Times(t *testing.T) {
assert.Equal(t, "two", call.ReturnArguments[1]) assert.Equal(t, "two", call.ReturnArguments[1])
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)
} }
@ -274,6 +476,43 @@ func Test_Mock_Called(t *testing.T) {
} }
func asyncCall(m *Mock, ch chan Arguments) {
ch <- m.Called(1, 2, 3)
}
func Test_Mock_Called_blocks(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.Mock.On("asyncCall", 1, 2, 3).Return(5, "6", true).After(2 * time.Millisecond)
ch := make(chan Arguments)
go asyncCall(&mockedService.Mock, ch)
select {
case <-ch:
t.Fatal("should have waited")
case <-time.After(1 * time.Millisecond):
}
returnArguments := <-ch
if assert.Equal(t, 1, len(mockedService.Mock.Calls)) {
assert.Equal(t, "asyncCall", mockedService.Mock.Calls[0].Method)
assert.Equal(t, 1, mockedService.Mock.Calls[0].Arguments[0])
assert.Equal(t, 2, mockedService.Mock.Calls[0].Arguments[1])
assert.Equal(t, 3, mockedService.Mock.Calls[0].Arguments[2])
}
if assert.Equal(t, 3, len(returnArguments)) {
assert.Equal(t, 5, returnArguments[0])
assert.Equal(t, "6", returnArguments[1])
assert.Equal(t, true, returnArguments[2])
}
}
func Test_Mock_Called_For_Bounded_Repeatability(t *testing.T) { func Test_Mock_Called_For_Bounded_Repeatability(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService *TestExampleImplementation = new(TestExampleImplementation)

View File

@ -216,7 +216,7 @@ func TestFreeSpaceImagesInUseContainersAreIgnored(t *testing.T) {
spaceFreed, err := manager.freeSpace(2048) spaceFreed, err := manager.freeSpace(2048)
assert := assert.New(t) assert := assert.New(t)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(1024, spaceFreed) assert.EqualValues(1024, spaceFreed)
assert.Len(fakeDocker.RemovedImages, 1) assert.Len(fakeDocker.RemovedImages, 1)
assert.True(fakeDocker.RemovedImages.Has(imageName(0))) assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
} }
@ -245,7 +245,7 @@ func TestFreeSpaceRemoveByLeastRecentlyUsed(t *testing.T) {
spaceFreed, err := manager.freeSpace(1024) spaceFreed, err := manager.freeSpace(1024)
assert := assert.New(t) assert := assert.New(t)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(1024, spaceFreed) assert.EqualValues(1024, spaceFreed)
assert.Len(fakeDocker.RemovedImages, 1) assert.Len(fakeDocker.RemovedImages, 1)
assert.True(fakeDocker.RemovedImages.Has(imageName(0))) assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
} }
@ -277,7 +277,7 @@ func TestFreeSpaceTiesBrokenByDetectedTime(t *testing.T) {
spaceFreed, err := manager.freeSpace(1024) spaceFreed, err := manager.freeSpace(1024)
assert := assert.New(t) assert := assert.New(t)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(1024, spaceFreed) assert.EqualValues(1024, spaceFreed)
assert.Len(fakeDocker.RemovedImages, 1) assert.Len(fakeDocker.RemovedImages, 1)
assert.True(fakeDocker.RemovedImages.Has(imageName(0))) assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
} }
@ -302,7 +302,7 @@ func TestFreeSpaceImagesAlsoDoesLookupByRepoTags(t *testing.T) {
spaceFreed, err := manager.freeSpace(1024) spaceFreed, err := manager.freeSpace(1024)
assert := assert.New(t) assert := assert.New(t)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(1024, spaceFreed) assert.EqualValues(1024, spaceFreed)
assert.Len(fakeDocker.RemovedImages, 1) assert.Len(fakeDocker.RemovedImages, 1)
assert.True(fakeDocker.RemovedImages.Has(imageName(0))) assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
} }