Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for unique_ptr #2

Merged
merged 1 commit into from
Jun 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 75 additions & 1 deletion HippoMocks/hippomocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -1481,6 +1481,13 @@ class mock : public base_mock
}
template <int X>
void mockedDestructor(int);
void defaultDestructor(int);
};

template <typename T>
struct unique_mock : mock<T>
{
unique_mock(MockRepository *repository);
};

// Do() function wrapping
Expand Down Expand Up @@ -3361,6 +3368,10 @@ class MockRepository {
mock<A> *realMock = (mock<A> *)mck;
realMock->members.push_back(new MemberWrap<C>(realRealMember));
}
template <typename Z2>
void SetupDefaultDestructor(Z2 *mck, int x);
template <int X, typename Z2>
int SetupMockedDestructor(Z2 *mck);
template <int X, typename Z2>
TCall<void> &RegisterExpectDestructor(Z2 *mck, RegistrationType expect, const char *fileName, unsigned long lineNo);

Expand Down Expand Up @@ -4424,6 +4435,10 @@ noexcept(false)
}
template <typename base>
base *Mock();
template <typename base>
std::unique_ptr<base> UniqueMock();
template <typename base, typename D>
std::unique_ptr<base, D> UniqueMock(D deleter);
};

// mock function providers
Expand Down Expand Up @@ -5311,6 +5326,22 @@ void mock<T>::mockedDestructor(int)
isZombie = true;
}

template <typename T>
void mock<T>::defaultDestructor(int)
{
repo->VerifyPartial(this);
isZombie = true;
}

template <typename T>
unique_mock<T>::unique_mock(MockRepository *repository) : mock<T>(repository)
{
// restore function table from mock<T>
*(void **)this = this->funcTables[0];
// setup destructor - since MockRepository is not the owner of the object
this->repo->SetupDefaultDestructor(reinterpret_cast<T*>(this), -1);
}

template <typename Z>
void MockRepository::BasicRegisterExpect(mock<Z> *zMock, int baseOffset, int funcIndex, void (base_mock::*func)(), int X)
{
Expand All @@ -5332,8 +5363,27 @@ void MockRepository::BasicRegisterExpect(mock<Z> *zMock, int baseOffset, int fun
}
}

template <typename Z2>
void MockRepository::SetupDefaultDestructor(Z2 *mck, int X)
{
func_index idx;
((Z2 *)&idx)->~Z2();
int funcIndex = idx.lci * FUNCTION_STRIDE + FUNCTION_BASE;
void (mock<Z2>::*member)(int);
member = &mock<Z2>::defaultDestructor;
BasicRegisterExpect(reinterpret_cast<mock<Z2> *>(mck),
0, funcIndex,
reinterpret_cast<void (base_mock::*)()>(member), X);
#ifdef EXTRA_DESTRUCTOR
BasicRegisterExpect(reinterpret_cast<mock<Z2> *>(mck),
0, funcIndex+1,
reinterpret_cast<void (base_mock::*)()>(member), X);
#endif
}


template <int X, typename Z2>
TCall<void> &MockRepository::RegisterExpectDestructor(Z2 *mck, RegistrationType expect, const char *fileName, unsigned long lineNo)
int MockRepository::SetupMockedDestructor(Z2 *mck)
{
func_index idx;
((Z2 *)&idx)->~Z2();
Expand All @@ -5348,6 +5398,13 @@ TCall<void> &MockRepository::RegisterExpectDestructor(Z2 *mck, RegistrationType
0, funcIndex+1,
reinterpret_cast<void (base_mock::*)()>(member), X);
#endif
return funcIndex;
}

template <int X, typename Z2>
TCall<void> &MockRepository::RegisterExpectDestructor(Z2 *mck, RegistrationType expect, const char *fileName, unsigned long lineNo)
{
int funcIndex = this->template SetupMockedDestructor<X>(mck);
TCall<void> *call = new TCall<void>(Once, reinterpret_cast<base_mock *>(mck), std::pair<int, int>(0, funcIndex), lineNo, "destructor", fileName);
addCall( call, expect );
return *call;
Expand Down Expand Up @@ -6361,6 +6418,23 @@ base *MockRepository::Mock() {
mocks.push_back(m);
return reinterpret_cast<base *>(m);
}

template <typename base>
std::unique_ptr<base> MockRepository::UniqueMock() {
return std::move(std::unique_ptr<base>{reinterpret_cast<base *>(new unique_mock<base>(this))});
}

template <typename base, typename Deleter>
std::unique_ptr<base,Deleter> MockRepository::UniqueMock(Deleter deleter) {
return std::move(std::unique_ptr<base,Deleter>{reinterpret_cast<base *>(new unique_mock<base>(this)), deleter});
}

template<typename base, typename d>
std::unique_ptr<base,d> tee(base*& capture, std::unique_ptr<base,d> && obj) {
capture = obj.get();
return std::move(obj);
}

inline std::ostream &operator<<(std::ostream &os, const Call &call)
{
os << call.fileName << "(" << call.lineno << "): "; //format for Visual studio, enables doubleclick on output line
Expand Down
1 change: 1 addition & 0 deletions HippoMocksTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ add_executable(${PROJECT_NAME}
test_ref_args.cpp
test_regression_arg_count.cpp
test_retval.cpp
test_unique_ptr.cpp
test_transaction.cpp
test_zombie.cpp
)
Expand Down
87 changes: 87 additions & 0 deletions HippoMocksTest/test_unique_ptr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include <string>

#include "gtest/gtest.h"
#include "hippomocks.h"

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(TestUniquePtr, checkUniquePtrDestruction) {
MockRepository mocks;
auto iu = mocks.UniqueMock<IU>();
}

TEST(TestUniquePtr, checkCallsWorksOnUniquePtr) {
MockRepository mocks;
std::unique_ptr<IU> iu = mocks.UniqueMock<IU>();
mocks.ExpectCall(iu.get(), IU::f);
iu->f();
}

TEST(TestUniquePtr, checkMissingExpectationsWorksOnUniquePtr) {
MockRepository mocks;
bool exceptionCaught = false;
std::unique_ptr<IU> iu = mocks.UniqueMock<IU>();
try {
iu->f();
} catch (HippoMocks::NotImplementedException const &) {
exceptionCaught = true;
}
EXPECT_TRUE(exceptionCaught);
}

TEST(TestUniquePtr, checkNeverCallWorksOnUniquePtr) {
bool exceptionCaught = false;
MockRepository mocks;
auto iu = mocks.UniqueMock<IU>();
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;
}
EXPECT_TRUE(exceptionCaught);
}

TEST(TestUniquePtr, checkClassArgumentsAcceptedWithUniquePtr) {
MockRepository mocks;
auto iamock = mocks.UniqueMock<IU>();
mocks.OnCall(iamock.get(), IU::i).With("hi");
mocks.OnCall(iamock.get(), IU::j).With("bye");
iamock->i("hi");
iamock->j("bye");
}

TEST(TestUniquePtr, checkClassArgumentsCheckedWithUniquePtr) {
MockRepository mocks;
auto iamock = mocks.UniqueMock<IU>();
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;
}
EXPECT_TRUE(exceptionCaught);
mocks.reset();
}

TEST(TestUniquePtr, checkClassArgumentsIgnoredWithUniquePtr) {
MockRepository mocks;
auto iamock = mocks.UniqueMock<IU>();
mocks.OnCall(iamock.get(), IU::i);
iamock->i("bye");
}