?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. // https://github.com/vinniefalco/LuaBridge
  2. // Copyright 2019, Dmitry Tarakanov
  3. // SPDX-License-Identifier: MIT
  4.  
  5. #include "TestBase.h"
  6.  
  7. #include "LuaBridge/RefCountedObject.h"
  8.  
  9. struct RefCountedObjectTests : TestBase
  10. {
  11.     template<class T>
  12.     T variable(const std::string& name)
  13.     {
  14.         runLua("result = " + name);
  15.         return result().cast<T>();
  16.     }
  17. };
  18.  
  19. namespace {
  20.  
  21. class RefCounted : public luabridge::RefCountedObject
  22. {
  23. public:
  24.     explicit RefCounted(bool& deleted) : m_deleted(deleted) { m_deleted = false; }
  25.  
  26.     ~RefCounted() { m_deleted = true; }
  27.  
  28.     bool isDeleted() const { return m_deleted; }
  29.  
  30. private:
  31.     bool& m_deleted;
  32. };
  33.  
  34. } // namespace
  35.  
  36. TEST_F(RefCountedObjectTests, ConstructorDefault)
  37. {
  38.     const luabridge::RefCountedObjectPtr<RefCounted> ptr;
  39.  
  40.     ASSERT_EQ(ptr, nullptr);
  41. }
  42.  
  43. TEST_F(RefCountedObjectTests, ConstructorObject)
  44. {
  45.     bool deleted = false;
  46.     RefCounted* const rawPtr = new RefCounted(deleted);
  47.     const luabridge::RefCountedObjectPtr<RefCounted> ptr(rawPtr);
  48.  
  49.     ASSERT_EQ(ptr, rawPtr);
  50.     ASSERT_EQ(rawPtr->getReferenceCount(), 1);
  51.     ASSERT_FALSE(deleted);
  52. }
  53.  
  54. TEST_F(RefCountedObjectTests, ConstructorCopy)
  55. {
  56.     bool deleted = false;
  57.     RefCounted* const rawPtr = new RefCounted(deleted);
  58.     const luabridge::RefCountedObjectPtr<RefCounted> ptr(rawPtr);
  59.     const luabridge::RefCountedObjectPtr<RefCounted> ptrCopy(ptr);
  60.  
  61.     ASSERT_EQ(ptr, rawPtr);
  62.     ASSERT_EQ(ptrCopy, rawPtr);
  63.     ASSERT_EQ(rawPtr->getReferenceCount(), 2);
  64.     ASSERT_FALSE(deleted);
  65. }
  66.  
  67. TEST_F(RefCountedObjectTests, ConstructorCopyPolymorph)
  68. {
  69.     struct RefCountedSpecialized : public RefCounted
  70.     {
  71.         explicit RefCountedSpecialized(bool& deleted) : RefCounted(deleted) {}
  72.     };
  73.  
  74.     bool deleted = false;
  75.     RefCountedSpecialized* const rawPtr = new RefCountedSpecialized(deleted);
  76.  
  77.     const luabridge::RefCountedObjectPtr<RefCountedSpecialized> ptr(rawPtr);
  78.     const luabridge::RefCountedObjectPtr<RefCounted> ptrCopy(ptr);
  79.  
  80.     ASSERT_EQ(ptr, rawPtr);
  81.     ASSERT_EQ(ptrCopy, rawPtr);
  82.     ASSERT_EQ(rawPtr->getReferenceCount(), 2);
  83.     ASSERT_FALSE(deleted);
  84. }
  85.  
  86. TEST_F(RefCountedObjectTests, Destructor)
  87. {
  88.     bool deleted = false;
  89.     {
  90.         luabridge::RefCountedObjectPtr<RefCounted> ptr(new RefCounted(deleted));
  91.         ASSERT_FALSE(deleted);
  92.     }
  93.  
  94.     ASSERT_TRUE(deleted);
  95. }
  96.  
  97. TEST_F(RefCountedObjectTests, AssignOperator)
  98. {
  99.     bool deletedPrevious = false;
  100.     luabridge::RefCountedObjectPtr<RefCounted> ptr(new RefCounted(deletedPrevious));
  101.  
  102.     bool deletedNew = false;
  103.     RefCounted* const rawPtr = new RefCounted(deletedNew);
  104.  
  105.     const luabridge::RefCountedObjectPtr<RefCounted>& returnValue = (ptr = rawPtr);
  106.  
  107.     ASSERT_EQ(&returnValue, &ptr);
  108.     ASSERT_EQ(ptr, rawPtr);
  109.     ASSERT_EQ(rawPtr->getReferenceCount(), 1);
  110.     ASSERT_TRUE(deletedPrevious);
  111.     ASSERT_FALSE(deletedNew);
  112. }
  113.  
  114. TEST_F(RefCountedObjectTests, AssignOperatorSameObject)
  115. {
  116.     bool deleted = false;
  117.     RefCounted* const rawPtr = new RefCounted(deleted);
  118.  
  119.     luabridge::RefCountedObjectPtr<RefCounted> ptr(rawPtr);
  120.  
  121.     const luabridge::RefCountedObjectPtr<RefCounted>& returnValue = (ptr = rawPtr);
  122.  
  123.     ASSERT_EQ(&returnValue, &ptr);
  124.     ASSERT_EQ(ptr, rawPtr);
  125.     ASSERT_EQ(rawPtr->getReferenceCount(), 1);
  126.     ASSERT_FALSE(deleted);
  127. }
  128.  
  129. TEST_F(RefCountedObjectTests, AssignOperatorRef)
  130. {
  131.     bool deletedPrevious = false;
  132.     luabridge::RefCountedObjectPtr<RefCounted> ptr(new RefCounted(deletedPrevious));
  133.  
  134.     bool deletedNew = false;
  135.     RefCounted* const rawPtrNew = new RefCounted(deletedNew);
  136.     const luabridge::RefCountedObjectPtr<RefCounted> ptrNew(rawPtrNew);
  137.  
  138.     const luabridge::RefCountedObjectPtr<RefCounted>& returnValue = (ptr = ptrNew);
  139.  
  140.     ASSERT_EQ(&returnValue, &ptr);
  141.     ASSERT_EQ(ptr, rawPtrNew);
  142.     ASSERT_EQ(rawPtrNew->getReferenceCount(), 2);
  143.     ASSERT_TRUE(deletedPrevious);
  144.     ASSERT_FALSE(deletedNew);
  145. }
  146.  
  147. TEST_F(RefCountedObjectTests, AssignOperatorRefPolymorph)
  148. {
  149.     struct RefCountedSpecialized : public RefCounted
  150.     {
  151.         explicit RefCountedSpecialized(bool& deleted) : RefCounted(deleted) {}
  152.     };
  153.  
  154.     bool deletedPrevious = false;
  155.     luabridge::RefCountedObjectPtr<RefCounted> ptr(new RefCounted(deletedPrevious));
  156.  
  157.     bool deletedNew = false;
  158.     RefCountedSpecialized* const rawPtrNew = new RefCountedSpecialized(deletedNew);
  159.     const luabridge::RefCountedObjectPtr<RefCountedSpecialized> ptrNew(rawPtrNew);
  160.  
  161.     const luabridge::RefCountedObjectPtr<RefCounted>& returnValue = (ptr = ptrNew);
  162.  
  163.     ASSERT_EQ(&returnValue, &ptr);
  164.     ASSERT_EQ(ptr, rawPtrNew);
  165.     ASSERT_EQ(rawPtrNew->getReferenceCount(), 2);
  166.     ASSERT_TRUE(deletedPrevious);
  167.     ASSERT_FALSE(deletedNew);
  168. }
  169.  
  170. TEST_F(RefCountedObjectTests, AssignOperatorRefSelfAssignment)
  171. {
  172.     bool deleted = false;
  173.     RefCounted* const rawPtr = new RefCounted(deleted);
  174.  
  175.     luabridge::RefCountedObjectPtr<RefCounted> ptr(rawPtr);
  176.  
  177.     const luabridge::RefCountedObjectPtr<RefCounted>& returnValue = (ptr = ptr);
  178.  
  179.     ASSERT_EQ(&returnValue, &ptr);
  180.     ASSERT_EQ(ptr, rawPtr);
  181.     ASSERT_EQ(rawPtr->getReferenceCount(), 1);
  182.     ASSERT_FALSE(deleted);
  183. }
  184.  
  185. TEST_F(RefCountedObjectTests, AssignOperatorRefSameObject)
  186. {
  187.     bool deleted = false;
  188.     RefCounted* const rawPtr = new RefCounted(deleted);
  189.  
  190.     const luabridge::RefCountedObjectPtr<RefCounted> ptr1(rawPtr);
  191.     luabridge::RefCountedObjectPtr<RefCounted> ptr2(rawPtr);
  192.  
  193.     const luabridge::RefCountedObjectPtr<RefCounted>& returnValue = (ptr2 = ptr1);
  194.  
  195.     ASSERT_EQ(&returnValue, &ptr2);
  196.     ASSERT_EQ(ptr1, rawPtr);
  197.     ASSERT_EQ(ptr2, rawPtr);
  198.     ASSERT_EQ(rawPtr->getReferenceCount(), 2);
  199.     ASSERT_FALSE(deleted);
  200. }
  201.  
  202. namespace {
  203.  
  204. class TestObjectNested final : public luabridge::RefCountedObject
  205. {
  206. public:
  207.     explicit TestObjectNested(const uint64_t value) : m_value(value) {}
  208.  
  209.     uint64_t getValue() const { return m_value; }
  210.  
  211.     luabridge::RefCountedObjectPtr<TestObjectNested>& getChild() { return m_child; }
  212.  
  213. private:
  214.     const uint64_t m_value;
  215.  
  216.     luabridge::RefCountedObjectPtr<TestObjectNested> m_child;
  217. };
  218.  
  219. } // namespace
  220.  
  221. TEST_F(RefCountedObjectTests, AssignOperatorRefNestedObjects)
  222. {
  223.     // Test assignment operator in the case that the previous referenced object is
  224.     // part of the new referenced object. This nested situation can only be handled
  225.     // if the reference count of the new object is FIRST increased and after that
  226.     // the count of the old object is decreased. If this happens vice versa the
  227.     // stored pointer is invalid after the assignment because it points to an already
  228.     // deleted object.
  229.     const uint64_t parentValue = 123, childValue = 456;
  230.  
  231.     luabridge::RefCountedObjectPtr<TestObjectNested> ref = new TestObjectNested(parentValue);
  232.     ref->getChild() = new TestObjectNested(childValue);
  233.  
  234.     ASSERT_EQ(ref->getValue(), parentValue);
  235.     ASSERT_EQ(ref->getChild()->getValue(), childValue);
  236.  
  237.     const luabridge::RefCountedObjectPtr<TestObjectNested>& returnValue = (ref = ref->getChild());
  238.     ASSERT_EQ(&returnValue, &ref);
  239.     ASSERT_EQ(ref->getValue(), childValue);
  240. }
  241.  
  242. TEST_F(RefCountedObjectTests, CompareOperators)
  243. {
  244.     bool deleted = false;
  245.  
  246.     RefCounted* const rawPtr1 = new RefCounted(deleted);
  247.     luabridge::RefCountedObjectPtr<RefCounted> ptr1(rawPtr1);
  248.  
  249.     RefCounted* const rawPtr2 = new RefCounted(deleted);
  250.     luabridge::RefCountedObjectPtr<RefCounted> ptr2(rawPtr2);
  251.  
  252.     ASSERT_TRUE(ptr1 == ptr1);
  253.     ASSERT_TRUE(ptr1 != ptr2);
  254.  
  255.     ASSERT_TRUE(rawPtr1 == ptr1);
  256.     ASSERT_TRUE(ptr1 == rawPtr1);
  257.  
  258.     ASSERT_TRUE(rawPtr2 != ptr1);
  259.     ASSERT_TRUE(ptr1 != rawPtr2);
  260. }
  261.  
  262. TEST_F(RefCountedObjectTests, LastReferenceInLua)
  263. {
  264.     luabridge::getGlobalNamespace(L)
  265.         .beginClass<RefCounted>("Class")
  266.         .addProperty("deleted", &RefCounted::isDeleted)
  267.         .endClass();
  268.  
  269.     bool deleted = false;
  270.     luabridge::RefCountedObjectPtr<RefCounted> object(new RefCounted(deleted));
  271.  
  272.     luabridge::setGlobal(L, object, "object");
  273.     runLua("result = object.deleted");
  274.     ASSERT_EQ(true, result().isBool());
  275.     ASSERT_EQ(false, result<bool>());
  276.  
  277.     object = nullptr;
  278.     runLua("result = object.deleted");
  279.     ASSERT_EQ(true, result().isBool());
  280.     ASSERT_EQ(false, result<bool>());
  281.     ASSERT_EQ(false, deleted);
  282.  
  283.     runLua("object = nil");
  284.     lua_gc(L, LUA_GCCOLLECT, 1);
  285.  
  286.     ASSERT_EQ(true, deleted);
  287. }
  288.  
  289. TEST_F(RefCountedObjectTests, LastReferenceInCpp)
  290. {
  291.     luabridge::getGlobalNamespace(L)
  292.         .beginClass<RefCounted>("Class")
  293.         .addProperty("deleted", &RefCounted::isDeleted)
  294.         .endClass();
  295.  
  296.     bool deleted = false;
  297.     luabridge::RefCountedObjectPtr<RefCounted> object(new RefCounted(deleted));
  298.  
  299.     luabridge::setGlobal(L, object, "object");
  300.     runLua("result = object.deleted");
  301.     ASSERT_EQ(true, result().isBool());
  302.     ASSERT_EQ(false, result<bool>());
  303.  
  304.     runLua("object = nil");
  305.     lua_gc(L, LUA_GCCOLLECT, 1);
  306.     ASSERT_EQ(false, deleted);
  307.  
  308.     object = nullptr;
  309.     ASSERT_EQ(true, deleted);
  310. }
  311.