// Copyright Epic Games, Inc. All Rights Reserved. #include "pmatests/Defs.h" #include namespace pmatests { namespace { struct Counters { int constructed; int destructed; }; class Client { public: static Client* create(Counters& counters) { return new Client(counters); } static void destroy(Client* instance) { delete instance; } Client(Counters& counters_) : counters{& counters_} { counters->constructed += 1; } ~Client() { counters->destructed += 1; } Client(const Client&) = default; Client& operator=(const Client&) = default; Client(Client&&) = default; Client& operator=(Client&&) = default; private: Counters* counters; }; struct Base { virtual ~Base() = default; }; struct Derived : public Base { static Derived* create() { return new Derived{}; } static void destroy(Derived* ptr) { delete ptr; } }; } // namespace } // namespace pmatests TEST(ScopedPtrTest, EmptyConstruction) { pma::ScopedPtr sp; ASSERT_EQ(sp.get(), nullptr); ASSERT_FALSE(sp); } TEST(ScopedPtrTest, ProperCleanup) { pmatests::Counters counters{}; ASSERT_EQ(counters.constructed, 0); ASSERT_EQ(counters.destructed, 0); { auto sp = pma::makeScoped(counters); ASSERT_EQ(counters.constructed, 1); ASSERT_EQ(counters.destructed, 0); } ASSERT_EQ(counters.constructed, 1); ASSERT_EQ(counters.destructed, 1); } TEST(ScopedPtrTest, MoveAssign) { pmatests::Counters counters{}; ASSERT_EQ(counters.constructed, 0); ASSERT_EQ(counters.destructed, 0); { pma::ScopedPtr > sp; sp = pma::makeScoped(counters); ASSERT_EQ(counters.constructed, 1); ASSERT_EQ(counters.destructed, 0); } ASSERT_EQ(counters.constructed, 1); ASSERT_EQ(counters.destructed, 1); } TEST(ScopedPtrTest, MoveConstruct) { pmatests::Counters counters{}; ASSERT_EQ(counters.constructed, 0); ASSERT_EQ(counters.destructed, 0); { auto sp = pma::makeScoped(counters); pma::ScopedPtr > dest = std::move(sp); ASSERT_EQ(counters.constructed, 1); ASSERT_EQ(counters.destructed, 0); } ASSERT_EQ(counters.constructed, 1); ASSERT_EQ(counters.destructed, 1); } TEST(ScopedPtrTest, ReAssign) { pmatests::Counters counters{}; ASSERT_EQ(counters.constructed, 0); ASSERT_EQ(counters.destructed, 0); { auto sp = pma::makeScoped(counters); ASSERT_EQ(counters.constructed, 1); ASSERT_EQ(counters.destructed, 0); sp = nullptr; ASSERT_EQ(counters.constructed, 1); ASSERT_EQ(counters.destructed, 1); } ASSERT_EQ(counters.constructed, 1); ASSERT_EQ(counters.destructed, 1); } TEST(ScopedPtrTest, Reset) { pmatests::Counters counters{}; ASSERT_EQ(counters.constructed, 0); ASSERT_EQ(counters.destructed, 0); { auto sp = pma::makeScoped(counters); ASSERT_EQ(counters.constructed, 1); ASSERT_EQ(counters.destructed, 0); sp.reset(new pmatests::Client(counters)); ASSERT_EQ(counters.constructed, 2); ASSERT_EQ(counters.destructed, 1); } ASSERT_EQ(counters.constructed, 2); ASSERT_EQ(counters.destructed, 2); } TEST(ScopedPtrTest, UseNewDelete) { auto sp = pma::makeScoped(42); ASSERT_EQ(*sp, 42); } TEST(ScopedPtrTest, UseNewDeleteForArrays) { auto sp = pma::makeScoped(100ul); ASSERT_EQ(sp[0], 0); } TEST(ScopedPtrTest, CustomDestroyer) { std::size_t timesCalled = 0ul; { pma::ScopedPtr > sp{new int{}, [×Called](int* ptr) { delete ptr; ++timesCalled; }}; ASSERT_EQ(timesCalled, 0ul); } ASSERT_EQ(timesCalled, 1ul); } TEST(ScopedPtrTest, MoveAssignWithCustomDestroyer) { std::size_t timesCalled = 0ul; { using PtrType = pma::ScopedPtr >; PtrType sp; sp = PtrType{new pmatests::Derived{}, [×Called](pmatests::Base* ptr) { delete ptr; ++timesCalled; }}; ASSERT_EQ(timesCalled, 0ul); } ASSERT_EQ(timesCalled, 1ul); } TEST(ScopedPtrTest, MoveConstructWithCustomDestroyer) { std::size_t timesCalled = 0ul; { pma::ScopedPtr > sp{new pmatests::Derived{}, [×Called](pmatests::Base* ptr) { delete ptr; ++timesCalled; }}; ASSERT_EQ(timesCalled, 0ul); } ASSERT_EQ(timesCalled, 1ul); } TEST(ScopedPtrTest, UseDefaultCreateDestroy) { auto spPrimitive = pma::makeScoped(42); ASSERT_EQ(*spPrimitive, 42); auto spArray = pma::makeScoped(10ul); ASSERT_EQ(spArray[0], 0); } TEST(ScopedPtrTest, StoreDerivedInBasePointer) { using NewCreator = pma::New; using NewDestroyer = pma::Delete; pma::ScopedPtr vbp = pma::makeScoped(); using FactoryCreator = pma::FactoryCreate; using FactoryDestroyer = pma::FactoryDestroy; pma::ScopedPtr fbp = pma::makeScoped(); }