- // https://github.com/vinniefalco/LuaBridge 
- // Copyright 2021, Stefan Frings 
- // SPDX-License-Identifier: MIT 
-   
- #include <gtest/gtest.h> 
-   
- #include "LuaBridge/RefCountedPtr.h" 
-   
- class RefCountedPtrTests : public ::testing::Test, private luabridge::detail::RefCountedPtrBase 
- { 
- public: 
-     void SetUp() override { getRefCounts().clear(); } 
-   
-     void TearDown() override 
-     { 
-         for (const RefCountsType::value_type& refCountEntry : getRefCounts()) 
-         { 
-             std::cout << "REMAINING ptr=" << refCountEntry.first 
-                       << ", count=" << refCountEntry.second << std::endl; 
-         } 
-   
-         ASSERT_TRUE(getRefCounts().empty()); 
-     } 
-   
-     size_t getNumRefCounts() const { return getRefCounts().size(); } 
- }; 
-   
- TEST_F(RefCountedPtrTests, ConstructorDefault) 
- { 
-     const luabridge::RefCountedPtr<int> ptr; 
-   
-     ASSERT_EQ(ptr, nullptr); 
-     ASSERT_EQ(getNumRefCounts(), 0); 
-     ASSERT_EQ(ptr.use_count(), 0); 
- } 
-   
- TEST_F(RefCountedPtrTests, ConstructorObject) 
- { 
-     int* const rawPtr = new int(123); 
-     const luabridge::RefCountedPtr<int> ptr(rawPtr); 
-   
-     ASSERT_EQ(ptr, rawPtr); 
-     ASSERT_EQ(getNumRefCounts(), 1); 
-     ASSERT_EQ(ptr.use_count(), 1); 
- } 
-   
- TEST_F(RefCountedPtrTests, ConstructorCopy) 
- { 
-     int* const rawPtr = new int(123); 
-     const luabridge::RefCountedPtr<int> ptr(rawPtr); 
-     const luabridge::RefCountedPtr<int> ptrCopy(ptr); 
-   
-     ASSERT_EQ(ptr, rawPtr); 
-     ASSERT_EQ(ptrCopy, rawPtr); 
-     ASSERT_EQ(getNumRefCounts(), 1); 
-     ASSERT_EQ(ptr.use_count(), 2); 
-     ASSERT_EQ(ptrCopy.use_count(), 2); 
- } 
-   
- TEST_F(RefCountedPtrTests, ConstructorCopyPolymorph) 
- { 
-     struct Base 
-     { 
-     }; 
-     struct Specialized : public Base 
-     { 
-     }; 
-     Specialized* const rawPtr = new Specialized; 
-   
-     const luabridge::RefCountedPtr<Specialized> ptr(rawPtr); 
-     const luabridge::RefCountedPtr<Base> ptrCopy(ptr); 
-   
-     ASSERT_EQ(ptr, rawPtr); 
-     ASSERT_EQ(ptrCopy, rawPtr); 
-     ASSERT_EQ(getNumRefCounts(), 1); 
-     ASSERT_EQ(ptr.use_count(), 2); 
-     ASSERT_EQ(ptrCopy.use_count(), 2); 
- } 
-   
- namespace { 
-   
- class TestObject 
- { 
- public: 
-     explicit TestObject(bool& deleted) : m_deleted(deleted) { m_deleted = false; } 
-   
-     ~TestObject() { m_deleted = true; } 
-   
- private: 
-     bool& m_deleted; 
- }; 
-   
- } // namespace 
-   
- TEST_F(RefCountedPtrTests, Destructor) 
- { 
-     bool deleted = false; 
-     { 
-         const luabridge::RefCountedPtr<TestObject> ptr(new TestObject(deleted)); 
-         ASSERT_FALSE(deleted); 
-     } 
-   
-     ASSERT_TRUE(deleted); 
- } 
-   
- TEST_F(RefCountedPtrTests, ResetObject) 
- { 
-     bool deleted = false; 
-     luabridge::RefCountedPtr<TestObject> ptr(new TestObject(deleted)); 
-     ASSERT_FALSE(deleted); 
-   
-     ptr.reset(); 
-   
-     ASSERT_EQ(ptr, nullptr); 
-     ASSERT_TRUE(deleted); 
- } 
-   
- TEST_F(RefCountedPtrTests, ResetNull) 
- { 
-     luabridge::RefCountedPtr<TestObject> ptr; 
-   
-     ptr.reset(); 
-   
-     ASSERT_EQ(ptr, nullptr); 
- } 
-   
- TEST_F(RefCountedPtrTests, AssignOperator) 
- { 
-     bool deletedPrevious = false; 
-     luabridge::RefCountedPtr<TestObject> ptr(new TestObject(deletedPrevious)); 
-   
-     bool deletedNew = false; 
-     TestObject* const rawPtr = new TestObject(deletedNew); 
-   
-     const luabridge::RefCountedPtr<TestObject>& returnValue = (ptr = rawPtr); 
-   
-     ASSERT_EQ(&returnValue, &ptr); 
-     ASSERT_EQ(ptr, rawPtr); 
-     ASSERT_EQ(getNumRefCounts(), 1); 
-     ASSERT_EQ(ptr.use_count(), 1); 
-     ASSERT_TRUE(deletedPrevious); 
-     ASSERT_FALSE(deletedNew); 
- } 
-   
- TEST_F(RefCountedPtrTests, AssignOperatorSameObject) 
- { 
-     bool deleted = false; 
-     TestObject* const rawPtr = new TestObject(deleted); 
-   
-     luabridge::RefCountedPtr<TestObject> ptr(rawPtr); 
-   
-     const luabridge::RefCountedPtr<TestObject>& returnValue = (ptr = rawPtr); 
-   
-     ASSERT_EQ(&returnValue, &ptr); 
-     ASSERT_EQ(ptr, rawPtr); 
-     ASSERT_EQ(getNumRefCounts(), 1); 
-     ASSERT_EQ(ptr.use_count(), 1); 
-     ASSERT_FALSE(deleted); 
- } 
-   
- TEST_F(RefCountedPtrTests, AssignOperatorRef) 
- { 
-     bool deletedPrevious = false; 
-     luabridge::RefCountedPtr<TestObject> ptr(new TestObject(deletedPrevious)); 
-   
-     bool deletedNew = false; 
-     TestObject* const rawPtrNew = new TestObject(deletedNew); 
-     const luabridge::RefCountedPtr<TestObject> ptrNew(rawPtrNew); 
-   
-     const luabridge::RefCountedPtr<TestObject>& returnValue = (ptr = ptrNew); 
-   
-     ASSERT_EQ(&returnValue, &ptr); 
-     ASSERT_EQ(ptr, rawPtrNew); 
-     ASSERT_EQ(getNumRefCounts(), 1); 
-     ASSERT_EQ(ptr.use_count(), 2); 
-     ASSERT_EQ(ptrNew.use_count(), 2); 
-     ASSERT_TRUE(deletedPrevious); 
-     ASSERT_FALSE(deletedNew); 
- } 
-   
- TEST_F(RefCountedPtrTests, AssignOperatorRefPolymorph) 
- { 
-     struct TestObjectSpecialized : public TestObject 
-     { 
-         explicit TestObjectSpecialized(bool& deleted) : TestObject(deleted) {} 
-     }; 
-   
-     bool deletedPrevious = false; 
-     luabridge::RefCountedPtr<TestObject> ptr(new TestObject(deletedPrevious)); 
-   
-     bool deletedNew = false; 
-     TestObjectSpecialized* const rawPtrNew = new TestObjectSpecialized(deletedNew); 
-     const luabridge::RefCountedPtr<TestObjectSpecialized> ptrNew(rawPtrNew); 
-   
-     const luabridge::RefCountedPtr<TestObject>& returnValue = (ptr = ptrNew); 
-   
-     ASSERT_EQ(&returnValue, &ptr); 
-     ASSERT_EQ(ptr, rawPtrNew); 
-     ASSERT_EQ(getNumRefCounts(), 1); 
-     ASSERT_EQ(ptr.use_count(), 2); 
-     ASSERT_EQ(ptrNew.use_count(), 2); 
-     ASSERT_TRUE(deletedPrevious); 
-     ASSERT_FALSE(deletedNew); 
- } 
-   
- TEST_F(RefCountedPtrTests, AssignOperatorRefSelfAssignment) 
- { 
-     bool deleted = false; 
-     TestObject* const rawPtr = new TestObject(deleted); 
-   
-     luabridge::RefCountedPtr<TestObject> ptr(rawPtr); 
-   
-     const luabridge::RefCountedPtr<TestObject>& returnValue = (ptr = ptr); 
-   
-     ASSERT_EQ(&returnValue, &ptr); 
-     ASSERT_EQ(ptr, rawPtr); 
-     ASSERT_EQ(getNumRefCounts(), 1); 
-     ASSERT_EQ(ptr.use_count(), 1); 
-     ASSERT_FALSE(deleted); 
- } 
-   
- TEST_F(RefCountedPtrTests, AssignOperatorRefSameObject) 
- { 
-     bool deleted = false; 
-     TestObject* const rawPtr = new TestObject(deleted); 
-   
-     const luabridge::RefCountedPtr<TestObject> ptr1(rawPtr); 
-     luabridge::RefCountedPtr<TestObject> ptr2(rawPtr); 
-   
-     const luabridge::RefCountedPtr<TestObject>& returnValue = (ptr2 = ptr1); 
-   
-     ASSERT_EQ(&returnValue, &ptr2); 
-     ASSERT_EQ(ptr1, rawPtr); 
-     ASSERT_EQ(ptr2, rawPtr); 
-     ASSERT_EQ(getNumRefCounts(), 1); 
-     ASSERT_EQ(ptr1.use_count(), 2); 
-     ASSERT_EQ(ptr2.use_count(), 2); 
-     ASSERT_FALSE(deleted); 
- } 
-   
- namespace { 
-   
- class TestObjectNested 
- { 
- public: 
-     explicit TestObjectNested(const uint64_t value) : m_value(value) {} 
-   
-     uint64_t getValue() const { return m_value; } 
-   
-     luabridge::RefCountedPtr<TestObjectNested>& getChild() { return m_child; } 
-   
- private: 
-     const uint64_t m_value; 
-   
-     luabridge::RefCountedPtr<TestObjectNested> m_child; 
- }; 
-   
- } // namespace 
-   
- TEST_F(RefCountedPtrTests, AssignOperatorRefNestedObjects) 
- { 
-     // Test assignment operator in the case that the previous referenced object is 
-     // part of the new referenced object. This nested situation can only be handled 
-     // if the reference count of the new object is FIRST increased and after that 
-     // the count of the old object is decreased. If this happens vice versa the 
-     // stored pointer is invalid after the assignment because it points to an already 
-     // deleted object. 
-     const uint64_t parentValue = 123, childValue = 456; 
-   
-     luabridge::RefCountedPtr<TestObjectNested> ref = new TestObjectNested(parentValue); 
-     ref->getChild() = new TestObjectNested(childValue); 
-   
-     ASSERT_EQ(ref->getValue(), parentValue); 
-     ASSERT_EQ(ref->getChild()->getValue(), childValue); 
-   
-     const luabridge::RefCountedPtr<TestObjectNested>& returnValue = (ref = ref->getChild()); 
-     ASSERT_EQ(&returnValue, &ref); 
-     ASSERT_EQ(ref->getValue(), childValue); 
- } 
-   
- TEST_F(RefCountedPtrTests, CompareOperators) 
- { 
-     int* const rawPtr1 = new int; 
-     luabridge::RefCountedPtr<int> ptr1(rawPtr1); 
-   
-     int* const rawPtr2 = new int; 
-     luabridge::RefCountedPtr<int> ptr2(rawPtr2); 
-   
-     ASSERT_TRUE(ptr1 == ptr1); 
-     ASSERT_TRUE(ptr1 != ptr2); 
-   
-     ASSERT_TRUE(rawPtr1 == ptr1); 
-     ASSERT_TRUE(ptr1 == rawPtr1); 
-   
-     ASSERT_TRUE(rawPtr2 != ptr1); 
-     ASSERT_TRUE(ptr1 != rawPtr2); 
- } 
-