From 25d08c3e1ec637e06e9e3bf5d439209e00fdeb82 Mon Sep 17 00:00:00 2001 From: Andreas Pokorny Date: Fri, 7 Jul 2017 15:11:45 +0200 Subject: [PATCH 1/7] Support Unique Ptr Mocks in Hippomocks This allows creating default unique_ptr mock objects. Signed-off-by: Andreas Pokorny --- HippoMocks/hippomocks.h | 63 +++++++++++++++++- HippoMocksTest/CMakeLists.txt | 1 + HippoMocksTest/test_unique_ptr.cpp | 102 +++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 HippoMocksTest/test_unique_ptr.cpp diff --git a/HippoMocks/hippomocks.h b/HippoMocks/hippomocks.h index 61375f1..8fb1c07 100644 --- a/HippoMocks/hippomocks.h +++ b/HippoMocks/hippomocks.h @@ -390,6 +390,13 @@ class mock : public base_mock } template void mockedDestructor(int); + void defaultDestructor(int); +}; + +template +struct unique_mock : mock +{ + unique_mock(MockRepository *repository); }; template @@ -779,6 +786,10 @@ class MockRepository { mock *realMock = (mock *)mck; realMock->members.emplace_back(new MemberWrap(realRealMember)); } + template + void SetupDefaultDestructor(Z2 *mck, int x); + template + int SetupMockedDestructor(Z2 *mck); template TCall &RegisterExpectDestructor(Z2 *mck, RegistrationType expect, const char *fileName, unsigned long lineNo); @@ -965,6 +976,8 @@ class MockRepository { } template base *Mock(); + template + std::unique_ptr UniqueMock(); }; // mock function providers @@ -1077,6 +1090,22 @@ void mock::mockedDestructor(int) isZombie = true; } +template +void mock::defaultDestructor(int) +{ + repo->VerifyPartial(this); + isZombie = true; +} + +template +unique_mock::unique_mock(MockRepository *repository) : mock(repository) +{ + // restore function table from mock + *(void **)this = this->funcTables[0]; + // setup destructor - since MockRepository is not the owner of the object + this->repo->template SetupDefaultDestructor(reinterpret_cast(this), -1); +} + template void MockRepository::BasicRegisterExpect(mock *zMock, int baseOffset, int funcIndex, void (base_mock::*func)(), int X) { @@ -1102,8 +1131,26 @@ void MockRepository::BasicRegisterExpect(mock *zMock, int baseOffset, int fun } } +template +void MockRepository::SetupDefaultDestructor(Z2 *mck, int X) +{ + func_index idx; + ((Z2 *)&idx)->~Z2(); + int funcIndex = idx.lci * FUNCTION_STRIDE + FUNCTION_BASE; + void (mock::*member)(int); + member = &mock::defaultDestructor; + BasicRegisterExpect(reinterpret_cast *>(mck), + 0, funcIndex, + reinterpret_cast(member), X); +#ifdef EXTRA_DESTRUCTOR + BasicRegisterExpect(reinterpret_cast *>(mck), + 0, funcIndex+1, + reinterpret_cast(member), X); +#endif +} + template -TCall &MockRepository::RegisterExpectDestructor(Z2 *mck, RegistrationType expect, const char *fileName, unsigned long lineNo) +int MockRepository::SetupMockedDestructor(Z2 *mck) { func_index idx; ((Z2 *)&idx)->~Z2(); @@ -1118,11 +1165,19 @@ TCall &MockRepository::RegisterExpectDestructor(Z2 *mck, RegistrationType 0, funcIndex+1, reinterpret_cast(member), X); #endif + return funcIndex; +} + +template +TCall &MockRepository::RegisterExpectDestructor(Z2 *mck, RegistrationType expect, const char *fileName, unsigned long lineNo) +{ + int funcIndex = this->template SetupMockedDestructor(mck); TCall *call = new TCall(Once, reinterpret_cast(mck), std::pair(0, funcIndex), lineNo, "destructor", fileName); addCall( call, expect ); return *call; } + #if defined(_MSC_VER) && !defined(_WIN64) // Support for COM, see declarations template @@ -1227,6 +1282,12 @@ base *MockRepository::Mock() { return reinterpret_cast(m); } +template +std::unique_ptr MockRepository::UniqueMock() { + return std::move(std::unique_ptr{reinterpret_cast(new unique_mock(this))}); +} + + #include "detail/defaultreporter.h" #ifndef NO_HIPPOMOCKS_NAMESPACE diff --git a/HippoMocksTest/CMakeLists.txt b/HippoMocksTest/CMakeLists.txt index 1e9e9b0..87b6e42 100644 --- a/HippoMocksTest/CMakeLists.txt +++ b/HippoMocksTest/CMakeLists.txt @@ -32,6 +32,7 @@ set(SOURCES test_retval.cpp test_transaction.cpp test_zombie.cpp + test_unique_ptr.cpp ) add_executable(HippoMocksTest64 diff --git a/HippoMocksTest/test_unique_ptr.cpp b/HippoMocksTest/test_unique_ptr.cpp new file mode 100644 index 0000000..b42ea27 --- /dev/null +++ b/HippoMocksTest/test_unique_ptr.cpp @@ -0,0 +1,102 @@ +#include "Framework.h" +#include "hippomocks.h" +#include + +class IU { +public: + virtual ~IU() { std::cout << "deleting " << std::endl;} + virtual void f() = 0;// {} + virtual void g() {} + virtual int h() { return 0; } + virtual void i(std::string ) {} + virtual void j(std::string ) = 0; +}; + +TEST (checkUniquePtrDestruction) +{ + MockRepository mocks; + auto iu = mocks.UniqueMock(); +} + +TEST (checkCallsWorksOnUniquePtr) +{ + MockRepository mocks; + std::unique_ptr iu = mocks.UniqueMock(); + mocks.ExpectCall(iu.get(), IU::f); + iu->f(); +} + +TEST (checkMissingExpectationsWorksOnUniquePtr) +{ + MockRepository mocks; + bool exceptionCaught = false; + std::unique_ptr iu = mocks.UniqueMock(); + try + { + iu->f(); + } + catch (HippoMocks::NotImplementedException const& e) + { + exceptionCaught = true; + } + CHECK(exceptionCaught); +} + +TEST (checkNeverCallWorksOnUniquePtr) +{ + bool exceptionCaught = false; + MockRepository mocks; + auto iu = mocks.UniqueMock(); + Call &callF = mocks.ExpectCall(iu.get(), IU::f); + mocks.OnCall(iu.get(), IU::g); + mocks.NeverCall(iu.get(), IU::g).After(callF); + iu->g(); + iu->g(); + iu->f(); + try + { + iu->g(); + } + catch (HippoMocks::ExpectationException &) + { + exceptionCaught = true; + } + CHECK(exceptionCaught); +} + +TEST (checkClassArgumentsAcceptedWithUniquePtr) +{ + MockRepository mocks; + auto iamock = mocks.UniqueMock(); + mocks.OnCall(iamock.get(), IU::i).With("hi"); + mocks.OnCall(iamock.get(), IU::j).With("bye"); + iamock->i("hi"); + iamock->j("bye"); +} + +TEST (checkClassArgumentsCheckedWithUniquePtr) +{ + MockRepository mocks; + auto iamock = mocks.UniqueMock(); + mocks.OnCall(iamock.get(), IU::i).With("hi"); + mocks.OnCall(iamock.get(), IU::j).With("bye"); + bool exceptionCaught = false; + try + { + iamock->i("bye"); + } + catch (HippoMocks::ExpectationException) + { + exceptionCaught = true; + } + CHECK(exceptionCaught); + mocks.reset(); +} + +TEST (checkClassArgumentsIgnoredWithUniquePtr) +{ + MockRepository mocks; + auto iamock = mocks.UniqueMock(); + mocks.OnCall(iamock.get(), IU::i); + iamock->i("bye"); +} From 054df95d70ce10d732a382c82ee9b02e4ce6528e Mon Sep 17 00:00:00 2001 From: Andreas Pokorny Date: Sat, 8 Jul 2017 16:47:06 +0200 Subject: [PATCH 2/7] Add Support for unique_ptr with deleter functions This assumes that the destructor of "base" is actually called. Signed-off-by: Andreas Pokorny --- HippoMocks/hippomocks.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/HippoMocks/hippomocks.h b/HippoMocks/hippomocks.h index 8fb1c07..84c1d77 100644 --- a/HippoMocks/hippomocks.h +++ b/HippoMocks/hippomocks.h @@ -978,6 +978,8 @@ class MockRepository { base *Mock(); template std::unique_ptr UniqueMock(); + template + std::unique_ptr UniqueMock(D deleter); }; // mock function providers @@ -1287,6 +1289,11 @@ std::unique_ptr MockRepository::UniqueMock() { return std::move(std::unique_ptr{reinterpret_cast(new unique_mock(this))}); } +template +std::unique_ptr MockRepository::UniqueMock(Deleter deleter) { + return std::move(std::unique_ptr{reinterpret_cast(new unique_mock(this)), deleter}); +} + #include "detail/defaultreporter.h" From ad4bb62b2e2c661b40e023861db7d132257453c6 Mon Sep 17 00:00:00 2001 From: Andreas Pokorny Date: Sat, 8 Jul 2017 16:55:13 +0200 Subject: [PATCH 3/7] Add tee utility Solves the common case of capturing an object to formulate expectations while forwarding exclusive ownership to the class under test Signed-off-by: Andreas Pokorny --- HippoMocks/hippomocks.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/HippoMocks/hippomocks.h b/HippoMocks/hippomocks.h index 84c1d77..da4aee0 100644 --- a/HippoMocks/hippomocks.h +++ b/HippoMocks/hippomocks.h @@ -1294,6 +1294,12 @@ std::unique_ptr MockRepository::UniqueMock(Deleter deleter) { return std::move(std::unique_ptr{reinterpret_cast(new unique_mock(this)), deleter}); } +template +std::unique_ptr tee(base*& capture, std::unique_ptr && obj) { + capture = obj.get(); + return std::move(obj); +} + #include "detail/defaultreporter.h" From 335f46f390cc5bdb3cd3c157affbae0084e29d36 Mon Sep 17 00:00:00 2001 From: Andreas Pokorny Date: Sat, 8 Jul 2017 17:05:37 +0200 Subject: [PATCH 4/7] Cleanup test and fix warning Signed-off-by: Andreas Pokorny --- HippoMocksTest/test_unique_ptr.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HippoMocksTest/test_unique_ptr.cpp b/HippoMocksTest/test_unique_ptr.cpp index b42ea27..df91419 100644 --- a/HippoMocksTest/test_unique_ptr.cpp +++ b/HippoMocksTest/test_unique_ptr.cpp @@ -4,8 +4,8 @@ class IU { public: - virtual ~IU() { std::cout << "deleting " << std::endl;} - virtual void f() = 0;// {} + virtual ~IU() {} + virtual void f() = 0; virtual void g() {} virtual int h() { return 0; } virtual void i(std::string ) {} @@ -35,7 +35,7 @@ TEST (checkMissingExpectationsWorksOnUniquePtr) { iu->f(); } - catch (HippoMocks::NotImplementedException const& e) + catch (HippoMocks::NotImplementedException const&) { exceptionCaught = true; } From 7fa00d2454305c8ee943af23be58b33059646463 Mon Sep 17 00:00:00 2001 From: Andreas Pokorny Date: Sat, 8 Jul 2017 20:53:14 +0200 Subject: [PATCH 5/7] Visual studio parse error --- HippoMocks/hippomocks.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HippoMocks/hippomocks.h b/HippoMocks/hippomocks.h index da4aee0..ce8b705 100644 --- a/HippoMocks/hippomocks.h +++ b/HippoMocks/hippomocks.h @@ -1105,7 +1105,7 @@ unique_mock::unique_mock(MockRepository *repository) : mock(repository) // restore function table from mock *(void **)this = this->funcTables[0]; // setup destructor - since MockRepository is not the owner of the object - this->repo->template SetupDefaultDestructor(reinterpret_cast(this), -1); + this->repo->SetupDefaultDestructor(reinterpret_cast(this), -1); } template From fc1f9e26ab5913593842138a3fca1bc2aedd4e31 Mon Sep 17 00:00:00 2001 From: Andreas Pokorny Date: Mon, 10 Jul 2017 08:40:51 +0200 Subject: [PATCH 6/7] Update project files --- HippoMocksTest/HippoMocks.dev | 12 +++++++++++- HippoMocksTest/HippoMocksTest.vcproj | 4 ++++ HippoMocksTest/HippoMocksTest_2012.vcxproj | 1 + HippoMocksTest/makefile | 2 +- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/HippoMocksTest/HippoMocks.dev b/HippoMocksTest/HippoMocks.dev index e96bb3a..4182610 100644 --- a/HippoMocksTest/HippoMocks.dev +++ b/HippoMocksTest/HippoMocks.dev @@ -1,7 +1,7 @@ [Project] FileName=HippoMocks.dev Name=HippoMocks -UnitCount=12 +UnitCount=13 Type=1 Ver=1 ObjFiles= @@ -167,3 +167,13 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= +[Unit13] +FileName=test_unique_ptr.cpp +CompileCpp=1 +Folder=HippoMocks +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/HippoMocksTest/HippoMocksTest.vcproj b/HippoMocksTest/HippoMocksTest.vcproj index 97d52f2..894d3b3 100644 --- a/HippoMocksTest/HippoMocksTest.vcproj +++ b/HippoMocksTest/HippoMocksTest.vcproj @@ -352,6 +352,10 @@ + + + diff --git a/HippoMocksTest/makefile b/HippoMocksTest/makefile index 18ff461..75f5445 100644 --- a/HippoMocksTest/makefile +++ b/HippoMocksTest/makefile @@ -4,7 +4,7 @@ WARNFLAGS = -Wall -Wextra -pedantic -Wno-long-long CXXOPTS = -I../HippoMocks/ $(WARNFLAGS) -g TARGET = $(PREFIX)test.exe -OBJECTS = $(patsubst %,$(PREFIX)%,is_virtual.o test.o test_args.o test_array.o test_autoptr.o test_cfuncs.o test_class_args.o test_constref_params.o test_cv_funcs.o test_do.o test_dontcare.o test_dynamic_cast.o test_except.o test_exception_quality.o test_filter.o test_inparam.o test_membermock.o test_mi.o test_nevercall.o test_optional.o test_outparam.o test_overload.o test_ref_args.o test_regression_arg_count.o test_retval.o test_transaction.o test_zombie.o Framework.o main.o) +OBJECTS = $(patsubst %,$(PREFIX)%,is_virtual.o test.o test_args.o test_array.o test_autoptr.o test_cfuncs.o test_class_args.o test_constref_params.o test_cv_funcs.o test_do.o test_dontcare.o test_dynamic_cast.o test_except.o test_exception_quality.o test_filter.o test_inparam.o test_membermock.o test_mi.o test_nevercall.o test_optional.o test_outparam.o test_overload.o test_ref_args.o test_regression_arg_count.o test_retval.o test_transaction.o test_zombie.o test_unique_ptr.o Framework.o main.o) all: $(TARGETS) From 672ca9e508a6a8b8036cf21df3da9e2de8e27179 Mon Sep 17 00:00:00 2001 From: Andreas Pokorny Date: Mon, 10 Jul 2017 08:49:24 +0200 Subject: [PATCH 7/7] one more project file --- HippoMocksTest/HippoMocks.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/HippoMocksTest/HippoMocks.pro b/HippoMocksTest/HippoMocks.pro index e355ac2..86a5656 100644 --- a/HippoMocksTest/HippoMocks.pro +++ b/HippoMocksTest/HippoMocks.pro @@ -43,4 +43,5 @@ SOURCES += \ test_regression_arg_count.cpp \ test_retval.cpp \ test_transaction.cpp \ + test_unique_ptr.cpp \ test_zombie.cpp