// // copy_ptr.t.h // pointers // // Created by Sam Jaffe on 1/5/17. // #include "pointers/value_ptr.hpp" #include #include #include "test_stubs.h" struct copy_me {}; struct copy_me_throw {}; namespace pointers { namespace detail { template <> class value_ptr_copy { protected: copy_me_throw * Copy(copy_me_throw const * p) const { if (p == nullptr) { throw std::runtime_error{"NULL"}; } return new copy_me_throw{*p}; } }; }} class base { public: virtual ~base() {} virtual base * clone() const = 0; virtual int id() const = 0; }; class derived_0 : public base { public: static const constexpr int ID = 0; virtual base * clone() const override { return new derived_0; } virtual int id() const override { return ID; } }; class derived_1 : public base { public: static const constexpr int ID = 1; virtual base * clone() const override { return new derived_1; } virtual int id() const override { return ID; } }; using namespace pointers; TEST(ValuePtrTest, CanCopySimpleObject) { value_ptr c1{new copy_me}; value_ptr c2{c1}; EXPECT_THAT(c1.get(), testing::Not(c2.get())); } TEST(ValuePtrTest, CopyCtorIsNullSafe) { value_ptr c1{nullptr}; value_ptr c2{c1}; EXPECT_THAT(c1.get(), testing::IsNull()); EXPECT_THAT(c1.get(), c2.get()); } TEST(ValuePtrCustomTest, CanCopyWithCustomFunction) { using ptr_t = value_ptr; value_ptr c1{new copy_me_throw}; value_ptr c2{c1}; EXPECT_THAT(c1.get(), testing::Not(c2.get())); } TEST(ValuePtrCustomTest, CustomCopyFunctionCanThrow) { value_ptr c1{nullptr}; EXPECT_THROW(value_ptr{c1}, std::runtime_error); } TEST(ValuePtrTest, CopiedValueDeeplyEqualButNotSameAddress) { std::vector my_vec = {1, 3, 5, 3, 6, 1, 2, -1, 0}; value_ptr> c1{new std::vector{my_vec}}; EXPECT_THAT(*c1, my_vec); value_ptr> c2{c1}; EXPECT_THAT(*c2, *c1); EXPECT_THAT(c2.get(), testing::Not(c1.get())); } TEST(ValuePtrPolymorphicTest, CanConstructPtrToBaseFromDerivedClasses) { value_ptr c0{new derived_0}; EXPECT_THAT(c0->id(), derived_0::ID); value_ptr c1{new derived_1}; EXPECT_THAT(c1->id(), derived_1::ID); } TEST(ValuePtrPolymorphicTest, CanConstructFromNullptr) { value_ptr c1{nullptr}; value_ptr c2{c1}; EXPECT_THAT(c1.get(), testing::IsNull()); EXPECT_THAT(c1.get(), c2.get()); } TEST(ValuePtrTest, OwnsGivenObject) { bool has_delete{false}; destructor_sentinal * test_struct = new destructor_sentinal{has_delete}; // I cannot actually copy-construct from a pointer for safety EXPECT_NO_THROW(value_ptr{std::move(test_struct)}); EXPECT_TRUE(has_delete); } TEST(ValuePtrTest, OwnsTemporaryObject) { bool has_delete{false}; EXPECT_NO_THROW( value_ptr{new destructor_sentinal{has_delete}}); EXPECT_TRUE(has_delete); } TEST(ValuePtrTest, FactoryMethodProducesCopy) { int deleted{0}; { std::unique_ptr test_struct{new destructor_ctr{deleted}}; EXPECT_NO_THROW(value_ptr::copy_of(test_struct.get())); EXPECT_THAT(deleted, 1); } EXPECT_THAT(deleted, 2); }