From 83011bddd0f1bef4666fb9b8ea54a27ee1fb74cb Mon Sep 17 00:00:00 2001 From: Max Chechel Date: Thu, 20 Jun 2024 10:22:02 -0400 Subject: [PATCH] Return FailNow to Tester interface for previously generated mocks to be able to work with newer versions of the minimock package --- mock_controller.go | 1 + tests/package_name_specified_test.go | 182 +++++++++++++++++++++++++++ tests/tester_mock_test.go | 182 +++++++++++++++++++++++++++ 3 files changed, 365 insertions(+) diff --git a/mock_controller.go b/mock_controller.go index 557dfa3..60d8d4d 100644 --- a/mock_controller.go +++ b/mock_controller.go @@ -17,6 +17,7 @@ type Tester interface { Fatalf(format string, args ...interface{}) Error(...interface{}) Errorf(format string, args ...interface{}) + FailNow() Cleanup(f func()) } diff --git a/tests/package_name_specified_test.go b/tests/package_name_specified_test.go index b5e9656..0fccc87 100644 --- a/tests/package_name_specified_test.go +++ b/tests/package_name_specified_test.go @@ -35,6 +35,12 @@ type TesterMock struct { beforeErrorfCounter uint64 ErrorfMock mTesterMockErrorf + funcFailNow func() + inspectFuncFailNow func() + afterFailNowCounter uint64 + beforeFailNowCounter uint64 + FailNowMock mTesterMockFailNow + funcFatal func(args ...interface{}) inspectFuncFatal func(args ...interface{}) afterFatalCounter uint64 @@ -65,6 +71,8 @@ func NewTesterMock(t minimock.Tester) *TesterMock { m.ErrorfMock = mTesterMockErrorf{mock: m} m.ErrorfMock.callArgs = []*TesterMockErrorfParams{} + m.FailNowMock = mTesterMockFailNow{mock: m} + m.FatalMock = mTesterMockFatal{mock: m} m.FatalMock.callArgs = []*TesterMockFatalParams{} @@ -896,6 +904,177 @@ func (m *TesterMock) MinimockErrorfInspect() { } } +type mTesterMockFailNow struct { + optional bool + mock *TesterMock + defaultExpectation *TesterMockFailNowExpectation + expectations []*TesterMockFailNowExpectation + + expectedInvocations uint64 +} + +// TesterMockFailNowExpectation specifies expectation struct of the Tester.FailNow +type TesterMockFailNowExpectation struct { + mock *TesterMock + + Counter uint64 +} + +// Marks this method to be optional. The default behavior of any method with Return() is '1 or more', meaning +// the test will fail minimock's automatic final call check if the mocked method was not called at least once. +// Optional() makes method check to work in '0 or more' mode. +// It is NOT RECOMMENDED to use this option unless you really need it, as default behaviour helps to +// catch the problems when the expected method call is totally skipped during test run. +func (mmFailNow *mTesterMockFailNow) Optional() *mTesterMockFailNow { + mmFailNow.optional = true + return mmFailNow +} + +// Expect sets up expected params for Tester.FailNow +func (mmFailNow *mTesterMockFailNow) Expect() *mTesterMockFailNow { + if mmFailNow.mock.funcFailNow != nil { + mmFailNow.mock.t.Fatalf("TesterMock.FailNow mock is already set by Set") + } + + if mmFailNow.defaultExpectation == nil { + mmFailNow.defaultExpectation = &TesterMockFailNowExpectation{} + } + + return mmFailNow +} + +// Inspect accepts an inspector function that has same arguments as the Tester.FailNow +func (mmFailNow *mTesterMockFailNow) Inspect(f func()) *mTesterMockFailNow { + if mmFailNow.mock.inspectFuncFailNow != nil { + mmFailNow.mock.t.Fatalf("Inspect function is already set for TesterMock.FailNow") + } + + mmFailNow.mock.inspectFuncFailNow = f + + return mmFailNow +} + +// Return sets up results that will be returned by Tester.FailNow +func (mmFailNow *mTesterMockFailNow) Return() *TesterMock { + if mmFailNow.mock.funcFailNow != nil { + mmFailNow.mock.t.Fatalf("TesterMock.FailNow mock is already set by Set") + } + + if mmFailNow.defaultExpectation == nil { + mmFailNow.defaultExpectation = &TesterMockFailNowExpectation{mock: mmFailNow.mock} + } + + return mmFailNow.mock +} + +// Set uses given function f to mock the Tester.FailNow method +func (mmFailNow *mTesterMockFailNow) Set(f func()) *TesterMock { + if mmFailNow.defaultExpectation != nil { + mmFailNow.mock.t.Fatalf("Default expectation is already set for the Tester.FailNow method") + } + + if len(mmFailNow.expectations) > 0 { + mmFailNow.mock.t.Fatalf("Some expectations are already set for the Tester.FailNow method") + } + + mmFailNow.mock.funcFailNow = f + return mmFailNow.mock +} + +// Times sets number of times Tester.FailNow should be invoked +func (mmFailNow *mTesterMockFailNow) Times(n uint64) *mTesterMockFailNow { + if n == 0 { + mmFailNow.mock.t.Fatalf("Times of TesterMock.FailNow mock can not be zero") + } + mm_atomic.StoreUint64(&mmFailNow.expectedInvocations, n) + return mmFailNow +} + +func (mmFailNow *mTesterMockFailNow) invocationsDone() bool { + if len(mmFailNow.expectations) == 0 && mmFailNow.defaultExpectation == nil && mmFailNow.mock.funcFailNow == nil { + return true + } + + totalInvocations := mm_atomic.LoadUint64(&mmFailNow.mock.afterFailNowCounter) + expectedInvocations := mm_atomic.LoadUint64(&mmFailNow.expectedInvocations) + + return totalInvocations > 0 && (expectedInvocations == 0 || expectedInvocations == totalInvocations) +} + +// FailNow implements minimock.Tester +func (mmFailNow *TesterMock) FailNow() { + mm_atomic.AddUint64(&mmFailNow.beforeFailNowCounter, 1) + defer mm_atomic.AddUint64(&mmFailNow.afterFailNowCounter, 1) + + if mmFailNow.inspectFuncFailNow != nil { + mmFailNow.inspectFuncFailNow() + } + + if mmFailNow.FailNowMock.defaultExpectation != nil { + mm_atomic.AddUint64(&mmFailNow.FailNowMock.defaultExpectation.Counter, 1) + + return + + } + if mmFailNow.funcFailNow != nil { + mmFailNow.funcFailNow() + return + } + mmFailNow.t.Fatalf("Unexpected call to TesterMock.FailNow.") + +} + +// FailNowAfterCounter returns a count of finished TesterMock.FailNow invocations +func (mmFailNow *TesterMock) FailNowAfterCounter() uint64 { + return mm_atomic.LoadUint64(&mmFailNow.afterFailNowCounter) +} + +// FailNowBeforeCounter returns a count of TesterMock.FailNow invocations +func (mmFailNow *TesterMock) FailNowBeforeCounter() uint64 { + return mm_atomic.LoadUint64(&mmFailNow.beforeFailNowCounter) +} + +// MinimockFailNowDone returns true if the count of the FailNow invocations corresponds +// the number of defined expectations +func (m *TesterMock) MinimockFailNowDone() bool { + if m.FailNowMock.optional { + // Optional methods provide '0 or more' call count restriction. + return true + } + + for _, e := range m.FailNowMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + return false + } + } + + return m.FailNowMock.invocationsDone() +} + +// MinimockFailNowInspect logs each unmet expectation +func (m *TesterMock) MinimockFailNowInspect() { + for _, e := range m.FailNowMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + m.t.Error("Expected call to TesterMock.FailNow") + } + } + + afterFailNowCounter := mm_atomic.LoadUint64(&m.afterFailNowCounter) + // if default expectation was set then invocations count should be greater than zero + if m.FailNowMock.defaultExpectation != nil && afterFailNowCounter < 1 { + m.t.Error("Expected call to TesterMock.FailNow") + } + // if func was set then invocations count should be greater than zero + if m.funcFailNow != nil && afterFailNowCounter < 1 { + m.t.Error("Expected call to TesterMock.FailNow") + } + + if !m.FailNowMock.invocationsDone() && afterFailNowCounter > 0 { + m.t.Errorf("Expected %d calls to TesterMock.FailNow but found %d calls", + mm_atomic.LoadUint64(&m.FailNowMock.expectedInvocations), afterFailNowCounter) + } +} + type mTesterMockFatal struct { optional bool mock *TesterMock @@ -1462,6 +1641,8 @@ func (m *TesterMock) MinimockFinish() { m.MinimockErrorfInspect() + m.MinimockFailNowInspect() + m.MinimockFatalInspect() m.MinimockFatalfInspect() @@ -1491,6 +1672,7 @@ func (m *TesterMock) minimockDone() bool { m.MinimockCleanupDone() && m.MinimockErrorDone() && m.MinimockErrorfDone() && + m.MinimockFailNowDone() && m.MinimockFatalDone() && m.MinimockFatalfDone() } diff --git a/tests/tester_mock_test.go b/tests/tester_mock_test.go index 7eb91eb..93f2f73 100644 --- a/tests/tester_mock_test.go +++ b/tests/tester_mock_test.go @@ -35,6 +35,12 @@ type TesterMock struct { beforeErrorfCounter uint64 ErrorfMock mTesterMockErrorf + funcFailNow func() + inspectFuncFailNow func() + afterFailNowCounter uint64 + beforeFailNowCounter uint64 + FailNowMock mTesterMockFailNow + funcFatal func(args ...interface{}) inspectFuncFatal func(args ...interface{}) afterFatalCounter uint64 @@ -65,6 +71,8 @@ func NewTesterMock(t minimock.Tester) *TesterMock { m.ErrorfMock = mTesterMockErrorf{mock: m} m.ErrorfMock.callArgs = []*TesterMockErrorfParams{} + m.FailNowMock = mTesterMockFailNow{mock: m} + m.FatalMock = mTesterMockFatal{mock: m} m.FatalMock.callArgs = []*TesterMockFatalParams{} @@ -896,6 +904,177 @@ func (m *TesterMock) MinimockErrorfInspect() { } } +type mTesterMockFailNow struct { + optional bool + mock *TesterMock + defaultExpectation *TesterMockFailNowExpectation + expectations []*TesterMockFailNowExpectation + + expectedInvocations uint64 +} + +// TesterMockFailNowExpectation specifies expectation struct of the Tester.FailNow +type TesterMockFailNowExpectation struct { + mock *TesterMock + + Counter uint64 +} + +// Marks this method to be optional. The default behavior of any method with Return() is '1 or more', meaning +// the test will fail minimock's automatic final call check if the mocked method was not called at least once. +// Optional() makes method check to work in '0 or more' mode. +// It is NOT RECOMMENDED to use this option unless you really need it, as default behaviour helps to +// catch the problems when the expected method call is totally skipped during test run. +func (mmFailNow *mTesterMockFailNow) Optional() *mTesterMockFailNow { + mmFailNow.optional = true + return mmFailNow +} + +// Expect sets up expected params for Tester.FailNow +func (mmFailNow *mTesterMockFailNow) Expect() *mTesterMockFailNow { + if mmFailNow.mock.funcFailNow != nil { + mmFailNow.mock.t.Fatalf("TesterMock.FailNow mock is already set by Set") + } + + if mmFailNow.defaultExpectation == nil { + mmFailNow.defaultExpectation = &TesterMockFailNowExpectation{} + } + + return mmFailNow +} + +// Inspect accepts an inspector function that has same arguments as the Tester.FailNow +func (mmFailNow *mTesterMockFailNow) Inspect(f func()) *mTesterMockFailNow { + if mmFailNow.mock.inspectFuncFailNow != nil { + mmFailNow.mock.t.Fatalf("Inspect function is already set for TesterMock.FailNow") + } + + mmFailNow.mock.inspectFuncFailNow = f + + return mmFailNow +} + +// Return sets up results that will be returned by Tester.FailNow +func (mmFailNow *mTesterMockFailNow) Return() *TesterMock { + if mmFailNow.mock.funcFailNow != nil { + mmFailNow.mock.t.Fatalf("TesterMock.FailNow mock is already set by Set") + } + + if mmFailNow.defaultExpectation == nil { + mmFailNow.defaultExpectation = &TesterMockFailNowExpectation{mock: mmFailNow.mock} + } + + return mmFailNow.mock +} + +// Set uses given function f to mock the Tester.FailNow method +func (mmFailNow *mTesterMockFailNow) Set(f func()) *TesterMock { + if mmFailNow.defaultExpectation != nil { + mmFailNow.mock.t.Fatalf("Default expectation is already set for the Tester.FailNow method") + } + + if len(mmFailNow.expectations) > 0 { + mmFailNow.mock.t.Fatalf("Some expectations are already set for the Tester.FailNow method") + } + + mmFailNow.mock.funcFailNow = f + return mmFailNow.mock +} + +// Times sets number of times Tester.FailNow should be invoked +func (mmFailNow *mTesterMockFailNow) Times(n uint64) *mTesterMockFailNow { + if n == 0 { + mmFailNow.mock.t.Fatalf("Times of TesterMock.FailNow mock can not be zero") + } + mm_atomic.StoreUint64(&mmFailNow.expectedInvocations, n) + return mmFailNow +} + +func (mmFailNow *mTesterMockFailNow) invocationsDone() bool { + if len(mmFailNow.expectations) == 0 && mmFailNow.defaultExpectation == nil && mmFailNow.mock.funcFailNow == nil { + return true + } + + totalInvocations := mm_atomic.LoadUint64(&mmFailNow.mock.afterFailNowCounter) + expectedInvocations := mm_atomic.LoadUint64(&mmFailNow.expectedInvocations) + + return totalInvocations > 0 && (expectedInvocations == 0 || expectedInvocations == totalInvocations) +} + +// FailNow implements minimock.Tester +func (mmFailNow *TesterMock) FailNow() { + mm_atomic.AddUint64(&mmFailNow.beforeFailNowCounter, 1) + defer mm_atomic.AddUint64(&mmFailNow.afterFailNowCounter, 1) + + if mmFailNow.inspectFuncFailNow != nil { + mmFailNow.inspectFuncFailNow() + } + + if mmFailNow.FailNowMock.defaultExpectation != nil { + mm_atomic.AddUint64(&mmFailNow.FailNowMock.defaultExpectation.Counter, 1) + + return + + } + if mmFailNow.funcFailNow != nil { + mmFailNow.funcFailNow() + return + } + mmFailNow.t.Fatalf("Unexpected call to TesterMock.FailNow.") + +} + +// FailNowAfterCounter returns a count of finished TesterMock.FailNow invocations +func (mmFailNow *TesterMock) FailNowAfterCounter() uint64 { + return mm_atomic.LoadUint64(&mmFailNow.afterFailNowCounter) +} + +// FailNowBeforeCounter returns a count of TesterMock.FailNow invocations +func (mmFailNow *TesterMock) FailNowBeforeCounter() uint64 { + return mm_atomic.LoadUint64(&mmFailNow.beforeFailNowCounter) +} + +// MinimockFailNowDone returns true if the count of the FailNow invocations corresponds +// the number of defined expectations +func (m *TesterMock) MinimockFailNowDone() bool { + if m.FailNowMock.optional { + // Optional methods provide '0 or more' call count restriction. + return true + } + + for _, e := range m.FailNowMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + return false + } + } + + return m.FailNowMock.invocationsDone() +} + +// MinimockFailNowInspect logs each unmet expectation +func (m *TesterMock) MinimockFailNowInspect() { + for _, e := range m.FailNowMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + m.t.Error("Expected call to TesterMock.FailNow") + } + } + + afterFailNowCounter := mm_atomic.LoadUint64(&m.afterFailNowCounter) + // if default expectation was set then invocations count should be greater than zero + if m.FailNowMock.defaultExpectation != nil && afterFailNowCounter < 1 { + m.t.Error("Expected call to TesterMock.FailNow") + } + // if func was set then invocations count should be greater than zero + if m.funcFailNow != nil && afterFailNowCounter < 1 { + m.t.Error("Expected call to TesterMock.FailNow") + } + + if !m.FailNowMock.invocationsDone() && afterFailNowCounter > 0 { + m.t.Errorf("Expected %d calls to TesterMock.FailNow but found %d calls", + mm_atomic.LoadUint64(&m.FailNowMock.expectedInvocations), afterFailNowCounter) + } +} + type mTesterMockFatal struct { optional bool mock *TesterMock @@ -1462,6 +1641,8 @@ func (m *TesterMock) MinimockFinish() { m.MinimockErrorfInspect() + m.MinimockFailNowInspect() + m.MinimockFatalInspect() m.MinimockFatalfInspect() @@ -1491,6 +1672,7 @@ func (m *TesterMock) minimockDone() bool { m.MinimockCleanupDone() && m.MinimockErrorDone() && m.MinimockErrorfDone() && + m.MinimockFailNowDone() && m.MinimockFatalDone() && m.MinimockFatalfDone() }