#include #include #include "cpp-utils/pointer/cast.h" #include "cpp-utils/pointer/unique_ref.h" #include "cpp-utils/pointer/unique_ref_boost_optional_gtest_workaround.h" //TODO There is a lot of duplication here, because each test case is there twice - once for unique_ptr, once for unique_ref. Remove redundancy by using generic test cases. //TODO Then also move the unique_ref related test cases there - cast_test.cpp should only contain the unique_ptr related ones. using namespace cpputils; using std::unique_ptr; using std::make_unique; using boost::optional; using boost::none; class DestructorCallback { public: MOCK_METHOD(void, call, (), (const)); }; class Parent { public: virtual ~Parent() { } }; class Child : public Parent { public: Child(const DestructorCallback *childDestructorCallback) : _destructorCallback(childDestructorCallback) { } Child(): Child(nullptr) {} ~Child() override { if (_destructorCallback != nullptr) { _destructorCallback->call(); } } private: const DestructorCallback *_destructorCallback; DISALLOW_COPY_AND_ASSIGN(Child); }; class Child2 : public Parent {}; TEST(UniquePtr_DynamicPointerMoveTest, NullPtrParentToChildCast) { unique_ptr source(nullptr); const unique_ptr casted = dynamic_pointer_move(source); EXPECT_EQ(nullptr, source.get()); EXPECT_EQ(nullptr, casted.get()); } TEST(UniquePtr_DynamicPointerMoveTest, NullPtrChildToParentCast) { unique_ptr source(nullptr); const unique_ptr casted = dynamic_pointer_move(source); EXPECT_EQ(nullptr, source.get()); EXPECT_EQ(nullptr, casted.get()); } TEST(UniquePtr_DynamicPointerMoveTest, NullPtrSelfCast) { unique_ptr source(nullptr); const unique_ptr casted = dynamic_pointer_move(source); EXPECT_EQ(nullptr, source.get()); EXPECT_EQ(nullptr, casted.get()); } TEST(UniqueRef_DynamicPointerMoveTest, ValidParentToChildCast) { Child *obj = new Child(); unique_ref source(nullcheck(unique_ptr(obj)).value()); const unique_ref casted = dynamic_pointer_move(source).value(); EXPECT_FALSE(source.is_valid()); // source lost ownership EXPECT_EQ(obj, casted.get()); } TEST(UniquePtr_DynamicPointerMoveTest, ValidParentToChildCast) { Child *obj = new Child(); unique_ptr source(obj); const unique_ptr casted = dynamic_pointer_move(source); EXPECT_EQ(nullptr, source.get()); // source lost ownership EXPECT_EQ(obj, casted.get()); } TEST(UniqueRef_DynamicPointerMoveTest, InvalidParentToChildCast1) { Parent *obj = new Parent(); unique_ref source(nullcheck(unique_ptr(obj)).value()); const optional> casted = dynamic_pointer_move(source); EXPECT_EQ(obj, source.get()); // source still has ownership EXPECT_EQ(none, casted); } TEST(UniquePtr_DynamicPointerMoveTest, InvalidParentToChildCast1) { Parent *obj = new Parent(); unique_ptr source(obj); const unique_ptr casted = dynamic_pointer_move(source); EXPECT_EQ(obj, source.get()); // source still has ownership EXPECT_EQ(nullptr, casted.get()); } TEST(UniqueRef_DynamicPointerMoveTest, InvalidParentToChildCast2) { Child2 *obj = new Child2(); unique_ref source(nullcheck(unique_ptr(obj)).value()); const optional> casted = dynamic_pointer_move(source); EXPECT_EQ(obj, source.get()); // source still has ownership EXPECT_EQ(none, casted); } TEST(UniquePtr_DynamicPointerMoveTest, InvalidParentToChildCast2) { Child2 *obj = new Child2(); unique_ptr source(obj); const unique_ptr casted = dynamic_pointer_move(source); EXPECT_EQ(obj, source.get()); // source still has ownership EXPECT_EQ(nullptr, casted.get()); } TEST(UniqueRef_DynamicPointerMoveTest, ChildToParentCast) { Child *obj = new Child(); unique_ref source(nullcheck(unique_ptr(obj)).value()); const unique_ref casted = dynamic_pointer_move(source).value(); EXPECT_FALSE(source.is_valid()); // source lost ownership EXPECT_EQ(obj, casted.get()); } TEST(UniquePtr_DynamicPointerMoveTest, ChildToParentCast) { Child *obj = new Child(); unique_ptr source(obj); const unique_ptr casted = dynamic_pointer_move(source); EXPECT_EQ(nullptr, source.get()); // source lost ownership EXPECT_EQ(obj, casted.get()); } class UniqueRef_DynamicPointerMoveDestructorTest: public ::testing::Test { public: UniqueRef_DynamicPointerMoveDestructorTest(): childDestructorCallback() {} DestructorCallback childDestructorCallback; unique_ref createChild() { return make_unique_ref(&childDestructorCallback); } void EXPECT_CHILD_DESTRUCTOR_CALLED() { EXPECT_CALL(childDestructorCallback, call()).Times(1); } }; class UniquePtr_DynamicPointerMoveDestructorTest: public ::testing::Test { public: UniquePtr_DynamicPointerMoveDestructorTest(): childDestructorCallback() {} DestructorCallback childDestructorCallback; unique_ptr createChild() { return make_unique(&childDestructorCallback); } void EXPECT_CHILD_DESTRUCTOR_CALLED() { EXPECT_CALL(childDestructorCallback, call()).Times(1); } }; TEST_F(UniqueRef_DynamicPointerMoveDestructorTest, ChildInParentPtr) { const unique_ref parent = createChild(); EXPECT_CHILD_DESTRUCTOR_CALLED(); } TEST_F(UniquePtr_DynamicPointerMoveDestructorTest, ChildInParentPtr) { const unique_ptr parent = createChild(); EXPECT_CHILD_DESTRUCTOR_CALLED(); } TEST_F(UniqueRef_DynamicPointerMoveDestructorTest, ChildToParentCast) { unique_ref child = createChild(); const unique_ref parent = dynamic_pointer_move(child).value(); EXPECT_CHILD_DESTRUCTOR_CALLED(); } TEST_F(UniquePtr_DynamicPointerMoveDestructorTest, ChildToParentCast) { unique_ptr child = createChild(); const unique_ptr parent = dynamic_pointer_move(child); EXPECT_CHILD_DESTRUCTOR_CALLED(); } TEST_F(UniqueRef_DynamicPointerMoveDestructorTest, ParentToChildCast) { unique_ref parent = createChild(); const unique_ref child = dynamic_pointer_move(parent).value(); EXPECT_CHILD_DESTRUCTOR_CALLED(); } TEST_F(UniquePtr_DynamicPointerMoveDestructorTest, ParentToChildCast) { unique_ptr parent = createChild(); const unique_ptr child = dynamic_pointer_move(parent); EXPECT_CHILD_DESTRUCTOR_CALLED(); }