diff --git a/HippoMocks/hippomocks.h b/HippoMocks/hippomocks.h index 61375f1..ce8b705 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,10 @@ class MockRepository { } template base *Mock(); + template + std::unique_ptr UniqueMock(); + template + std::unique_ptr UniqueMock(D deleter); }; // mock function providers @@ -1077,6 +1092,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->SetupDefaultDestructor(reinterpret_cast(this), -1); +} + template void MockRepository::BasicRegisterExpect(mock *zMock, int baseOffset, int funcIndex, void (base_mock::*func)(), int X) { @@ -1102,8 +1133,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 +1167,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 +1284,23 @@ 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))}); +} + +template +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" #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/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/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 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) diff --git a/HippoMocksTest/test_unique_ptr.cpp b/HippoMocksTest/test_unique_ptr.cpp new file mode 100644 index 0000000..df91419 --- /dev/null +++ b/HippoMocksTest/test_unique_ptr.cpp @@ -0,0 +1,102 @@ +#include "Framework.h" +#include "hippomocks.h" +#include + +class IU { +public: + virtual ~IU() {} + 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&) + { + 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"); +}