From 51cd27a889a0135e59644c4f50213af06da3d1a6 Mon Sep 17 00:00:00 2001 From: ac7 Date: Mon, 3 Nov 2014 10:26:29 -0600 Subject: [PATCH 01/50] Wrap NoError message with quote marks Previous behavior was to print the error with no delimiters: No error is expected but got unexpected character in stream New behavior is to print the error surrounded by quotes: Recieved unexpected error "unexpected character in stream" --- assert/assertions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assert/assertions.go b/assert/assertions.go index 5de1ab1..61a5c77 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -695,7 +695,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`). From 1e710e53ab3a184bd9da3afe10880e0b4b0d3b9f Mon Sep 17 00:00:00 2001 From: Daniel Perez Date: Wed, 13 May 2015 15:54:04 +0900 Subject: [PATCH 02/50] Support map keys for Contains/NotContains assertion. --- assert/assertions.go | 16 ++++++++++++++-- assert/assertions_test.go | 28 ++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/assert/assertions.go b/assert/assertions.go index 818cd7b..7c0d67d 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -476,6 +476,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 +495,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 +517,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 { diff --git a/assert/assertions_test.go b/assert/assertions_test.go index d859c77..51f0f2a 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -255,6 +255,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 +276,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 +306,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 +352,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) { From d4befe148c6fba622e9fa7964605fa81c93ea370 Mon Sep 17 00:00:00 2001 From: Matt Carter Date: Tue, 19 May 2015 14:31:47 -0500 Subject: [PATCH 03/50] Updated README for versioning strategy --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a27eb86..e27b6b5 100644 --- a/README.md +++ b/README.md @@ -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. ------ From 9768526b706b87960cd70933a3d0d20604920ae5 Mon Sep 17 00:00:00 2001 From: Lee Packham Date: Wed, 25 Mar 2015 12:27:39 +0000 Subject: [PATCH 04/50] Fix race condition with ExpectedCalls There is race condition caused when a method being tested calls a mocked method within a go routine. For example, caching might be done a go routine and that caching might be mocked. There is already a mutex protecting the lists on the Mock object - however Return() appends to ExpectedCalls and findExpectedCall could run at the same time. --- mock/mock.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mock/mock.go b/mock/mock.go index fa8747e..168bba2 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -112,6 +112,9 @@ func (m *Mock) On(methodName string, arguments ...interface{}) *Mock { // // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2) func (m *Mock) Return(returnArguments ...interface{}) *Mock { + m.mutex.Lock() + defer m.mutex.Unlock() + m.ExpectedCalls = append(m.ExpectedCalls, Call{m.onMethodName, m.onMethodArguments, returnArguments, 0, nil, nil}) return m } From d6265bda1ab26613ff9d3ab5291cad88b0f54fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Jime=CC=81nez?= Date: Tue, 2 Jun 2015 19:59:43 +0100 Subject: [PATCH 05/50] Add test mocking variadic function --- mock/mock_test.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/mock/mock_test.go b/mock/mock_test.go index b7446ac..3b0b69a 100644 --- a/mock/mock_test.go +++ b/mock/mock_test.go @@ -44,6 +44,11 @@ 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) +} + type ExampleFuncType func(string) error func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error { @@ -105,6 +110,24 @@ func Test_Mock_On_WithFuncArg(t *testing.T) { } +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_WithFuncPanics(t *testing.T) { // make a test impl object var mockedService *TestExampleImplementation = new(TestExampleImplementation) From 4464dda05e74b94b8f58aefca98ed53d8e12d4d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Jime=CC=81nez?= Date: Tue, 2 Jun 2015 20:23:13 +0100 Subject: [PATCH 06/50] Add extra tests mocking variadic functions --- mock/mock_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/mock/mock_test.go b/mock/mock_test.go index 3b0b69a..b1ee954 100644 --- a/mock/mock_test.go +++ b/mock/mock_test.go @@ -49,6 +49,11 @@ func (i *TestExampleImplementation) TheExampleMethodVariadic(a ...int) error { 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 { @@ -128,6 +133,43 @@ func Test_Mock_On_WithVariadicFunc(t *testing.T) { } +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) From a7a0af787a562037e52c6e7a4c22fbc684afb62b Mon Sep 17 00:00:00 2001 From: Paul Bellamy Date: Thu, 4 Jun 2015 14:00:35 +0100 Subject: [PATCH 07/50] Add a basic stacktrace to the assertion output --- assert/assertions.go | 53 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/assert/assertions.go b/assert/assertions.go index 818cd7b..646d23d 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -10,6 +10,8 @@ import ( "runtime" "strings" "time" + "unicode" + "unicode/utf8" ) // TestingT is an interface wrapper around *testing.T @@ -64,28 +66,62 @@ 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 } + 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([]string{fmt.Sprintf("%s:%d", file, line)}, callers...) + } + + 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 +180,20 @@ func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { message := messageFromMsgAndArgs(msgAndArgs...) + locationInfo := strings.Join(CallerInfo(), "\n\r\t\t\t") if len(message) > 0 { t.Errorf("\r%s\r\tLocation:\t%s\n"+ "\r\tError:%s\n"+ "\r\tMessages:\t%s\n\r", getWhitespaceString(), - CallerInfo(), + locationInfo, indentMessageLines(failureMessage, 2), message) } else { t.Errorf("\r%s\r\tLocation:\t%s\n"+ "\r\tError:%s\n\r", getWhitespaceString(), - CallerInfo(), + locationInfo, indentMessageLines(failureMessage, 2)) } From 925c3ad43bafd87e3de78d272b799d74fbcc90b7 Mon Sep 17 00:00:00 2001 From: Paul Bellamy Date: Fri, 5 Jun 2015 10:13:41 +0100 Subject: [PATCH 08/50] Reverse the stacktrace on assertion output (to match panic) --- assert/assertions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assert/assertions.go b/assert/assertions.go index 646d23d..ae75302 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -88,7 +88,7 @@ func CallerInfo() []string { dir := parts[len(parts)-2] file = parts[len(parts)-1] if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" { - callers = append([]string{fmt.Sprintf("%s:%d", file, line)}, callers...) + callers = append(callers, fmt.Sprintf("%s:%d", file, line)) } f := runtime.FuncForPC(pc) From 0fd7b57c23515bbac29982f2918adeb78dced7aa Mon Sep 17 00:00:00 2001 From: Paul Bellamy Date: Fri, 5 Jun 2015 10:14:07 +0100 Subject: [PATCH 09/50] rename assert.locationInfo -> assert.errorTrace --- assert/assertions.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assert/assertions.go b/assert/assertions.go index ae75302..73afcac 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -180,20 +180,20 @@ func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { message := messageFromMsgAndArgs(msgAndArgs...) - locationInfo := strings.Join(CallerInfo(), "\n\r\t\t\t") + errorTrace := strings.Join(CallerInfo(), "\n\r\t\t\t") if len(message) > 0 { t.Errorf("\r%s\r\tLocation:\t%s\n"+ "\r\tError:%s\n"+ "\r\tMessages:\t%s\n\r", getWhitespaceString(), - locationInfo, + errorTrace, indentMessageLines(failureMessage, 2), message) } else { t.Errorf("\r%s\r\tLocation:\t%s\n"+ "\r\tError:%s\n\r", getWhitespaceString(), - locationInfo, + errorTrace, indentMessageLines(failureMessage, 2)) } From c0b6c3bbd7954e40c428a39680c198d436496a09 Mon Sep 17 00:00:00 2001 From: Paul Bellamy Date: Fri, 5 Jun 2015 14:01:19 +0100 Subject: [PATCH 10/50] Rename Location to Error Trace in failure output --- assert/assertions.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assert/assertions.go b/assert/assertions.go index 73afcac..7b5ce72 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -182,7 +182,7 @@ func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { 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(), @@ -190,7 +190,7 @@ func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { 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(), errorTrace, From b11fb1691542b198b0c1c2156b97a661f8b9c2d6 Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 5 Jun 2015 14:46:11 +0200 Subject: [PATCH 11/50] mock: fix races to m.Calls/m.ExpectedCalls Fixes races inside the mock package caused by unsychronized reads/writes of m.Calls/m.ExpectedCalls. --- mock/mock.go | 71 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/mock/mock.go b/mock/mock.go index 168bba2..007643f 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -2,13 +2,14 @@ package mock import ( "fmt" - "github.com/stretchr/objx" - "github.com/stretchr/testify/assert" "reflect" "runtime" "strings" "sync" "time" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" ) // TestingT is an interface wrapper around *testing.T @@ -123,14 +124,18 @@ func (m *Mock) Return(returnArguments ...interface{}) *Mock { // // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once() func (m *Mock) Once() { + m.mutex.Lock() m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 1 + m.mutex.Unlock() } // 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.mutex.Lock() m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 2 + m.mutex.Unlock() } // Times indicates that that the mock should only return the indicated number @@ -138,7 +143,9 @@ func (m *Mock) Twice() { // // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5) func (m *Mock) Times(i int) { + m.mutex.Lock() 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 @@ -146,7 +153,9 @@ func (m *Mock) Times(i int) { // // 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 } @@ -166,7 +175,9 @@ func (m *Mock) After(d time.Duration) *Mock { // 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 } @@ -175,7 +186,7 @@ func (m *Mock) Run(fn func(Arguments)) *Mock { */ 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 { _, diffCount := call.Arguments.Diff(arguments) @@ -189,11 +200,10 @@ 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) @@ -231,9 +241,6 @@ 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 { @@ -245,8 +252,7 @@ func (m *Mock) Called(arguments ...interface{}) Arguments { 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: // @@ -261,16 +267,23 @@ 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 + m.ExpectedCalls[found] = *call + case call.Repeatability > 1: + call.Repeatability -= 1 + m.ExpectedCalls[found] = *call + } + m.mutex.Unlock() } // add the call + 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 { @@ -305,12 +318,12 @@ 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 { + expectedCalls := m.expectedCalls() + for _, expectedCall := range expectedCalls { switch { case !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments): somethingMissing = true @@ -325,7 +338,7 @@ func (m *Mock) AssertExpectations(t TestingT) bool { } 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 @@ -334,7 +347,7 @@ 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++ } @@ -345,7 +358,7 @@ func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls // 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 @@ -354,14 +367,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) @@ -377,6 +390,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 */ From c769e40e8bd93cd041b6984c3ca43b42784b89fe Mon Sep 17 00:00:00 2001 From: Andrew Burns Date: Thu, 11 Jun 2015 14:33:49 -0600 Subject: [PATCH 12/50] Handle `` files in `CallerInfo()` Fixes #180 --- assert/assertions.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/assert/assertions.go b/assert/assertions.go index 7b5ce72..48a6d5e 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -84,6 +84,11 @@ func CallerInfo() []string { return nil } + // This is a huge edge case, but it will panic if this is the case, see #180 + if file == "" { + break + } + parts := strings.Split(file, "/") dir := parts[len(parts)-2] file = parts[len(parts)-1] From abc938a12b76ff35e817db5d65b8d509c2efc8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Jime=CC=81nez?= Date: Sun, 14 Jun 2015 19:29:18 +0100 Subject: [PATCH 13/50] Add test to avoid regression of issue #180 --- assert/assertions_test.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index d859c77..15117d2 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -2,6 +2,7 @@ package assert import ( "errors" + "io" "math" "regexp" "testing" @@ -789,3 +790,24 @@ func TestRegexp(t *testing.T) { True(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str)) } } + +func testAutogeneratedFucntion() { + 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() { + testAutogeneratedFucntion() + }) +} From ddcad49ec6b8f31bc3daf3a1fbea7eac58d61ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Jime=CC=81nez?= Date: Mon, 15 Jun 2015 21:31:24 +0100 Subject: [PATCH 14/50] Fix typo in test function name --- assert/assertions_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 15117d2..36c671e 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -791,7 +791,7 @@ func TestRegexp(t *testing.T) { } } -func testAutogeneratedFucntion() { +func testAutogeneratedFunction() { defer func() { if err := recover(); err == nil { panic("did not panic") @@ -808,6 +808,6 @@ func testAutogeneratedFucntion() { func TestCallerInfoWithAutogeneratedFunctions(t *testing.T) { NotPanics(t, func() { - testAutogeneratedFucntion() + testAutogeneratedFunction() }) } From 6756bdecf463d06f0f6aabce65a694531a10aa1e Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Sun, 21 Jun 2015 07:39:50 +1000 Subject: [PATCH 15/50] Adjust NotNil error message --- assert/assertions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assert/assertions.go b/assert/assertions.go index 48a6d5e..fbf03f4 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -301,7 +301,7 @@ func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { } if !success { - Fail(t, "Expected not to be nil.", msgAndArgs...) + Fail(t, "Expected value not to be nil.", msgAndArgs...) } return success From 84e2423404381868ce17a659342774bc5f3e48b1 Mon Sep 17 00:00:00 2001 From: Boris Pruessmann Date: Fri, 3 Jul 2015 13:30:03 +0200 Subject: [PATCH 16/50] AssertNumberOfCalls: wrong order of arguments The assert.Equal called had the actual and expected values mixed up. --- mock/mock.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mock/mock.go b/mock/mock.go index 007643f..515eec7 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -352,7 +352,7 @@ func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls 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. From 6b09f60392f1d1bb7d55dd0e081a94e93f620aa6 Mon Sep 17 00:00:00 2001 From: davelondon Date: Sun, 5 Jul 2015 10:37:27 -0400 Subject: [PATCH 17/50] Update assertions.go Fixed incorrect order of parameters to Equal --- assert/assertions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assert/assertions.go b/assert/assertions.go index fbf03f4..ee5967c 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -842,7 +842,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) } From 74bbd8924095b918ff1731ba49474342746ac5be Mon Sep 17 00:00:00 2001 From: Patrick Hemmer Date: Wed, 22 Jul 2015 15:56:30 -0400 Subject: [PATCH 18/50] remove overview sections from documentation --- assert/doc.go | 109 ------------------------------------------------- require/doc.go | 50 ----------------------- 2 files changed, 159 deletions(-) diff --git a/assert/doc.go b/assert/doc.go index f678106..767a637 100644 --- a/assert/doc.go +++ b/assert/doc.go @@ -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 diff --git a/require/doc.go b/require/doc.go index 7b38438..bc16147 100644 --- a/require/doc.go +++ b/require/doc.go @@ -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 From 2161431195983d630f604089d837f821c0cd7521 Mon Sep 17 00:00:00 2001 From: Ivan Fraixedes Date: Tue, 28 Jul 2015 12:31:24 +0100 Subject: [PATCH 19/50] Update README.md Added link to the api documentation for `require` --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e27b6b5..1f57561 100644 --- a/README.md +++ b/README.md @@ -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. From 81bd467d7c689f42cae012c585b6a3827b730e98 Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Thu, 6 Aug 2015 17:14:15 -0400 Subject: [PATCH 20/50] Use "method" rather than "mode" for http tests Use `method` (this is what http.NewRequest and the HTTP standard in general calls this) rather than `mode` for `"GET"`, `"POST"`, etc. --- assert/http_assertions.go | 48 +++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/assert/http_assertions.go b/assert/http_assertions.go index 1246e58..437a86c 100644 --- a/assert/http_assertions.go +++ b/assert/http_assertions.go @@ -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) } From 9c13092f453154eb4f4782c7f8e2dcc619936922 Mon Sep 17 00:00:00 2001 From: Mawueli Kofi Adzoe Date: Wed, 12 Aug 2015 11:24:55 +0000 Subject: [PATCH 21/50] Fix tiny typo --- assert/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assert/doc.go b/assert/doc.go index f678106..d10a8a1 100644 --- a/assert/doc.go +++ b/assert/doc.go @@ -17,7 +17,7 @@ // // } // -// if you assert many times, use the below: +// if you assert many times, use the format below: // // import ( // "testing" From 8512261d41035ecb44deda0c37e078c8b01b9627 Mon Sep 17 00:00:00 2001 From: Will Faught Date: Mon, 24 Aug 2015 15:53:36 -0700 Subject: [PATCH 22/50] Add Zero and NotZero assertions and requirements Zero returns true if the value equals the value's type's zero value. NotZero returns the opposite of Zero. --- assert/assertions.go | 20 +++++- assert/assertions_test.go | 92 ++++++++++++++++++++++++++++ assert/forward_assertions.go | 10 +++ assert/forward_assertions_test.go | 26 ++++++++ require/forward_requirements.go | 10 +++ require/forward_requirements_test.go | 24 ++++++++ require/requirements.go | 14 +++++ require/requirements_test.go | 22 +++++++ 8 files changed, 216 insertions(+), 2 deletions(-) diff --git a/assert/assertions.go b/assert/assertions.go index fbf03f4..0a01629 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -334,7 +334,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), @@ -360,7 +360,7 @@ func isEmpty(object interface{}) bool { return true } - for _, v := range zeros { + for _, v := range numericZeros { if object == v { return true } @@ -893,3 +893,19 @@ 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 +} diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 36c671e..ce4ecae 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -4,11 +4,79 @@ import ( "errors" "io" "math" + "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() @@ -811,3 +879,27 @@ func TestCallerInfoWithAutogeneratedFunctions(t *testing.T) { 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))) + } +} diff --git a/assert/forward_assertions.go b/assert/forward_assertions.go index d8d3f53..dc14771 100644 --- a/assert/forward_assertions.go +++ b/assert/forward_assertions.go @@ -263,3 +263,13 @@ 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...) +} diff --git a/assert/forward_assertions_test.go b/assert/forward_assertions_test.go index 3df3f39..280d0ab 100644 --- a/assert/forward_assertions_test.go +++ b/assert/forward_assertions_test.go @@ -509,3 +509,29 @@ 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) + } +} diff --git a/require/forward_requirements.go b/require/forward_requirements.go index 069d419..d58512f 100644 --- a/require/forward_requirements.go +++ b/require/forward_requirements.go @@ -209,3 +209,13 @@ 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...) +} diff --git a/require/forward_requirements_test.go b/require/forward_requirements_test.go index 02be291..404962d 100644 --- a/require/forward_requirements_test.go +++ b/require/forward_requirements_test.go @@ -258,3 +258,27 @@ 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") + } +} diff --git a/require/requirements.go b/require/requirements.go index 122a3f3..cfc1887 100644 --- a/require/requirements.go +++ b/require/requirements.go @@ -269,3 +269,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() + } +} diff --git a/require/requirements_test.go b/require/requirements_test.go index 9131b2f..2c9d351 100644 --- a/require/requirements_test.go +++ b/require/requirements_test.go @@ -264,3 +264,25 @@ 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") + } +} From 05776ad5412cefeda2517320bc88fd365a9769e2 Mon Sep 17 00:00:00 2001 From: Siva Gollapalli Date: Tue, 25 Aug 2015 20:49:33 +0530 Subject: [PATCH 23/50] EqualError error output swaps the actual and expected values --- assert/assertions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assert/assertions.go b/assert/assertions.go index fbf03f4..17a7a6b 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -239,7 +239,7 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) if !ObjectsAreEqual(expected, actual) { return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+ - " != %#v (actual)", expected, actual), msgAndArgs...) + " != %#v (actual)", actual, expected), msgAndArgs...) } return true From 80b247df3c54f1f299bf104715356eab26778695 Mon Sep 17 00:00:00 2001 From: Siva Gollapalli Date: Wed, 26 Aug 2015 19:31:23 +0530 Subject: [PATCH 24/50] Display actual and expected values on NotEqual --- assert/assertions.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assert/assertions.go b/assert/assertions.go index 17a7a6b..56758bc 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -492,7 +492,8 @@ 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("Not Equal: %#v (expected)\n"+ + " != %#v (actual)", actual, expected), msgAndArgs...) } return true From b60ec447d6993e172a232a2be896a2f59a0c1145 Mon Sep 17 00:00:00 2001 From: Siva Gollapalli Date: Wed, 26 Aug 2015 19:40:56 +0530 Subject: [PATCH 25/50] Modified the error message for NotEqual --- assert/assertions.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/assert/assertions.go b/assert/assertions.go index 56758bc..54aa49e 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -492,8 +492,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, fmt.Sprintf("Not Equal: %#v (expected)\n"+ - " != %#v (actual)", actual, expected), msgAndArgs...) + return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) } return true From 49804a382a4e56090c608f1b353a8f6e86e184eb Mon Sep 17 00:00:00 2001 From: Trent Clarke Date: Thu, 27 Aug 2015 21:57:07 +1000 Subject: [PATCH 26/50] Allows mock call expectations to be defined in arbitrary order Originally the expctations required that the return values be specified immediately after the method name and arguments, otherwise the call setup will either panic (best case) or silently modify the *previous* call specification (worst case). This change moves the Return(), Run(), Once(), etc methods onto the Call struct, and changes the chaining behaviour so that they modify the Call data directly rather than referencing the last item in the ExpectedCalls array. --- mock/mock.go | 222 +++++++++++++++------------- mock/mock_test.go | 369 ++++++++++++++++++++++++++++------------------ 2 files changed, 344 insertions(+), 247 deletions(-) diff --git a/mock/mock.go b/mock/mock.go index 007643f..4d05e1b 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -25,6 +25,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 @@ -47,24 +48,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 @@ -95,95 +185,23 @@ 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.mutex.Lock() - defer m.mutex.Unlock() - - 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.mutex.Lock() - m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 1 - m.mutex.Unlock() -} - -// 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.mutex.Lock() - m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 2 - m.mutex.Unlock() -} - -// 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.mutex.Lock() - 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 -} - -/* - Recording and responding to activity -*/ +// /* +// Recording and responding to activity +// */ func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) { for i, call := range m.expectedCalls() { @@ -191,7 +209,7 @@ func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, * _, diffCount := call.Arguments.Diff(arguments) if diffCount == 0 { - return i, &call + return i, call } } @@ -209,7 +227,7 @@ func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, * _, tempDiffCount := call.Arguments.Diff(arguments) if tempDiffCount < diffCount || diffCount == 0 { diffCount = tempDiffCount - closestCall = &call + closestCall = call } } @@ -272,17 +290,16 @@ func (m *Mock) Called(arguments ...interface{}) Arguments { switch { case call.Repeatability == 1: call.Repeatability = -1 - m.ExpectedCalls[found] = *call + case call.Repeatability > 1: call.Repeatability -= 1 - m.ExpectedCalls[found] = *call } m.mutex.Unlock() } // add the call m.mutex.Lock() - m.Calls = append(m.Calls, Call{functionName, arguments, make([]interface{}, 0), 0, nil, nil}) + m.Calls = append(m.Calls, *newCall(m, functionName, arguments...)) m.mutex.Unlock() // block if specified @@ -290,12 +307,11 @@ func (m *Mock) Called(arguments ...interface{}) Arguments { <-call.WaitFor } - if call.Run != nil { - call.Run(arguments) + if call.RunFn != nil { + call.RunFn(arguments) } return call.ReturnArguments - } /* @@ -390,10 +406,10 @@ func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool { return false } -func (m *Mock) expectedCalls() []Call { +func (m *Mock) expectedCalls() []*Call { m.mutex.Lock() defer m.mutex.Unlock() - return append([]Call{}, m.ExpectedCalls...) + return append([]*Call{}, m.ExpectedCalls...) } func (m *Mock) calls() []Call { diff --git a/mock/mock_test.go b/mock/mock_test.go index b1ee954..1315cec 100644 --- a/mock/mock_test.go +++ b/mock/mock_test.go @@ -3,6 +3,7 @@ package mock import ( "errors" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "testing" "time" ) @@ -73,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) { @@ -83,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) { @@ -93,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) { @@ -106,13 +131,20 @@ 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) { @@ -120,9 +152,13 @@ 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]) + 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) @@ -138,9 +174,12 @@ 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]) + 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) @@ -157,9 +196,13 @@ func Test_Mock_On_WithVariadicFuncWithEmptyInterfaceArray(t *testing.T) { 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]) + 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() @@ -184,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) { @@ -198,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) { @@ -224,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) { @@ -249,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) } @@ -274,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) { @@ -304,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) { @@ -329,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) { @@ -354,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) { @@ -379,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) { @@ -517,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) @@ -716,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")) From 69ff3e840b8c46957c9400f98568fe6c8070be11 Mon Sep 17 00:00:00 2001 From: Daniel Chatfield Date: Thu, 27 Aug 2015 16:56:39 +0100 Subject: [PATCH 27/50] Fix order of params in Equal --- assert/assertions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assert/assertions.go b/assert/assertions.go index aa2e351..59b30eb 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -239,7 +239,7 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) if !ObjectsAreEqual(expected, actual) { return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+ - " != %#v (actual)", actual, expected), msgAndArgs...) + " != %#v (actual)", expected, actual), msgAndArgs...) } return true From 5d8c1da624bd0f8d59e305f509b126343899698c Mon Sep 17 00:00:00 2001 From: Jonathan Camenisch Date: Thu, 27 Aug 2015 23:37:31 -0400 Subject: [PATCH 28/50] Fix param order in ObjectsAreEqualValues after type conversion --- assert/assertions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assert/assertions.go b/assert/assertions.go index 59b30eb..023b1c3 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -54,7 +54,7 @@ func ObjectsAreEqualValues(expected, actual interface{}) bool { expectedValue := reflect.ValueOf(expected) if expectedValue.Type().ConvertibleTo(actualType) { // Attempt comparison after type conversion - if reflect.DeepEqual(actual, expectedValue.Convert(actualType).Interface()) { + if reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) { return true } } From 1cb1359759dc647aa6bb7cd8bfa079a0f6daed5f Mon Sep 17 00:00:00 2001 From: James Aguilar Date: Fri, 28 Aug 2015 15:09:49 -0700 Subject: [PATCH 29/50] Remove unnecessary branches. reflect.DeepEqual already returns exactly what we want in both of these cases. --- assert/assertions.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/assert/assertions.go b/assert/assertions.go index 023b1c3..fc67503 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -35,11 +35,7 @@ func ObjectsAreEqual(expected, actual interface{}) bool { return expected == actual } - if reflect.DeepEqual(expected, actual) { - return true - } - - return false + return reflect.DeepEqual(expected, actual) } @@ -54,9 +50,7 @@ func ObjectsAreEqualValues(expected, actual interface{}) bool { expectedValue := reflect.ValueOf(expected) if expectedValue.Type().ConvertibleTo(actualType) { // Attempt comparison after type conversion - if reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) { - return true - } + return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) } return false From 930ea90dbd163f5a9e1452b2eb60be94c5cbf277 Mon Sep 17 00:00:00 2001 From: Julian Cooper Date: Wed, 23 Sep 2015 10:34:52 -0700 Subject: [PATCH 30/50] Added assertion/requirement that checks if two JSON strings represent equivalent objects --- assert/assertions.go | 35 ++++++++++++++++++ assert/assertions_test.go | 17 ++++++++- assert/forward_assertions.go | 9 +++++ assert/forward_assertions_test.go | 41 +++++++++++++++++++++ require/forward_requirements.go | 9 +++++ require/forward_requirements_test.go | 53 ++++++++++++++++++++++++++++ require/requirements.go | 35 ++++++++++++++++++ require/requirements_test.go | 50 ++++++++++++++++++++++++++ 8 files changed, 248 insertions(+), 1 deletion(-) diff --git a/assert/assertions.go b/assert/assertions.go index 023b1c3..b4d863f 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -3,6 +3,7 @@ package assert import ( "bufio" "bytes" + "encoding/json" "fmt" "math" "reflect" @@ -909,3 +910,37 @@ func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { } 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 { + expectSlice := false + expectedJSONAsMap := make(map[string]interface{}) + expectedJSONAsSlice := make([]interface{}, 0, 0) + + actualJSONAsMap := make(map[string]interface{}) + actualJSONAsSlice := make([]interface{}, 0, 0) + + if err := json.Unmarshal([]byte(expected), &expectedJSONAsMap); err != nil { + if err := json.Unmarshal([]byte(expected), &expectedJSONAsSlice); err == nil { + expectSlice = true + } else { + return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...) + } + } + + if expectSlice { + if err := json.Unmarshal([]byte(actual), &actualJSONAsSlice); 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, expectedJSONAsSlice, actualJSONAsSlice, msgAndArgs...) + } else { + if err := json.Unmarshal([]byte(actual), &actualJSONAsMap); 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, expectedJSONAsMap, actualJSONAsMap, msgAndArgs...) + } +} diff --git a/assert/assertions_test.go b/assert/assertions_test.go index ce4ecae..a8daded 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -11,7 +11,7 @@ import ( ) var ( - i interface{} + i interface{} zeros = []interface{}{ false, byte(0), @@ -903,3 +903,18 @@ func TestNotZero(t *testing.T) { True(t, NotZero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test))) } } + +func TestJSONEq(t *testing.T) { + mockT := new(testing.T) + + True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)) + True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)) + 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}")) + True(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)) + False(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)) + False(t, JSONEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)) + False(t, JSONEq(mockT, `{"foo": "bar"}`, "Not JSON")) + False(t, JSONEq(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`)) + False(t, JSONEq(mockT, "Not JSON", "Not JSON")) +} diff --git a/assert/forward_assertions.go b/assert/forward_assertions.go index dc14771..3a21ee9 100644 --- a/assert/forward_assertions.go +++ b/assert/forward_assertions.go @@ -273,3 +273,12 @@ func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool { 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...) +} diff --git a/assert/forward_assertions_test.go b/assert/forward_assertions_test.go index 280d0ab..3678ae7 100644 --- a/assert/forward_assertions_test.go +++ b/assert/forward_assertions_test.go @@ -535,3 +535,44 @@ func TestNotZeroWrapper(t *testing.T) { assert.True(mockAssert.NotZero(test), "Zero should return false for %v", test) } } + +func TestJSONEqWrapper(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") + } + + if !assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) { + t.Error("JSONEq should return true") + } + + 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") + } + + if !assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) { + t.Error("JSONEq should return true") + } + + if assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) { + t.Error("JSONEq should return false") + } + + if assert.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) { + t.Error("JSONEq should return false") + } + + if assert.JSONEq(`{"foo": "bar"}`, "Not JSON") { + t.Error("JSONEq should return false for invalid JSON") + } + + if assert.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`) { + t.Error("JSONEq should return false") + } + + if assert.JSONEq("Not JSON", "Not JSON") { + t.Error("JSONEq should return false") + } +} diff --git a/require/forward_requirements.go b/require/forward_requirements.go index d58512f..035ecee 100644 --- a/require/forward_requirements.go +++ b/require/forward_requirements.go @@ -219,3 +219,12 @@ func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) { 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...) +} diff --git a/require/forward_requirements_test.go b/require/forward_requirements_test.go index 404962d..475c63b 100644 --- a/require/forward_requirements_test.go +++ b/require/forward_requirements_test.go @@ -282,3 +282,56 @@ func TestNotZeroWrapper(t *testing.T) { t.Error("Check should fail") } } + +func TestJSONEqWrapper(t *testing.T) { + // mockRequire := New(new(testing.T)) + + mockT := new(MockT) + mockRequire := New(mockT) + + mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) + if mockT.Failed { + t.Error("JSONEq should pass") + } + + mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) + if mockT.Failed { + t.Error("JSONEq should pass") + } + + 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("JSONEq should pass") + } + + mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) + if mockT.Failed { + t.Error("JSONEq should pass") + } + + mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) + if !mockT.Failed { + t.Error("JSONEq should fail") + } + + mockRequire.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) + if !mockT.Failed { + t.Error("JSONEq should fail") + } + + mockRequire.JSONEq(`{"foo": "bar"}`, "Not JSON") + if !mockT.Failed { + t.Error("JSONEq should fail") + } + + mockRequire.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`) + if !mockT.Failed { + t.Error("JSONEq should fail") + } + + mockRequire.JSONEq("Not JSON", "Not JSON") + if !mockT.Failed { + t.Error("JSONEq should fail") + } +} diff --git a/require/requirements.go b/require/requirements.go index cfc1887..9de321f 100644 --- a/require/requirements.go +++ b/require/requirements.go @@ -1,6 +1,7 @@ package require import ( + "encoding/json" "time" "github.com/stretchr/testify/assert" @@ -228,6 +229,40 @@ 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{}) { + expectSlice := false + expectedJSONAsMap := make(map[string]interface{}) + expectedJSONAsSlice := make([]interface{}, 0, 0) + + actualJSONAsMap := make(map[string]interface{}) + actualJSONAsSlice := make([]interface{}, 0, 0) + + if err := json.Unmarshal([]byte(expected), &expectedJSONAsMap); err != nil { + if err := json.Unmarshal([]byte(expected), &expectedJSONAsSlice); err == nil { + expectSlice = true + } else { + t.FailNow() + } + } + + if expectSlice { + if err := json.Unmarshal([]byte(actual), &actualJSONAsSlice); err != nil { + t.FailNow() + } + Equal(t, expectedJSONAsSlice, actualJSONAsSlice, msgAndArgs...) + } else { + if err := json.Unmarshal([]byte(actual), &actualJSONAsMap); err != nil { + t.FailNow() + } + Equal(t, expectedJSONAsMap, actualJSONAsMap, msgAndArgs...) + } +} + /* Errors */ diff --git a/require/requirements_test.go b/require/requirements_test.go index 2c9d351..dcc56e0 100644 --- a/require/requirements_test.go +++ b/require/requirements_test.go @@ -286,3 +286,53 @@ func TestNotZero(t *testing.T) { t.Error("Check should fail") } } + +func TestJSONEq(t *testing.T) { + mockT := new(MockT) + + JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) + if mockT.Failed { + t.Error("Check should pass") + } + + JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) + if mockT.Failed { + t.Error("Check should pass") + } + + 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") + } + + JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) + if mockT.Failed { + t.Error("Check should pass") + } + + JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) + if !mockT.Failed { + t.Error("Check should fail") + } + + JSONEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) + if !mockT.Failed { + t.Error("Check should fail") + } + + JSONEq(mockT, `{"foo": "bar"}`, "Not JSON") + if !mockT.Failed { + t.Error("Check should fail") + } + + JSONEq(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`) + if !mockT.Failed { + t.Error("Check should fail") + } + + JSONEq(mockT, "Not JSON", "Not JSON") + if !mockT.Failed { + t.Error("Check should fail") + } +} From fb64a0ab08a14b72fcce748f8fd40119e0dac8ec Mon Sep 17 00:00:00 2001 From: Bryan Matsuo Date: Wed, 23 Sep 2015 23:22:23 -0700 Subject: [PATCH 31/50] Fix NotNil assertion for typed nil values The NotNil assertion had an error in its handling of typed nil values. This change makes use of the helper function isNil (used by the Nil assertion). The helper function has correct handling of typed nil values and when negated provides the expected semantics for `assert.NotNil(t, x)`. if x == nil { assert.Fail(t, "is nil", x) } --- assert/assertions.go | 20 +++----------------- assert/assertions_test.go | 5 ++++- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/assert/assertions.go b/assert/assertions.go index 023b1c3..22e3a6b 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -287,24 +287,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 value 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. diff --git a/assert/assertions_test.go b/assert/assertions_test.go index ce4ecae..afc2e41 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -11,7 +11,7 @@ import ( ) var ( - i interface{} + i interface{} zeros = []interface{}{ false, byte(0), @@ -198,6 +198,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)") + } } From ee60e76e549e5c318da9a01f6102484e8ca3cbbd Mon Sep 17 00:00:00 2001 From: Bryan Matsuo Date: Thu, 24 Sep 2015 10:02:27 -0700 Subject: [PATCH 32/50] Test Nil assertion behavior for typed nil values --- assert/assertions_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index afc2e41..9c5bef8 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -211,6 +211,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") } From b1b3c1e4c0d8770cb741e206fc14a99768c7f11b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Jime=CC=81nez?= Date: Tue, 29 Sep 2015 01:58:17 +0100 Subject: [PATCH 33/50] Add Go 1.4 and 1.5 to .travis.yml --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0595ddb..8f90db6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ go: - 1.1 - 1.2 - 1.3 + - 1.4 + - 1.5 - tip script: From 0df687d7a97f9021b6a5dda4832b1b1a101d6830 Mon Sep 17 00:00:00 2001 From: Srini Brahmaroutu Date: Mon, 28 Sep 2015 22:03:20 +0000 Subject: [PATCH 34/50] Due to function name format differences, code fails with GCCGO Signed-off-by: Srini Brahmaroutu --- mock/mock.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mock/mock.go b/mock/mock.go index 9be2031..88ac0ee 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -3,6 +3,7 @@ package mock import ( "fmt" "reflect" + "regexp" "runtime" "strings" "sync" @@ -265,6 +266,14 @@ func (m *Mock) Called(arguments ...interface{}) Arguments { 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
. + re := regexp.MustCompile("\\.pN\\d+_") + if re.MatchString(functionPath) { + functionPath = re.Split(functionPath, -1)[0] + } parts := strings.Split(functionPath, ".") functionName := parts[len(parts)-1] From 3c35d25e9b00eece24b06de0353305176325d424 Mon Sep 17 00:00:00 2001 From: Levi Corcoran Date: Wed, 7 Oct 2015 16:34:11 -0500 Subject: [PATCH 35/50] fix race conditions related to mutation of expectedCall.Repeatability --- mock/mock.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/mock/mock.go b/mock/mock.go index 88ac0ee..af201ae 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -205,7 +205,9 @@ func (self *Mock) On(methodName string, arguments ...interface{}) *Call { // */ func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) { - for i, call := range m.expectedCalls() { + 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) @@ -349,16 +351,19 @@ func (m *Mock) AssertExpectations(t TestingT) bool { // iterate through each expectation expectedCalls := m.expectedCalls() for _, expectedCall := range expectedCalls { - switch { - case !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments): + 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() } } From 7f6cb13c5cb6a8b9cbf0bc473c59979c8ce477f6 Mon Sep 17 00:00:00 2001 From: Julian Cooper Date: Tue, 13 Oct 2015 13:36:47 -0700 Subject: [PATCH 36/50] split JSONEq tests into individual assertions from one monolithic test --- assert/assertions_test.go | 40 ++++++++++- assert/forward_assertions_test.go | 39 +++++++++- require/forward_requirements_test.go | 103 ++++++++++++++++++++++++++- require/requirements_test.go | 35 ++++++++- 4 files changed, 208 insertions(+), 9 deletions(-) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index a8daded..5c582b8 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -904,17 +904,53 @@ func TestNotZero(t *testing.T) { } } -func TestJSONEq(t *testing.T) { +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"]`)) +} diff --git a/assert/forward_assertions_test.go b/assert/forward_assertions_test.go index 3678ae7..22e1df1 100644 --- a/assert/forward_assertions_test.go +++ b/assert/forward_assertions_test.go @@ -536,43 +536,76 @@ func TestNotZeroWrapper(t *testing.T) { } } -func TestJSONEqWrapper(t *testing.T) { +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 for invalid 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") + } +} diff --git a/require/forward_requirements_test.go b/require/forward_requirements_test.go index 475c63b..02be59c 100644 --- a/require/forward_requirements_test.go +++ b/require/forward_requirements_test.go @@ -284,8 +284,6 @@ func TestNotZeroWrapper(t *testing.T) { } func TestJSONEqWrapper(t *testing.T) { - // mockRequire := New(new(testing.T)) - mockT := new(MockT) mockRequire := New(mockT) @@ -335,3 +333,104 @@ func TestJSONEqWrapper(t *testing.T) { t.Error("JSONEq 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") + } +} diff --git a/require/requirements_test.go b/require/requirements_test.go index dcc56e0..d2ccc99 100644 --- a/require/requirements_test.go +++ b/require/requirements_test.go @@ -287,52 +287,83 @@ func TestNotZero(t *testing.T) { } } -func TestJSONEq(t *testing.T) { +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") + } +} From 2d0c0a478c95a7b6cfc1b3540959a48ce8f44c0c Mon Sep 17 00:00:00 2001 From: Julian Cooper Date: Tue, 13 Oct 2015 14:13:42 -0700 Subject: [PATCH 37/50] JSONEq unmarshal's into an interface{} instead of attemping Map and Slice unmarshallings --- assert/assertions.go | 29 +++++++---------------------- require/requirements.go | 29 +++++++---------------------- 2 files changed, 14 insertions(+), 44 deletions(-) diff --git a/assert/assertions.go b/assert/assertions.go index b4d863f..09b3898 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -917,30 +917,15 @@ func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { // // Returns whether the assertion was successful (true) or not (false). func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { - expectSlice := false - expectedJSONAsMap := make(map[string]interface{}) - expectedJSONAsSlice := make([]interface{}, 0, 0) + var expectedJSONAsInterface, actualJSONAsInterface interface{} - actualJSONAsMap := make(map[string]interface{}) - actualJSONAsSlice := make([]interface{}, 0, 0) - - if err := json.Unmarshal([]byte(expected), &expectedJSONAsMap); err != nil { - if err := json.Unmarshal([]byte(expected), &expectedJSONAsSlice); err == nil { - expectSlice = true - } else { - 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(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 expectSlice { - if err := json.Unmarshal([]byte(actual), &actualJSONAsSlice); 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, expectedJSONAsSlice, actualJSONAsSlice, msgAndArgs...) - } else { - if err := json.Unmarshal([]byte(actual), &actualJSONAsMap); 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, expectedJSONAsMap, actualJSONAsMap, 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...) } diff --git a/require/requirements.go b/require/requirements.go index 9de321f..6c3e7bc 100644 --- a/require/requirements.go +++ b/require/requirements.go @@ -235,32 +235,17 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf // // Returns whether the assertion was successful (true) or not (false). func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { - expectSlice := false - expectedJSONAsMap := make(map[string]interface{}) - expectedJSONAsSlice := make([]interface{}, 0, 0) + var expectedJSONAsInterface, actualJSONAsInterface interface{} - actualJSONAsMap := make(map[string]interface{}) - actualJSONAsSlice := make([]interface{}, 0, 0) - - if err := json.Unmarshal([]byte(expected), &expectedJSONAsMap); err != nil { - if err := json.Unmarshal([]byte(expected), &expectedJSONAsSlice); err == nil { - expectSlice = true - } else { - t.FailNow() - } + if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil { + t.FailNow() } - if expectSlice { - if err := json.Unmarshal([]byte(actual), &actualJSONAsSlice); err != nil { - t.FailNow() - } - Equal(t, expectedJSONAsSlice, actualJSONAsSlice, msgAndArgs...) - } else { - if err := json.Unmarshal([]byte(actual), &actualJSONAsMap); err != nil { - t.FailNow() - } - Equal(t, expectedJSONAsMap, actualJSONAsMap, msgAndArgs...) + if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil { + t.FailNow() } + + Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...) } /* From 2933ed99aa7f9da7b72e821f9120bdf17131697e Mon Sep 17 00:00:00 2001 From: Julian Cooper Date: Tue, 13 Oct 2015 14:15:08 -0700 Subject: [PATCH 38/50] Deleted monolithic TestJSONEqWrapper from forward_requirements_test --- require/forward_requirements_test.go | 51 ---------------------------- 1 file changed, 51 deletions(-) diff --git a/require/forward_requirements_test.go b/require/forward_requirements_test.go index 02be59c..b120ae3 100644 --- a/require/forward_requirements_test.go +++ b/require/forward_requirements_test.go @@ -283,57 +283,6 @@ func TestNotZeroWrapper(t *testing.T) { } } -func TestJSONEqWrapper(t *testing.T) { - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) - if mockT.Failed { - t.Error("JSONEq should pass") - } - - mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) - if mockT.Failed { - t.Error("JSONEq should pass") - } - - 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("JSONEq should pass") - } - - mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) - if mockT.Failed { - t.Error("JSONEq should pass") - } - - mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) - if !mockT.Failed { - t.Error("JSONEq should fail") - } - - mockRequire.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) - if !mockT.Failed { - t.Error("JSONEq should fail") - } - - mockRequire.JSONEq(`{"foo": "bar"}`, "Not JSON") - if !mockT.Failed { - t.Error("JSONEq should fail") - } - - mockRequire.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`) - if !mockT.Failed { - t.Error("JSONEq should fail") - } - - mockRequire.JSONEq("Not JSON", "Not JSON") - if !mockT.Failed { - t.Error("JSONEq should fail") - } -} - func TestJSONEqWrapper_EqualSONString(t *testing.T) { mockT := new(MockT) mockRequire := New(mockT) From be704a5c57bbe6a1169530127c5e4d91e026162a Mon Sep 17 00:00:00 2001 From: praveen shukla Date: Tue, 20 Oct 2015 10:44:48 +0530 Subject: [PATCH 39/50] corrected the README documentation of suite package --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f57561..07fb92a 100644 --- a/README.md +++ b/README.md @@ -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 From 6e25351910236beca3ecd676110842cec8ad7e65 Mon Sep 17 00:00:00 2001 From: praveen shukla Date: Tue, 20 Oct 2015 10:51:47 +0530 Subject: [PATCH 40/50] modified the go.doc in suite package. --- suite/doc.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/suite/doc.go b/suite/doc.go index 3731eaa..81d838d 100644 --- a/suite/doc.go +++ b/suite/doc.go @@ -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 From 95644cab17b69efffe8dd8983827a063d9d336c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Jime=CC=81nez?= Date: Sun, 1 Nov 2015 15:12:29 +0000 Subject: [PATCH 41/50] Fixes issue #149 --- suite/suite.go | 1 + suite/suite_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/suite/suite.go b/suite/suite.go index ac6744d..f831e25 100644 --- a/suite/suite.go +++ b/suite/suite.go @@ -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. diff --git a/suite/suite_test.go b/suite/suite_test.go index 6a1bb2c..c7c4e88 100644 --- a/suite/suite_test.go +++ b/suite/suite_test.go @@ -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 From 9d7bb925107ef21f759015719d9bd3ba2f968fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Jim=C3=A9nez?= Date: Mon, 2 Nov 2015 00:05:23 +0000 Subject: [PATCH 42/50] fix #201 - Remove broken link from README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 07fb92a..aaf2aa0 100644 --- a/README.md +++ b/README.md @@ -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) From ef3ce2dd137d7f1677484bbcb6e4738e2ab1323b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Jime=CC=81nez?= Date: Mon, 2 Nov 2015 00:46:20 +0000 Subject: [PATCH 43/50] Show struct fields in mock unexpected method error --- mock/mock.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mock/mock.go b/mock/mock.go index af201ae..111a281 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -249,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")) } From 8254b8f76b5458f6b16b2ca5db856e2e3af7145d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Jime=CC=81nez?= Date: Mon, 2 Nov 2015 01:24:09 +0000 Subject: [PATCH 44/50] Fix #144 --- assert/assertions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assert/assertions.go b/assert/assertions.go index 5385499..be5921e 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -269,7 +269,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...) From c478a808a1b37e10c82f71a2172728f8742bad51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Jime=CC=81nez?= Date: Mon, 2 Nov 2015 01:41:59 +0000 Subject: [PATCH 45/50] Fix #136 --- assert/assertions.go | 3 +++ assert/assertions_test.go | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/assert/assertions.go b/assert/assertions.go index be5921e..14d7036 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -358,6 +358,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() diff --git a/assert/assertions_test.go b/assert/assertions_test.go index dff6f2d..ab5e797 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -4,6 +4,7 @@ import ( "errors" "io" "math" + "os" "reflect" "regexp" "testing" @@ -580,6 +581,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") @@ -587,6 +591,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") From 0d5a14c5a477957864f3b747d95255ad4e34bcc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Jime=CC=81nez?= Date: Mon, 2 Nov 2015 02:08:28 +0000 Subject: [PATCH 46/50] Fix #117: Update require.Contains docs --- require/requirements.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/require/requirements.go b/require/requirements.go index 6c3e7bc..81705a5 100644 --- a/require/requirements.go +++ b/require/requirements.go @@ -137,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() From 33c4c93911cfa4f4759bbec45981615aa733e57b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Jime=CC=81nez?= Date: Tue, 3 Nov 2015 01:32:38 +0000 Subject: [PATCH 47/50] Fixes #229 - show diffs for structs/maps/arrays/slices when Equal fails --- assert/assertions.go | 51 ++++++++++++++++++++++++++- assert/assertions_test.go | 74 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) diff --git a/assert/assertions.go b/assert/assertions.go index be5921e..899e9f4 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -13,6 +13,9 @@ import ( "time" "unicode" "unicode/utf8" + + "github.com/davecgh/go-spew/spew" + "github.com/pmezard/go-difflib/difflib" ) // TestingT is an interface wrapper around *testing.T @@ -233,8 +236,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 @@ -921,3 +925,48 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{ 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 "" + } + + 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 +} diff --git a/assert/assertions_test.go b/assert/assertions_test.go index dff6f2d..e7d3ad1 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -984,3 +984,77 @@ 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) + + // output for maps cannot be equally tested since order is random + actual = diff( + map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}, + map[string]int{"one": 1, "three": 3, "five": 5, "seven": 7}, + ) + NotZero(t, len(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})) +} From 7d6ace91136b7231a9106b3965fc140401e8936e Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Sat, 7 Nov 2015 19:02:25 +1100 Subject: [PATCH 48/50] Handle case where one object is nil and the other is not --- assert/assertions.go | 5 ++++- assert/assertions_test.go | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/assert/assertions.go b/assert/assertions.go index 831db83..a82c781 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -51,8 +51,11 @@ 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 return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) } diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 46dc3fb..a55bc9c 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -132,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() + } } From 635a01b70498485841495a8fd095a48fb37560d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Gonz=C3=A1lez?= Date: Sun, 8 Nov 2015 00:15:59 +0100 Subject: [PATCH 49/50] Show type of the object instead just "Object" string The `Implements` test was just showing a string instead the name of the object that was not implementing the interface. Now the type of the object is shown. --- assert/assertions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assert/assertions.go b/assert/assertions.go index a82c781..bc8ac6c 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -214,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 From 67106a5111a06241c8d84952c33214675f51a34a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Jime=CC=81nez?= Date: Wed, 11 Nov 2015 20:33:49 +0100 Subject: [PATCH 50/50] Sort map keys before diffing maps --- assert/assertions.go | 1 + assert/assertions_test.go | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/assert/assertions.go b/assert/assertions.go index bc8ac6c..f9f56a5 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -961,6 +961,7 @@ func diff(expected interface{}, actual interface{}) string { return "" } + spew.Config.SortKeys = true e := spew.Sdump(expected) a := spew.Sdump(actual) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index a55bc9c..a12352e 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -1055,12 +1055,28 @@ Diff: ) Equal(t, expected, actual) - // output for maps cannot be equally tested since order is random + 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}, ) - NotZero(t, len(actual)) + Equal(t, expected, actual) } func TestDiffEmptyCases(t *testing.T) {