?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download

  1. // https://github.com/vinniefalco/LuaBridge
  2. // Copyright 2020, Dmitry Tarakanov
  3. // SPDX-License-Identifier: MIT
  4.  
  5. #include "TestBase.h"
  6.  
  7. #include <exception>
  8. #include <functional>
  9. #include <map>
  10. #include <memory>
  11.  
  12. struct ClassTests : TestBase
  13. {
  14.     template<class T>
  15.     T variable(const std::string& name)
  16.     {
  17.         runLua("result = " + name);
  18.         return result<T>();
  19.     }
  20. };
  21.  
  22. namespace {
  23.  
  24. struct EmptyBase
  25. {
  26. };
  27.  
  28. template<class T, class Base>
  29. struct Class : Base
  30. {
  31.     Class() : data() {}
  32.  
  33.     Class(T data) : data(data) {}
  34.  
  35.     static Class<T, Base> staticFunction(Class<T, Base> value) { return value; }
  36.  
  37.     std::string toString() const
  38.     {
  39.         std::ostringstream stream;
  40.         stream << data;
  41.         return stream.str();
  42.     }
  43.  
  44.     bool operator==(const Class<T, Base>& rhs) const { return data == rhs.data; }
  45.  
  46.     bool operator<(const Class<T, Base>& rhs) const { return data < rhs.data; }
  47.  
  48.     bool operator<=(const Class<T, Base>& rhs) const { return data <= rhs.data; }
  49.  
  50.     Class<T, Base> operator+(const Class<T, Base>& rhs) const
  51.     {
  52.         return Class<T, Base>(data + rhs.data);
  53.     }
  54.  
  55.     Class<T, Base> operator-(const Class<T, Base>& rhs) const
  56.     {
  57.         return Class<T, Base>(data - rhs.data);
  58.     }
  59.  
  60.     Class<T, Base> operator*(const Class<T, Base>& rhs) const
  61.     {
  62.         return Class<T, Base>(data * rhs.data);
  63.     }
  64.  
  65.     Class<T, Base> operator/(const Class<T, Base>& rhs) const
  66.     {
  67.         return Class<T, Base>(data / rhs.data);
  68.     }
  69.  
  70.     Class<T, Base> operator%(const Class<T, Base>& rhs) const
  71.     {
  72.         return Class<T, Base>(data % rhs.data);
  73.     }
  74.  
  75.     Class<T, Base> operator()(T param) { return Class<T, Base>(param); }
  76.  
  77.     int len() const { return data; }
  78.  
  79.     Class<T, Base> negate() const { return Class<T, Base>(-data); }
  80.  
  81.     T method(T value) { return value; }
  82.  
  83.     T methodState(T value, lua_State*) { return value; }
  84.  
  85.     T constMethod(T value) const { return value; }
  86.  
  87.     T getData() const { return data; }
  88.  
  89.     void setData(T data) { this->data = data; }
  90.  
  91.     T getDataState(lua_State*) const { return data; }
  92.  
  93.     void setDataState(T data, lua_State*) { this->data = data; }
  94.  
  95.     mutable T data;
  96.     static T staticData;
  97. };
  98.  
  99. template<class T, class Base>
  100. T Class<T, Base>::staticData = {};
  101.  
  102. } // namespace
  103.  
  104. TEST_F(ClassTests, IsInstance)
  105. {
  106.     using BaseClass = Class<int, EmptyBase>;
  107.     using OtherClass = Class<float, EmptyBase>;
  108.     using DerivedClass = Class<float, BaseClass>;
  109.  
  110.     luabridge::getGlobalNamespace(L)
  111.         .beginClass<BaseClass>("BaseClass")
  112.         .endClass()
  113.         .deriveClass<DerivedClass, BaseClass>("DerivedClass")
  114.         .endClass()
  115.         .beginClass<OtherClass>("OtherClass")
  116.         .endClass();
  117.  
  118.     BaseClass base;
  119.     luabridge::push(L, base);
  120.  
  121.     DerivedClass derived;
  122.     luabridge::push(L, derived);
  123.  
  124.     OtherClass other;
  125.     luabridge::push(L, other);
  126.  
  127.     ASSERT_TRUE(luabridge::isInstance<BaseClass>(L, -3));
  128.     ASSERT_FALSE(luabridge::isInstance<DerivedClass>(L, -3)); // BaseClass is not DerivedClass
  129.     ASSERT_FALSE(luabridge::isInstance<OtherClass>(L, -3));
  130.  
  131.     ASSERT_TRUE(luabridge::isInstance<BaseClass>(L, -2));
  132.     ASSERT_TRUE(luabridge::isInstance<DerivedClass>(L, -2)); // DerivedClass is BaseClass
  133.     ASSERT_FALSE(luabridge::isInstance<OtherClass>(L, -2));
  134.  
  135.     ASSERT_FALSE(luabridge::isInstance<BaseClass>(L, -1));
  136.     ASSERT_FALSE(luabridge::isInstance<DerivedClass>(L, -1));
  137.     ASSERT_TRUE(luabridge::isInstance<OtherClass>(L, -1));
  138. }
  139.  
  140. TEST_F(ClassTests, PassingUnregisteredClassToLuaThrows)
  141. {
  142.     using Unregistered = Class<int, EmptyBase>;
  143.  
  144.     runLua("function process_fn (value) end");
  145.  
  146.     auto process_fn = luabridge::getGlobal(L, "process_fn");
  147.     ASSERT_TRUE(process_fn.isFunction());
  148.  
  149.     Unregistered value(1);
  150.     const Unregistered constValue(2);
  151.     ASSERT_THROW(process_fn(value), std::exception);
  152.     ASSERT_THROW(process_fn(constValue), std::exception);
  153.     ASSERT_THROW(process_fn(&value), std::exception);
  154.     ASSERT_THROW(process_fn(&constValue), std::exception);
  155. }
  156.  
  157. TEST_F(ClassTests, PassWrongClassFromLuaThrows)
  158. {
  159.     using Right = Class<int, EmptyBase>;
  160.     using WrongBase = Class<float, EmptyBase>;
  161.     using Wrong = Class<int, WrongBase>;
  162.  
  163.     luabridge::getGlobalNamespace(L)
  164.         .beginClass<Right>("Right")
  165.         .endClass()
  166.         .beginClass<WrongBase>("WrongBase")
  167.         .endClass()
  168.         .beginClass<Wrong>("Wrong")
  169.         .addConstructor<void (*)(int)>()
  170.         .endClass()
  171.         .addFunction("processRight", &Right::staticFunction);
  172.  
  173.     // bad argument #1 to 'processRight' (Right expected, got Wrong)
  174.     ASSERT_THROW(runLua("result = processRight (Wrong (5))"), std::exception);
  175.     ASSERT_TRUE(result().isNil());
  176. }
  177.  
  178. TEST_F(ClassTests, PassDerivedClassInsteadOfBase)
  179. {
  180.     using Base = Class<int, EmptyBase>;
  181.     using Derived = Class<float, Base>;
  182.  
  183.     luabridge::getGlobalNamespace(L)
  184.         .beginClass<Base>("Base")
  185.         .endClass()
  186.         .deriveClass<Derived, Base>("Derived")
  187.         .addConstructor<void (*)(float)>()
  188.         .endClass()
  189.         .addFunction("processBase", &Base::staticFunction);
  190.  
  191.     runLua("result = processBase (Derived (3.14))");
  192.     ASSERT_EQ(0, result<Base>().data);
  193. }
  194.  
  195. namespace {
  196.  
  197. template<class T, class Base>
  198. T processNonConst(Class<T, Base>* object)
  199. {
  200.     return object->data;
  201. }
  202.  
  203. } // namespace
  204.  
  205. TEST_F(ClassTests, PassConstClassInsteadOfNonConstThrows)
  206. {
  207.     using Base = Class<int, EmptyBase>;
  208.     using Derived = Class<float, Base>;
  209.  
  210.     luabridge::getGlobalNamespace(L)
  211.         .beginClass<Base>("Base")
  212.         .endClass()
  213.         .deriveClass<Derived, Base>("Derived")
  214.         .endClass()
  215.         .addFunction("processNonConst", &processNonConst<float, Base>);
  216.  
  217.     const Derived constObject(1.2f);
  218.     luabridge::setGlobal(L, &constObject, "constObject");
  219.  
  220.     // bad argument #1 to 'processNonConst' (Derived expected, got const Derived)
  221.     ASSERT_THROW(runLua("result = processNonConst (constObject)"), std::exception);
  222.     ASSERT_TRUE(result().isNil());
  223. }
  224.  
  225. TEST_F(ClassTests, PassOtherTypeInsteadOfNonConstThrows)
  226. {
  227.     using Int = Class<int, EmptyBase>;
  228.  
  229.     luabridge::getGlobalNamespace(L)
  230.         .beginClass<Int>("Int")
  231.         .addConstructor<void (*)(int)>() // Show that it does't matter
  232.         .endClass()
  233.         .addFunction("processNonConst", &processNonConst<int, EmptyBase>);
  234.  
  235.     // bad argument #1 to 'processNonConst' (Int expected, got number)
  236.     ASSERT_THROW(runLua("result = processNonConst (1)"), std::exception);
  237.     ASSERT_TRUE(result().isNil());
  238. }
  239.  
  240. TEST_F(ClassTests, PassRegisteredClassInsteadOfUnregisteredThrows)
  241. {
  242.     using Int = Class<int, EmptyBase>;
  243.     using Float = Class<float, EmptyBase>;
  244.  
  245.     luabridge::getGlobalNamespace(L)
  246.         .beginClass<Float>("Float")
  247.         .addConstructor<void (*)(float)>()
  248.         .endClass()
  249.         .addFunction("processUnregisteredInt", &Int::staticFunction);
  250.  
  251.     // bad argument #1 to 'processUnregisteredInt' (unregistered class expected, got Float)
  252.     ASSERT_THROW(runLua("result = processUnregisteredInt (Float (1.2))"), std::exception);
  253.     ASSERT_TRUE(result().isNil());
  254. }
  255.  
  256. namespace {
  257.  
  258. Class<int, EmptyBase>& returnRef()
  259. {
  260.     static Class<int, EmptyBase> value(1);
  261.     return value;
  262. }
  263.  
  264. const Class<int, EmptyBase>& returnConstRef()
  265. {
  266.     return returnRef();
  267. }
  268.  
  269. Class<int, EmptyBase>* returnPtr()
  270. {
  271.     return &returnRef();
  272. }
  273.  
  274. const Class<int, EmptyBase>* returnConstPtr()
  275. {
  276.     return &returnConstRef();
  277. }
  278.  
  279. Class<int, EmptyBase> returnValue()
  280. {
  281.     return Class<int, EmptyBase>(2);
  282. }
  283.  
  284. void addHelperFunctions(lua_State* L)
  285. {
  286.     luabridge::getGlobalNamespace(L)
  287.         .addFunction("returnRef", &returnRef)
  288.         .addFunction("returnConstRef", &returnConstRef)
  289.         .addFunction("returnPtr", &returnPtr)
  290.         .addFunction("returnConstPtr", &returnConstPtr)
  291.         .addFunction("returnValue", &returnValue);
  292. }
  293.  
  294. } // namespace
  295.  
  296. TEST_F(ClassTests, PassingUnregisteredClassFromLuaThrows)
  297. {
  298.     using Unregistered = Class<int, EmptyBase>;
  299.  
  300.     addHelperFunctions(L);
  301.  
  302.     ASSERT_THROW(runLua("result = returnRef ()"), std::exception);
  303.     ASSERT_THROW(runLua("result = returnConstRef ()"), std::exception);
  304.     ASSERT_THROW(runLua("result = returnPtr ()"), std::exception);
  305.     ASSERT_THROW(runLua("result = returnConstPtr ()"), std::exception);
  306.     ASSERT_THROW(runLua("result = returnValue ()"), std::exception);
  307. }
  308.  
  309. TEST_F(ClassTests, DeriveFromUnregisteredClassThrows)
  310. {
  311.     using Base = Class<int, EmptyBase>;
  312.     using Derived = Class<float, Base>;
  313.  
  314.     ASSERT_THROW((luabridge::getGlobalNamespace(L).deriveClass<Derived, Base>("Derived")),
  315.                  std::exception);
  316.  
  317.     ASSERT_EQ(1, lua_gettop(L));
  318. }
  319.  
  320. struct ClassFunctions : ClassTests
  321. {
  322. };
  323.  
  324. TEST_F(ClassFunctions, MemberFunctions)
  325. {
  326.     using Int = Class<int, EmptyBase>;
  327.  
  328.     luabridge::getGlobalNamespace(L)
  329.         .beginClass<Int>("Int")
  330.         .addFunction("method", &Int::method)
  331.         .endClass();
  332.  
  333.     addHelperFunctions(L);
  334.  
  335.     runLua("result = returnRef ():method (1)");
  336.     ASSERT_EQ(1, result<int>());
  337.  
  338.     runLua("result = returnConstRef ().method"); // Don't call, just get
  339.     ASSERT_TRUE(result().isNil());
  340.  
  341.     runLua("result = returnPtr ():method (2)");
  342.     ASSERT_EQ(2, result<int>());
  343.  
  344.     runLua("result = returnConstPtr ().method"); // Don't call, just get
  345.     ASSERT_TRUE(result().isNil());
  346.  
  347.     runLua("result = returnValue ():method (3)");
  348.     ASSERT_EQ(3, result<int>());
  349. }
  350.  
  351. TEST_F(ClassFunctions, MemberFunctions_PassState)
  352. {
  353.     using Int = Class<int, EmptyBase>;
  354.  
  355.     luabridge::getGlobalNamespace(L)
  356.         .beginClass<Int>("Int")
  357.         .addFunction("method", &Int::methodState)
  358.         .endClass();
  359.  
  360.     addHelperFunctions(L);
  361.  
  362.     runLua("result = returnRef ():method (1)");
  363.     ASSERT_EQ(1, result<int>());
  364.  
  365.     runLua("result = returnConstRef ().method"); // Don't call, just get
  366.     ASSERT_TRUE(result().isNil());
  367.  
  368.     runLua("result = returnPtr ():method (2)");
  369.     ASSERT_EQ(2, result<int>());
  370.  
  371.     runLua("result = returnConstPtr ().method"); // Don't call, just get
  372.     ASSERT_TRUE(result().isNil());
  373.  
  374.     runLua("result = returnValue ():method (3)");
  375.     ASSERT_EQ(3, result<int>());
  376. }
  377.  
  378. TEST_F(ClassFunctions, ConstMemberFunctions)
  379. {
  380.     using Int = Class<int, EmptyBase>;
  381.  
  382.     luabridge::getGlobalNamespace(L)
  383.         .beginClass<Int>("Int")
  384.         .addFunction("constMethod", &Int::constMethod)
  385.         .endClass();
  386.  
  387.     addHelperFunctions(L);
  388.  
  389.     runLua("result = returnRef ():constMethod (1)");
  390.     ASSERT_EQ(1, result<int>());
  391.  
  392.     runLua("result = returnConstRef ():constMethod (2)");
  393.     ASSERT_EQ(2, result<int>());
  394.  
  395.     runLua("result = returnPtr ():constMethod (3)");
  396.     ASSERT_EQ(3, result<int>());
  397.  
  398.     runLua("result = returnConstPtr ():constMethod (4)");
  399.     ASSERT_EQ(4, result<int>());
  400.  
  401.     runLua("result = returnValue ():constMethod (5)");
  402.     ASSERT_EQ(5, result<int>());
  403. }
  404.  
  405. namespace {
  406.  
  407. template<class T, class Base>
  408. T proxyFunction(Class<T, Base>* object, T value)
  409. {
  410.     object->data = value;
  411.     return value;
  412. }
  413.  
  414. template<class T, class Base>
  415. T proxyFunctionState(Class<T, Base>* object, T value, lua_State*)
  416. {
  417.     object->data = value;
  418.     return value;
  419. }
  420.  
  421. template<class T, class Base>
  422. T proxyConstFunction(const Class<T, Base>* object, T value)
  423. {
  424.     return value;
  425. }
  426.  
  427. } // namespace
  428.  
  429. TEST_F(ClassFunctions, ProxyFunctions)
  430. {
  431.     using Int = Class<int, EmptyBase>;
  432.  
  433.     luabridge::getGlobalNamespace(L)
  434.         .beginClass<Int>("Int")
  435.         .addFunction("method", &proxyFunction<int, EmptyBase>)
  436.         .endClass();
  437.  
  438.     addHelperFunctions(L);
  439.  
  440.     runLua("result = returnRef ():method (1)");
  441.     ASSERT_EQ(1, result<int>());
  442.  
  443.     runLua("result = returnConstRef ().method"); // Don't call, just get
  444.     ASSERT_TRUE(result().isNil());
  445.  
  446.     runLua("result = returnPtr ():method (2)");
  447.     ASSERT_EQ(2, result<int>());
  448.  
  449.     runLua("result = returnConstPtr ().method"); // Don't call, just get
  450.     ASSERT_TRUE(result().isNil());
  451.  
  452.     runLua("result = returnValue ():method (3)");
  453.     ASSERT_EQ(3, result<int>());
  454. }
  455.  
  456. TEST_F(ClassFunctions, ProxyFunctions_PassState)
  457. {
  458.     using Int = Class<int, EmptyBase>;
  459.  
  460.     luabridge::getGlobalNamespace(L)
  461.         .beginClass<Int>("Int")
  462.         .addFunction("method", &proxyFunctionState<int, EmptyBase>)
  463.         .endClass();
  464.  
  465.     addHelperFunctions(L);
  466.  
  467.     runLua("result = returnRef ():method (1)");
  468.     ASSERT_EQ(1, result<int>());
  469.  
  470.     runLua("result = returnConstRef ().method"); // Don't call, just get
  471.     ASSERT_TRUE(result().isNil());
  472.  
  473.     runLua("result = returnPtr ():method (2)");
  474.     ASSERT_EQ(2, result<int>());
  475.  
  476.     runLua("result = returnConstPtr ().method"); // Don't call, just get
  477.     ASSERT_TRUE(result().isNil());
  478.  
  479.     runLua("result = returnValue ():method (3)");
  480.     ASSERT_EQ(3, result<int>());
  481. }
  482.  
  483. TEST_F(ClassFunctions, ConstProxyFunctions)
  484. {
  485.     using Int = Class<int, EmptyBase>;
  486.  
  487.     luabridge::getGlobalNamespace(L)
  488.         .beginClass<Int>("Int")
  489.         .addFunction("constMethod", &proxyConstFunction<int, EmptyBase>)
  490.         .endClass();
  491.  
  492.     addHelperFunctions(L);
  493.  
  494.     runLua("result = returnRef ():constMethod (1)");
  495.     ASSERT_EQ(1, result<int>());
  496.  
  497.     runLua("result = returnConstRef ():constMethod (2)");
  498.     ASSERT_EQ(2, result<int>());
  499.  
  500.     runLua("result = returnPtr ():constMethod (3)");
  501.     ASSERT_EQ(3, result<int>());
  502.  
  503.     runLua("result = returnConstPtr ():constMethod (4)");
  504.     ASSERT_EQ(4, result<int>());
  505.  
  506.     runLua("result = returnValue ():constMethod (5)");
  507.     ASSERT_EQ(5, result<int>());
  508. }
  509.  
  510. TEST_F(ClassFunctions, StdFunctions)
  511. {
  512.     using Int = Class<int, EmptyBase>;
  513.  
  514.     auto sharedData = std::make_shared<int>();
  515.     std::weak_ptr<int> data = sharedData; // Check __gc meta-method
  516.  
  517.     std::function<int(Int*, int)> function = [sharedData](Int* object, int value) {
  518.         object->data = value;
  519.         return value;
  520.     };
  521.  
  522.     luabridge::getGlobalNamespace(L)
  523.         .beginClass<Int>("Int")
  524.         .addFunction("method", std::move(function))
  525.         .endClass();
  526.  
  527.     sharedData = nullptr;
  528.     ASSERT_FALSE(data.expired());
  529.  
  530.     addHelperFunctions(L);
  531.  
  532.     runLua("result = returnRef ():method (1)");
  533.     ASSERT_EQ(1, result<int>());
  534.  
  535.     runLua("result = returnConstRef ().method"); // Don't call, just get
  536.     ASSERT_TRUE(result().isNil());
  537.  
  538.     runLua("result = returnPtr ():method (2)");
  539.     ASSERT_EQ(2, result<int>());
  540.  
  541.     runLua("result = returnConstPtr ().method"); // Don't call, just get
  542.     ASSERT_TRUE(result().isNil());
  543.  
  544.     runLua("result = returnValue ():method (3)");
  545.     ASSERT_EQ(3, result<int>());
  546.  
  547.     runLua("result = nil");
  548.     lua_close(L); // Force garbage collection
  549.     L = nullptr;
  550.  
  551.     ASSERT_TRUE(data.expired());
  552. }
  553.  
  554. TEST_F(ClassFunctions, StdFunctions_PassState)
  555. {
  556.     using Int = Class<int, EmptyBase>;
  557.  
  558.     auto sharedData = std::make_shared<int>();
  559.     std::weak_ptr<int> data = sharedData; // Check __gc meta-method
  560.  
  561.     std::function<int(Int*, int, lua_State*)> function =
  562.         [sharedData](Int* object, int value, lua_State*) {
  563.             object->data = value;
  564.             return value;
  565.         };
  566.  
  567.     luabridge::getGlobalNamespace(L)
  568.         .beginClass<Int>("Int")
  569.         .addFunction("method", std::move(function))
  570.         .endClass();
  571.  
  572.     sharedData = nullptr;
  573.     ASSERT_FALSE(data.expired());
  574.  
  575.     addHelperFunctions(L);
  576.  
  577.     runLua("result = returnRef ():method (1)");
  578.     ASSERT_EQ(1, result<int>());
  579.  
  580.     runLua("result = returnConstRef ().method"); // Don't call, just get
  581.     ASSERT_TRUE(result().isNil());
  582.  
  583.     runLua("result = returnPtr ():method (2)");
  584.     ASSERT_EQ(2, result<int>());
  585.  
  586.     runLua("result = returnConstPtr ().method"); // Don't call, just get
  587.     ASSERT_TRUE(result().isNil());
  588.  
  589.     runLua("result = returnValue ():method (3)");
  590.     ASSERT_EQ(3, result<int>());
  591.  
  592.     runLua("result = nil");
  593.     lua_close(L); // Force garbage collection
  594.     L = nullptr;
  595.  
  596.     ASSERT_TRUE(data.expired());
  597. }
  598.  
  599. TEST_F(ClassFunctions, ConstStdFunctions)
  600. {
  601.     using Int = Class<int, EmptyBase>;
  602.  
  603.     auto sharedData = std::make_shared<int>();
  604.     std::weak_ptr<int> data = sharedData; // Check __gc meta-method
  605.  
  606.     std::function<int(const Int*, int)> function = [sharedData](const Int* object, int value) {
  607.         object->data = value;
  608.         return value;
  609.     };
  610.  
  611.     luabridge::getGlobalNamespace(L)
  612.         .beginClass<Int>("Int")
  613.         .addFunction("constMethod", std::move(function))
  614.         .endClass();
  615.  
  616.     sharedData = nullptr;
  617.     ASSERT_FALSE(data.expired());
  618.  
  619.     addHelperFunctions(L);
  620.  
  621.     runLua("result = returnRef ():constMethod (1)");
  622.     ASSERT_EQ(1, result<int>());
  623.  
  624.     runLua("result = returnConstRef ():constMethod (2)");
  625.     ASSERT_EQ(2, result<int>());
  626.  
  627.     runLua("result = returnPtr ():constMethod (3)");
  628.     ASSERT_EQ(3, result<int>());
  629.  
  630.     runLua("result = returnConstPtr ():constMethod (4)");
  631.     ASSERT_EQ(4, result<int>());
  632.  
  633.     runLua("result = returnValue ():constMethod (5)");
  634.     ASSERT_EQ(5, result<int>());
  635.  
  636.     runLua("result = nil");
  637.     lua_close(L); // Force garbage collection
  638.     L = nullptr;
  639.  
  640.     ASSERT_TRUE(data.expired());
  641. }
  642.  
  643. struct ClassProperties : ClassTests
  644. {
  645. };
  646.  
  647. TEST_F(ClassProperties, FieldPointers)
  648. {
  649.     using Int = Class<int, EmptyBase>;
  650.  
  651.     luabridge::getGlobalNamespace(L)
  652.         .beginClass<Int>("Int")
  653.         .addConstructor<void (*)(int)>()
  654.         .addProperty("data", &Int::data, true)
  655.         .endClass();
  656.  
  657.     runLua("result = Int (501)");
  658.     ASSERT_TRUE(result()["data"].isNumber());
  659.     ASSERT_EQ(501, result()["data"].cast<int>());
  660.  
  661.     runLua("result.data = 2");
  662.     ASSERT_TRUE(result()["data"].isNumber());
  663.     ASSERT_EQ(2, result()["data"].cast<int>());
  664.  
  665.     runLua("result = Int (42).data");
  666.     ASSERT_TRUE(result().isNumber());
  667.     ASSERT_EQ(42, result<int>());
  668. }
  669.  
  670. TEST_F(ClassProperties, FieldPointers_ReadOnly)
  671. {
  672.     using Int = Class<int, EmptyBase>;
  673.  
  674.     luabridge::getGlobalNamespace(L)
  675.         .beginClass<Int>("Int")
  676.         .addConstructor<void (*)(int)>()
  677.         .addProperty("data", &Int::data, false)
  678.         .endClass();
  679.  
  680.     runLua("result = Int (501)");
  681.     ASSERT_TRUE(result()["data"].isNumber());
  682.     ASSERT_EQ(501, result()["data"].cast<int>());
  683.  
  684.     ASSERT_THROW(runLua("result.data = 2"), std::exception);
  685.  
  686.     runLua("result = Int (42).data");
  687.     ASSERT_TRUE(result().isNumber());
  688.     ASSERT_EQ(42, result<int>());
  689. }
  690.  
  691. TEST_F(ClassProperties, MemberFunctions)
  692. {
  693.     using Int = Class<int, EmptyBase>;
  694.  
  695.     luabridge::getGlobalNamespace(L)
  696.         .beginClass<Int>("Int")
  697.         .addConstructor<void (*)(int)>()
  698.         .addProperty("data", &Int::getData, &Int::setData)
  699.         .endClass();
  700.  
  701.     runLua("result = Int (501)");
  702.     ASSERT_TRUE(result()["data"].isNumber());
  703.     ASSERT_EQ(501, result()["data"].cast<int>());
  704.  
  705.     runLua("result.data = -2");
  706.     ASSERT_TRUE(result()["data"].isNumber());
  707.     ASSERT_EQ(-2, result()["data"].cast<int>());
  708. }
  709.  
  710. TEST_F(ClassProperties, MemberFunctions_PassState)
  711. {
  712.     using Int = Class<int, EmptyBase>;
  713.  
  714.     luabridge::getGlobalNamespace(L)
  715.         .beginClass<Int>("Int")
  716.         .addConstructor<void (*)(int)>()
  717.         .addProperty("data", &Int::getDataState, &Int::setDataState)
  718.         .endClass();
  719.  
  720.     runLua("result = Int (501)");
  721.     ASSERT_TRUE(result()["data"].isNumber());
  722.     ASSERT_EQ(501, result()["data"].cast<int>());
  723.  
  724.     runLua("result.data = -2");
  725.     ASSERT_TRUE(result()["data"].isNumber());
  726.     ASSERT_EQ(-2, result()["data"].cast<int>());
  727. }
  728.  
  729. TEST_F(ClassProperties, MemberFunctions_ReadOnly)
  730. {
  731.     using Int = Class<int, EmptyBase>;
  732.  
  733.     luabridge::getGlobalNamespace(L)
  734.         .beginClass<Int>("Int")
  735.         .addConstructor<void (*)(int)>()
  736.         .addProperty("data", &Int::getData)
  737.         .endClass();
  738.  
  739.     runLua("result = Int (501)");
  740.     ASSERT_TRUE(result()["data"].isNumber());
  741.     ASSERT_EQ(501, result()["data"].cast<int>());
  742.  
  743.     ASSERT_THROW(runLua("result.data = -2"), std::exception);
  744.     ASSERT_EQ(501, result()["data"].cast<int>());
  745. }
  746.  
  747. TEST_F(ClassProperties, MemberFunctions_Derived)
  748. {
  749.     using Base = Class<std::string, EmptyBase>;
  750.     using Derived = Class<int, Base>;
  751.  
  752.     luabridge::getGlobalNamespace(L)
  753.         .beginClass<Base>("Base")
  754.         .addProperty("data", &Base::getData, &Base::setData)
  755.         .endClass()
  756.         .deriveClass<Derived, Base>("Derived")
  757.         .endClass();
  758.  
  759.     Derived derived(12);
  760.     derived.Base::data = "abc";
  761.     luabridge::setGlobal(L, &derived, "derived");
  762.  
  763.     runLua("result = derived.data");
  764.     ASSERT_TRUE(result().isString());
  765.     ASSERT_EQ("abc", result<std::string>());
  766.  
  767.     runLua("derived.data = 5"); // Lua just casts integer to string
  768.     ASSERT_EQ("5", derived.Base::data);
  769.     ASSERT_EQ(12, derived.data);
  770.  
  771.     runLua("derived.data = '123'");
  772.     ASSERT_EQ("123", derived.Base::data);
  773.     ASSERT_EQ(12, derived.data);
  774. }
  775.  
  776. TEST_F(ClassProperties, MemberFunctions_Overridden)
  777. {
  778.     using Base = Class<float, EmptyBase>;
  779.     using Derived = Class<int, Base>;
  780.  
  781.     luabridge::getGlobalNamespace(L)
  782.         .beginClass<Base>("Base")
  783.         .addProperty("data", &Base::getData, &Base::setData)
  784.         .endClass()
  785.         .deriveClass<Derived, Base>("Derived")
  786.         .addProperty("data", &Derived::getData, &Derived::setData)
  787.         .endClass();
  788.  
  789.     Derived derived(50);
  790.     derived.Base::data = 1.23f;
  791.     luabridge::setGlobal(L, static_cast<Base*>(&derived), "base");
  792.     luabridge::setGlobal(L, &derived, "derived");
  793.  
  794.     runLua("result = base.data");
  795.     ASSERT_TRUE(result().isNumber());
  796.     ASSERT_EQ(1.23f, result<float>());
  797.  
  798.     runLua("result = derived.data");
  799.     ASSERT_TRUE(result().isNumber());
  800.     ASSERT_EQ(50, result<int>());
  801.  
  802.     runLua("base.data = -3.14");
  803.     ASSERT_EQ(-3.14f, derived.Base::data);
  804.     ASSERT_EQ(50, derived.data);
  805.  
  806.     runLua("derived.data = 7");
  807.     ASSERT_EQ(-3.14f, derived.Base::data);
  808.     ASSERT_EQ(7, derived.data);
  809. }
  810.  
  811. namespace {
  812.  
  813. template<class T, class BaseClass>
  814. T getData(const Class<T, BaseClass>* object)
  815. {
  816.     return object->data;
  817. }
  818.  
  819. template<class T, class BaseClass>
  820. void setData(Class<T, BaseClass>* object, T data)
  821. {
  822.     object->data = data;
  823. }
  824.  
  825. } // namespace
  826.  
  827. TEST_F(ClassProperties, ProxyFunctions)
  828. {
  829.     using Int = Class<int, EmptyBase>;
  830.  
  831.     luabridge::getGlobalNamespace(L)
  832.         .beginClass<Int>("Int")
  833.         .addConstructor<void (*)(int)>()
  834.         .addProperty("data", &getData<int, EmptyBase>, &setData<int, EmptyBase>)
  835.         .endClass();
  836.  
  837.     runLua("result = Int (501)");
  838.     ASSERT_TRUE(result()["data"].isNumber());
  839.     ASSERT_EQ(501, result()["data"].cast<int>());
  840.  
  841.     runLua("result.data = -2");
  842.     ASSERT_TRUE(result()["data"].isNumber());
  843.     ASSERT_EQ(-2, result()["data"].cast<int>());
  844. }
  845.  
  846. TEST_F(ClassProperties, ProxyFunctions_ReadOnly)
  847. {
  848.     using Int = Class<int, EmptyBase>;
  849.  
  850.     luabridge::getGlobalNamespace(L)
  851.         .beginClass<Int>("Int")
  852.         .addConstructor<void (*)(int)>()
  853.         .addProperty("data", &getData<int, EmptyBase>)
  854.         .endClass();
  855.  
  856.     runLua("result = Int (501)");
  857.     ASSERT_TRUE(result()["data"].isNumber());
  858.     ASSERT_EQ(501, result()["data"].cast<int>());
  859.  
  860.     ASSERT_THROW(runLua("result.data = -2"), std::exception);
  861.     ASSERT_EQ(501, result()["data"].cast<int>());
  862. }
  863.  
  864. TEST_F(ClassProperties, ProxyFunctions_Derived)
  865. {
  866.     using Base = Class<std::string, EmptyBase>;
  867.     using Derived = Class<int, Base>;
  868.  
  869.     luabridge::getGlobalNamespace(L)
  870.         .beginClass<Base>("Base")
  871.         .addProperty("data", &getData<std::string, EmptyBase>, &setData<std::string, EmptyBase>)
  872.         .endClass()
  873.         .deriveClass<Derived, Base>("Derived")
  874.         .endClass();
  875.  
  876.     Derived derived(12);
  877.     derived.Base::data = "abc";
  878.     luabridge::setGlobal(L, &derived, "derived");
  879.  
  880.     runLua("result = derived.data");
  881.     ASSERT_TRUE(result().isString());
  882.     ASSERT_EQ("abc", result<std::string>());
  883.  
  884.     runLua("derived.data = 5"); // Lua just casts integer to string
  885.     ASSERT_EQ("5", derived.Base::data);
  886.     ASSERT_EQ(12, derived.data);
  887.  
  888.     runLua("derived.data = '123'");
  889.     ASSERT_EQ("123", derived.Base::data);
  890.     ASSERT_EQ(12, derived.data);
  891. }
  892.  
  893. TEST_F(ClassProperties, ProxyFunctions_Overridden)
  894. {
  895.     using Base = Class<float, EmptyBase>;
  896.     using Derived = Class<int, Base>;
  897.  
  898.     luabridge::getGlobalNamespace(L)
  899.         .beginClass<Base>("Base")
  900.         .addProperty("data", &getData<float, EmptyBase>, &setData<float, EmptyBase>)
  901.         .endClass()
  902.         .deriveClass<Derived, Base>("Derived")
  903.         .addProperty("data", &getData<int, Base>, &setData<int, Base>)
  904.         .endClass();
  905.  
  906.     Derived derived(50);
  907.     derived.Base::data = 1.23f;
  908.     luabridge::setGlobal(L, static_cast<Base*>(&derived), "base");
  909.     luabridge::setGlobal(L, &derived, "derived");
  910.  
  911.     runLua("result = base.data");
  912.     ASSERT_TRUE(result().isNumber());
  913.     ASSERT_EQ(1.23f, result<float>());
  914.  
  915.     runLua("result = derived.data");
  916.     ASSERT_TRUE(result().isNumber());
  917.     ASSERT_EQ(50, result<int>());
  918.  
  919.     runLua("base.data = -3.14");
  920.     ASSERT_EQ(-3.14f, derived.Base::data);
  921.     ASSERT_EQ(50, derived.data);
  922.  
  923.     runLua("derived.data = 7");
  924.     ASSERT_EQ(-3.14f, derived.Base::data);
  925.     ASSERT_EQ(7, derived.data);
  926. }
  927.  
  928. namespace {
  929.  
  930. template<class T, class BaseClass>
  931. int getDataC(lua_State* L)
  932. {
  933.     auto objectRef = luabridge::LuaRef::fromStack(L, 1);
  934.     auto* object = objectRef.cast<const Class<T, BaseClass>*>();
  935.     luabridge::Stack<T>::push(L, object->data);
  936.     return 1;
  937. }
  938.  
  939. template<class T, class BaseClass>
  940. int setDataC(lua_State* L)
  941. {
  942.     auto objectRef = luabridge::LuaRef::fromStack(L, 1);
  943.     auto* object = objectRef.cast<const Class<T, BaseClass>*>();
  944.     auto valueRef = luabridge::LuaRef::fromStack(L, 2);
  945.     T value = valueRef.cast<T>();
  946.     object->data = value;
  947.     return 0;
  948. }
  949.  
  950. } // namespace
  951.  
  952. TEST_F(ClassProperties, ProxyCFunctions)
  953. {
  954.     using Int = Class<int, EmptyBase>;
  955.  
  956.     luabridge::getGlobalNamespace(L)
  957.         .beginClass<Int>("Int")
  958.         .addConstructor<void (*)(int)>()
  959.         .addProperty("data", &getDataC<int, EmptyBase>, &setDataC<int, EmptyBase>)
  960.         .endClass();
  961.  
  962.     runLua("result = Int (501)");
  963.     ASSERT_TRUE(result()["data"].isNumber());
  964.     ASSERT_EQ(501, result()["data"].cast<int>());
  965.  
  966.     runLua("result.data = -2");
  967.     ASSERT_TRUE(result()["data"].isNumber());
  968.     ASSERT_EQ(-2, result()["data"].cast<int>());
  969. }
  970.  
  971. TEST_F(ClassProperties, ProxyCFunctions_ReadOnly)
  972. {
  973.     using Int = Class<int, EmptyBase>;
  974.  
  975.     luabridge::getGlobalNamespace(L)
  976.         .beginClass<Int>("Int")
  977.         .addConstructor<void (*)(int)>()
  978.         .addProperty("data", &getDataC<int, EmptyBase>)
  979.         .endClass();
  980.  
  981.     runLua("result = Int (501)");
  982.     ASSERT_TRUE(result()["data"].isNumber());
  983.     ASSERT_EQ(501, result()["data"].cast<int>());
  984.  
  985.     ASSERT_THROW(runLua("result.data = -2"), std::exception);
  986.     ASSERT_EQ(501, result()["data"].cast<int>());
  987. }
  988.  
  989. TEST_F(ClassProperties, ProxyCFunctions_Derived)
  990. {
  991.     using Base = Class<std::string, EmptyBase>;
  992.     using Derived = Class<int, Base>;
  993.  
  994.     luabridge::getGlobalNamespace(L)
  995.         .beginClass<Base>("Base")
  996.         .addProperty("data", &getDataC<std::string, EmptyBase>, &setDataC<std::string, EmptyBase>)
  997.         .endClass()
  998.         .deriveClass<Derived, Base>("Derived")
  999.         .endClass();
  1000.  
  1001.     Derived derived(12);
  1002.     derived.Base::data = "abc";
  1003.     luabridge::setGlobal(L, &derived, "derived");
  1004.  
  1005.     runLua("result = derived.data");
  1006.     ASSERT_TRUE(result().isString());
  1007.     ASSERT_EQ("abc", result<std::string>());
  1008.  
  1009.     runLua("derived.data = 5"); // Lua just casts integer to string
  1010.     ASSERT_EQ("5", derived.Base::data);
  1011.     ASSERT_EQ(12, derived.data);
  1012.  
  1013.     runLua("derived.data = '123'");
  1014.     ASSERT_EQ("123", derived.Base::data);
  1015.     ASSERT_EQ(12, derived.data);
  1016. }
  1017.  
  1018. TEST_F(ClassProperties, ProxyCFunctions_Overridden)
  1019. {
  1020.     using Base = Class<float, EmptyBase>;
  1021.     using Derived = Class<int, Base>;
  1022.  
  1023.     luabridge::getGlobalNamespace(L)
  1024.         .beginClass<Base>("Base")
  1025.         .addProperty("data", &getDataC<float, EmptyBase>, &setDataC<float, EmptyBase>)
  1026.         .endClass()
  1027.         .deriveClass<Derived, Base>("Derived")
  1028.         .addProperty("data", &getData<int, Base>, &setData<int, Base>)
  1029.         .endClass();
  1030.  
  1031.     Derived derived(50);
  1032.     derived.Base::data = 1.23f;
  1033.     luabridge::setGlobal(L, static_cast<Base*>(&derived), "base");
  1034.     luabridge::setGlobal(L, &derived, "derived");
  1035.  
  1036.     runLua("result = base.data");
  1037.     ASSERT_TRUE(result().isNumber());
  1038.     ASSERT_EQ(1.23f, result<float>());
  1039.  
  1040.     runLua("result = derived.data");
  1041.     ASSERT_TRUE(result().isNumber());
  1042.     ASSERT_EQ(50, result<int>());
  1043.  
  1044.     runLua("base.data = -3.14");
  1045.     ASSERT_EQ(-3.14f, derived.Base::data);
  1046.     ASSERT_EQ(50, derived.data);
  1047.  
  1048.     runLua("derived.data = 7");
  1049.     ASSERT_EQ(-3.14f, derived.Base::data);
  1050.     ASSERT_EQ(7, derived.data);
  1051. }
  1052.  
  1053. TEST_F(ClassProperties, StdFunctions)
  1054. {
  1055.     using Int = Class<int, EmptyBase>;
  1056.  
  1057.     auto sharedGetterData = std::make_shared<int>();
  1058.     std::weak_ptr<int> getterData = sharedGetterData; // Check __gc meta-method
  1059.  
  1060.     auto sharedSetterData = std::make_shared<int>();
  1061.     std::weak_ptr<int> setterData = sharedGetterData; // Check __gc meta-method
  1062.  
  1063.     std::function<int(const Int*)> getter = [sharedGetterData](const Int* object) {
  1064.         return object->data;
  1065.     };
  1066.  
  1067.     std::function<void(Int*, int)> setter = [sharedSetterData](Int* object, int value) {
  1068.         object->data = value;
  1069.     };
  1070.  
  1071.     luabridge::getGlobalNamespace(L)
  1072.         .beginClass<Int>("Int")
  1073.         .addConstructor<void (*)(int)>()
  1074.         .addProperty("data", std::move(getter), std::move(setter))
  1075.         .endClass();
  1076.  
  1077.     sharedGetterData = nullptr;
  1078.     ASSERT_FALSE(getterData.expired());
  1079.  
  1080.     sharedSetterData = nullptr;
  1081.     ASSERT_FALSE(setterData.expired());
  1082.  
  1083.     runLua("result = Int (501)");
  1084.     ASSERT_EQ(501, result()["data"].cast<int>());
  1085.  
  1086.     runLua("result.data = -2");
  1087.     ASSERT_TRUE(result()["data"].isNumber());
  1088.     ASSERT_EQ(-2, result()["data"].cast<int>());
  1089.  
  1090.     runLua("result = nil");
  1091.     lua_close(L); // Force garbage collection
  1092.     L = nullptr;
  1093.  
  1094.     ASSERT_TRUE(getterData.expired());
  1095.     ASSERT_TRUE(setterData.expired());
  1096. }
  1097.  
  1098. TEST_F(ClassProperties, StdFunctions_ReadOnly)
  1099. {
  1100.     using Int = Class<int, EmptyBase>;
  1101.  
  1102.     auto sharedGetterData = std::make_shared<int>();
  1103.     std::weak_ptr<int> getterData = sharedGetterData; // Check __gc meta-method
  1104.  
  1105.     std::function<int(const Int*)> getter = [sharedGetterData](const Int* object) {
  1106.         return object->data;
  1107.     };
  1108.  
  1109.     luabridge::getGlobalNamespace(L)
  1110.         .beginClass<Int>("Int")
  1111.         .addConstructor<void (*)(int)>()
  1112.         .addProperty("data", std::move(getter))
  1113.         .endClass();
  1114.  
  1115.     sharedGetterData = nullptr;
  1116.     ASSERT_FALSE(getterData.expired());
  1117.  
  1118.     runLua("result = Int (501)");
  1119.     ASSERT_TRUE(result()["data"].isNumber());
  1120.     ASSERT_EQ(501, result()["data"].cast<int>());
  1121.  
  1122.     ASSERT_THROW(runLua("result.data = -2"), std::exception);
  1123.     ASSERT_EQ(501, result()["data"].cast<int>());
  1124.  
  1125.     runLua("result = nil");
  1126.     lua_close(L); // Force garbage collection
  1127.     L = nullptr;
  1128.  
  1129.     ASSERT_TRUE(getterData.expired());
  1130. }
  1131.  
  1132. struct ClassStaticFunctions : ClassTests
  1133. {
  1134. };
  1135.  
  1136. TEST_F(ClassStaticFunctions, Functions)
  1137. {
  1138.     using Int = Class<int, EmptyBase>;
  1139.  
  1140.     luabridge::getGlobalNamespace(L)
  1141.         .beginClass<Int>("Int")
  1142.         .addConstructor<void (*)(int)>()
  1143.         .addStaticFunction("static", &Int::staticFunction)
  1144.         .endClass();
  1145.  
  1146.     runLua("result = Int.static (Int (35))");
  1147.     ASSERT_EQ(35, result<Int>().data);
  1148. }
  1149.  
  1150. TEST_F(ClassStaticFunctions, Functions_Derived)
  1151. {
  1152.     using Base = Class<std::string, EmptyBase>;
  1153.     using Derived = Class<int, Base>;
  1154.  
  1155.     luabridge::getGlobalNamespace(L)
  1156.         .beginClass<Base>("Base")
  1157.         .addConstructor<void (*)(std::string)>()
  1158.         .addStaticFunction("static", &Base::staticFunction)
  1159.         .endClass()
  1160.         .deriveClass<Derived, Base>("Derived")
  1161.         .endClass();
  1162.  
  1163.     runLua("result = Derived.static (Base ('abc'))");
  1164.     ASSERT_EQ("abc", result<Base>().data);
  1165. }
  1166.  
  1167. TEST_F(ClassStaticFunctions, Functions_Overridden)
  1168. {
  1169.     using Base = Class<std::string, EmptyBase>;
  1170.     using Derived = Class<int, Base>;
  1171.  
  1172.     luabridge::getGlobalNamespace(L)
  1173.         .beginClass<Base>("Base")
  1174.         .addConstructor<void (*)(std::string)>()
  1175.         .addStaticFunction("staticFunction", &Base::staticFunction)
  1176.         .endClass()
  1177.         .deriveClass<Derived, Base>("Derived")
  1178.         .addConstructor<void (*)(int)>()
  1179.         .addStaticFunction("staticFunction", &Derived::staticFunction)
  1180.         .endClass();
  1181.  
  1182.     runLua("result = Base.staticFunction (Base ('abc'))");
  1183.     ASSERT_EQ("abc", result<Base>().data);
  1184.  
  1185.     runLua("result = Derived.staticFunction (Derived (123))");
  1186.     ASSERT_EQ(123, result<Derived>().data);
  1187. }
  1188.  
  1189. TEST_F(ClassStaticFunctions, StdFunctions)
  1190. {
  1191.     using Int = Class<int, EmptyBase>;
  1192.  
  1193.     luabridge::getGlobalNamespace(L)
  1194.         .beginClass<Int>("Int")
  1195.         .addConstructor<void (*)(int)>()
  1196.         .addStaticFunction("static", std::function<Int(Int)>(&Int::staticFunction))
  1197.         .endClass();
  1198.  
  1199.     runLua("result = Int.static (Int (35))");
  1200.     ASSERT_EQ(35, result<Int>().data);
  1201. }
  1202.  
  1203. struct ClassStaticProperties : ClassTests
  1204. {
  1205. };
  1206.  
  1207. TEST_F(ClassStaticProperties, FieldPointers)
  1208. {
  1209.     using Int = Class<int, EmptyBase>;
  1210.  
  1211.     luabridge::getGlobalNamespace(L)
  1212.         .beginClass<Int>("Int")
  1213.         .addStaticProperty("staticData", &Int::staticData, true)
  1214.         .endClass();
  1215.  
  1216.     Int::staticData = 10;
  1217.  
  1218.     runLua("result = Int.staticData");
  1219.     ASSERT_TRUE(result().isNumber());
  1220.     ASSERT_EQ(10, result<int>());
  1221.  
  1222.     runLua("Int.staticData = 20");
  1223.     ASSERT_EQ(20, Int::staticData);
  1224. }
  1225.  
  1226. TEST_F(ClassStaticProperties, FieldPointers_ReadOnly)
  1227. {
  1228.     using Int = Class<int, EmptyBase>;
  1229.  
  1230.     luabridge::getGlobalNamespace(L)
  1231.         .beginClass<Int>("Int")
  1232.         .addStaticProperty("staticData", &Int::staticData, false)
  1233.         .endClass();
  1234.  
  1235.     Int::staticData = 10;
  1236.  
  1237.     runLua("result = Int.staticData");
  1238.     ASSERT_TRUE(result().isNumber());
  1239.     ASSERT_EQ(10, result<int>());
  1240.  
  1241.     ASSERT_THROW(runLua("Int.staticData = 20"), std::exception);
  1242.     ASSERT_EQ(10, Int::staticData);
  1243. }
  1244.  
  1245. TEST_F(ClassStaticProperties, FieldPointers_Derived)
  1246. {
  1247.     using Base = Class<float, EmptyBase>;
  1248.     using Derived = Class<int, Base>;
  1249.  
  1250.     luabridge::getGlobalNamespace(L)
  1251.         .beginClass<Base>("Base")
  1252.         .addStaticProperty("staticData", &Base::staticData, true)
  1253.         .endClass()
  1254.         .deriveClass<Derived, Base>("Derived")
  1255.         .endClass();
  1256.  
  1257.     Base::staticData = 1.23f;
  1258.     Derived::staticData = 50;
  1259.  
  1260.     runLua("result = Derived.staticData");
  1261.     ASSERT_TRUE(result().isNumber());
  1262.     ASSERT_EQ(1.23f, result<float>());
  1263.  
  1264.     runLua("Derived.staticData = -3.14");
  1265.     ASSERT_EQ(-3.14f, Base::staticData);
  1266.     ASSERT_EQ(50, Derived::staticData);
  1267. }
  1268.  
  1269. TEST_F(ClassStaticProperties, FieldPointers_Overridden)
  1270. {
  1271.     using Base = Class<float, EmptyBase>;
  1272.     using Derived = Class<int, Base>;
  1273.  
  1274.     luabridge::getGlobalNamespace(L)
  1275.         .beginClass<Base>("Base")
  1276.         .addStaticProperty("staticData", &Base::staticData, true)
  1277.         .endClass()
  1278.         .deriveClass<Derived, Base>("Derived")
  1279.         .addStaticProperty("staticData", &Derived::staticData, true)
  1280.         .endClass();
  1281.  
  1282.     Base::staticData = 1.23f;
  1283.     Derived::staticData = 50;
  1284.  
  1285.     runLua("result = Base.staticData");
  1286.     ASSERT_TRUE(result().isNumber());
  1287.     ASSERT_EQ(1.23f, result<float>());
  1288.  
  1289.     runLua("result = Derived.staticData");
  1290.     ASSERT_TRUE(result().isNumber());
  1291.     ASSERT_EQ(50, result<int>());
  1292.  
  1293.     runLua("Base.staticData = -3.14");
  1294.     ASSERT_EQ(-3.14f, Base::staticData);
  1295.     ASSERT_EQ(50, Derived::staticData);
  1296.  
  1297.     runLua("Derived.staticData = 7");
  1298.     ASSERT_EQ(-3.14f, Base::staticData);
  1299.     ASSERT_EQ(7, Derived::staticData);
  1300. }
  1301.  
  1302. struct ClassMetaMethods : ClassTests
  1303. {
  1304. };
  1305.  
  1306. TEST_F(ClassMetaMethods, __call)
  1307. {
  1308.     typedef Class<int, EmptyBase> Int;
  1309.  
  1310.     luabridge::getGlobalNamespace(L)
  1311.         .beginClass<Int>("Int")
  1312.         .addConstructor<void (*)(int)>()
  1313.         .addFunction("__call", &Int::operator())
  1314.         .endClass();
  1315.  
  1316.     runLua("result = Int (1) (-1)");
  1317.     ASSERT_TRUE(result().isUserdata());
  1318.     ASSERT_EQ(-1, result<Int>().data);
  1319.  
  1320.     runLua("result = Int (2) (5)");
  1321.     ASSERT_TRUE(result().isUserdata());
  1322.     ASSERT_EQ(5, result<Int>().data);
  1323. }
  1324.  
  1325. TEST_F(ClassMetaMethods, __tostring)
  1326. {
  1327.     typedef Class<int, EmptyBase> Int;
  1328.     typedef Class<std::string, EmptyBase> StringClass;
  1329.  
  1330.     luabridge::getGlobalNamespace(L)
  1331.         .beginClass<Int>("Int")
  1332.         .addConstructor<void (*)(int)>()
  1333.         .addFunction("__tostring", &Int::toString)
  1334.         .endClass()
  1335.         .beginClass<StringClass>("String")
  1336.         .addConstructor<void (*)(std::string)>()
  1337.         .addFunction("__tostring", &StringClass::toString)
  1338.         .endClass();
  1339.  
  1340.     runLua("result = tostring (Int (-123))");
  1341.     ASSERT_EQ("-123", result<std::string>());
  1342.  
  1343. #if LUA_VERSION_NUM >= 502
  1344.     // Lua 5.1 string.format doesn't use __tostring
  1345.     runLua("result = string.format ('%s%s', String ('abc'), Int (-123))");
  1346.     ASSERT_EQ("abc-123", result<std::string>());
  1347. #endif
  1348. }
  1349.  
  1350. TEST_F(ClassMetaMethods, __eq)
  1351. {
  1352.     typedef Class<int, EmptyBase> Int;
  1353.  
  1354.     luabridge::getGlobalNamespace(L)
  1355.         .beginClass<Int>("Int")
  1356.         .addConstructor<void (*)(int)>()
  1357.         .addFunction("__eq", &Int::operator==)
  1358.         .endClass();
  1359.  
  1360.     runLua("result = Int (1) == Int (1)");
  1361.     ASSERT_EQ(true, result<bool>());
  1362.  
  1363.     runLua("result = Int (1) ~= Int (1)");
  1364.     ASSERT_EQ(false, result<bool>());
  1365.  
  1366.     runLua("result = Int (1) == Int (2)");
  1367.     ASSERT_EQ(false, result<bool>());
  1368.  
  1369.     runLua("result = Int (1) ~= Int (2)");
  1370.     ASSERT_EQ(true, result<bool>());
  1371. }
  1372.  
  1373. TEST_F(ClassMetaMethods, __lt)
  1374. {
  1375.     typedef Class<int, EmptyBase> Int;
  1376.  
  1377.     luabridge::getGlobalNamespace(L)
  1378.         .beginClass<Int>("Int")
  1379.         .addConstructor<void (*)(int)>()
  1380.         .addFunction("__lt", &Int::operator<)
  1381.         .endClass();
  1382.  
  1383.     runLua("result = Int (1) < Int (1)");
  1384.     ASSERT_EQ(false, result<bool>());
  1385.  
  1386.     runLua("result = Int (1) < Int (2)");
  1387.     ASSERT_EQ(true, result<bool>());
  1388.  
  1389.     runLua("result = Int (2) < Int (1)");
  1390.     ASSERT_EQ(false, result<bool>());
  1391. }
  1392.  
  1393. TEST_F(ClassMetaMethods, __le)
  1394. {
  1395.     typedef Class<int, EmptyBase> Int;
  1396.  
  1397.     luabridge::getGlobalNamespace(L)
  1398.         .beginClass<Int>("Int")
  1399.         .addConstructor<void (*)(int)>()
  1400.         .addFunction("__le", &Int::operator<=)
  1401.         .endClass();
  1402.  
  1403.     runLua("result = Int (1) <= Int (1)");
  1404.     ASSERT_EQ(true, result<bool>());
  1405.  
  1406.     runLua("result = Int (1) <= Int (2)");
  1407.     ASSERT_EQ(true, result<bool>());
  1408.  
  1409.     runLua("result = Int (2) <= Int (1)");
  1410.     ASSERT_EQ(false, result<bool>());
  1411. }
  1412.  
  1413. TEST_F(ClassMetaMethods, __add)
  1414. {
  1415.     typedef Class<int, EmptyBase> Int;
  1416.  
  1417.     luabridge::getGlobalNamespace(L)
  1418.         .beginClass<Int>("Int")
  1419.         .addConstructor<void (*)(int)>()
  1420.         .addFunction("__add", &Int::operator+)
  1421.         .endClass();
  1422.  
  1423.     runLua("result = Int (1) + Int (2)");
  1424.     ASSERT_TRUE(result().isUserdata());
  1425.     ASSERT_EQ(3, result<Int>().data);
  1426. }
  1427.  
  1428. TEST_F(ClassMetaMethods, __sub)
  1429. {
  1430.     typedef Class<int, EmptyBase> Int;
  1431.  
  1432.     luabridge::getGlobalNamespace(L)
  1433.         .beginClass<Int>("Int")
  1434.         .addConstructor<void (*)(int)>()
  1435.         .addFunction("__sub", &Int::operator-)
  1436.         .endClass();
  1437.  
  1438.     runLua("result = Int (1) - Int (2)");
  1439.     ASSERT_TRUE(result().isUserdata());
  1440.     ASSERT_EQ(-1, result<Int>().data);
  1441. }
  1442.  
  1443. TEST_F(ClassMetaMethods, __mul)
  1444. {
  1445.     typedef Class<int, EmptyBase> Int;
  1446.  
  1447.     luabridge::getGlobalNamespace(L)
  1448.         .beginClass<Int>("Int")
  1449.         .addConstructor<void (*)(int)>()
  1450.         .addFunction("__mul", &Int::operator*)
  1451.         .endClass();
  1452.  
  1453.     runLua("result = Int (-2) * Int (-5)");
  1454.     ASSERT_TRUE(result().isUserdata());
  1455.     ASSERT_EQ(10, result<Int>().data);
  1456. }
  1457.  
  1458. TEST_F(ClassMetaMethods, __div)
  1459. {
  1460.     typedef Class<int, EmptyBase> Int;
  1461.  
  1462.     luabridge::getGlobalNamespace(L)
  1463.         .beginClass<Int>("Int")
  1464.         .addConstructor<void (*)(int)>()
  1465.         .addFunction("__div", &Int::operator/)
  1466.         .endClass();
  1467.  
  1468.     runLua("result = Int (10) / Int (2)");
  1469.     ASSERT_TRUE(result().isUserdata());
  1470.     ASSERT_EQ(5, result<Int>().data);
  1471. }
  1472.  
  1473. TEST_F(ClassMetaMethods, __mod)
  1474. {
  1475.     typedef Class<int, EmptyBase> Int;
  1476.  
  1477.     luabridge::getGlobalNamespace(L)
  1478.         .beginClass<Int>("Int")
  1479.         .addConstructor<void (*)(int)>()
  1480.         .addFunction("__mod", &Int::operator%)
  1481.         .endClass();
  1482.  
  1483.     runLua("result = Int (7) % Int (2)");
  1484.     ASSERT_TRUE(result().isUserdata());
  1485.     ASSERT_EQ(1, result<Int>().data);
  1486. }
  1487.  
  1488. TEST_F(ClassMetaMethods, __pow)
  1489. {
  1490.     typedef Class<int, EmptyBase> Int;
  1491.  
  1492.     luabridge::getGlobalNamespace(L)
  1493.         .beginClass<Int>("Int")
  1494.         .addConstructor<void (*)(int)>()
  1495.         .addFunction("__pow", &Int::operator-)
  1496.         .endClass();
  1497.  
  1498.     runLua("result = Int (5) ^ Int (2)");
  1499.     ASSERT_TRUE(result().isUserdata());
  1500.     ASSERT_EQ(3, result<Int>().data);
  1501. }
  1502.  
  1503. TEST_F(ClassMetaMethods, __unm)
  1504. {
  1505.     typedef Class<int, EmptyBase> Int;
  1506.  
  1507.     luabridge::getGlobalNamespace(L)
  1508.         .beginClass<Int>("Int")
  1509.         .addConstructor<void (*)(int)>()
  1510.         .addFunction("__unm", &Int::negate)
  1511.         .endClass();
  1512.  
  1513.     runLua("result = -Int (-3)");
  1514.     ASSERT_TRUE(result().isUserdata());
  1515.     ASSERT_EQ(3, result<Int>().data);
  1516. }
  1517.  
  1518. TEST_F(ClassMetaMethods, __concat)
  1519. {
  1520.     typedef Class<std::string, EmptyBase> String;
  1521.  
  1522.     luabridge::getGlobalNamespace(L)
  1523.         .beginClass<String>("String")
  1524.         .addConstructor<void (*)(std::string)>()
  1525.         .addFunction("__concat", &String::operator+)
  1526.         .endClass();
  1527.  
  1528.     ASSERT_THROW(runLua("result = String ('a') + String ('b')"), std::exception);
  1529.  
  1530.     runLua("result = String ('ab') .. String ('cd')");
  1531.     ASSERT_TRUE(result().isUserdata());
  1532.     ASSERT_EQ("abcd", result<String>().data);
  1533. }
  1534.  
  1535. TEST_F(ClassMetaMethods, __len)
  1536. {
  1537.     typedef Class<int, EmptyBase> Int;
  1538.  
  1539.     luabridge::getGlobalNamespace(L)
  1540.         .beginClass<Int>("Int")
  1541.         .addConstructor<void (*)(int)>()
  1542.         .addFunction("__len", &Int::len)
  1543.         .endClass();
  1544.  
  1545.     runLua("result = #Int (1)");
  1546.     ASSERT_TRUE(result().isNumber());
  1547.     ASSERT_EQ(1, result<int>());
  1548.  
  1549.     runLua("result = #Int (5)");
  1550.     ASSERT_TRUE(result().isNumber());
  1551.     ASSERT_EQ(5, result<int>());
  1552. }
  1553.  
  1554. namespace {
  1555.  
  1556. struct Table
  1557. {
  1558.     int index(const std::string& key) { return map.at(key); }
  1559.  
  1560.     void newIndex(const std::string& key, int value) { map.emplace(key, value); }
  1561.  
  1562.     std::map<std::string, int> map;
  1563. };
  1564.  
  1565. } // namespace
  1566.  
  1567. TEST_F(ClassMetaMethods, __index)
  1568. {
  1569.     luabridge::getGlobalNamespace(L)
  1570.         .beginClass<Table>("Table")
  1571.         .addFunction("__index", &Table::index)
  1572.         .endClass();
  1573.  
  1574.     Table t{{{"a", 1}, {"b", 2}}};
  1575.  
  1576.     luabridge::setGlobal(L, &t, "t");
  1577.  
  1578.     runLua("result = t.a");
  1579.     ASSERT_TRUE(result().isNumber());
  1580.     ASSERT_EQ(1, result<int>());
  1581.  
  1582.     runLua("result = t.b");
  1583.     ASSERT_TRUE(result().isNumber());
  1584.     ASSERT_EQ(2, result<int>());
  1585.  
  1586.     ASSERT_THROW(runLua("result = t.c"), std::exception); // at ("c") throws
  1587. }
  1588.  
  1589. TEST_F(ClassMetaMethods, __newindex)
  1590. {
  1591.     typedef Class<int, EmptyBase> Int;
  1592.  
  1593.     luabridge::getGlobalNamespace(L)
  1594.         .beginClass<Table>("Table")
  1595.         .addFunction("__newindex", &Table::newIndex)
  1596.         .endClass();
  1597.  
  1598.     Table t;
  1599.  
  1600.     luabridge::setGlobal(L, &t, "t");
  1601.  
  1602.     runLua("t.a = 1\n"
  1603.            "t ['b'] = 2");
  1604.  
  1605.     ASSERT_EQ((std::map<std::string, int>{{"a", 1}, {"b", 2}}), t.map);
  1606. }
  1607.  
  1608. TEST_F(ClassMetaMethods, __gcForbidden)
  1609. {
  1610.     typedef Class<int, EmptyBase> Int;
  1611.  
  1612.     ASSERT_THROW(luabridge::getGlobalNamespace(L)
  1613.                      .beginClass<Int>("Int")
  1614.                      .addFunction("__gc", &Int::method)
  1615.                      .endClass(),
  1616.                  std::exception);
  1617. }
  1618.  
  1619. TEST_F(ClassTests, EnclosedClassProperties)
  1620. {
  1621.     typedef Class<int, EmptyBase> Inner;
  1622.     typedef Class<Inner, EmptyBase> Outer;
  1623.  
  1624.     luabridge::getGlobalNamespace(L)
  1625.         .beginClass<Inner>("Inner")
  1626.         .addProperty("data", &Inner::data)
  1627.         .endClass()
  1628.         .beginClass<Outer>("Outer")
  1629.         .addProperty("data", &Outer::data)
  1630.         .endClass();
  1631.  
  1632.     Outer outer(Inner(0));
  1633.     luabridge::setGlobal(L, &outer, "outer");
  1634.  
  1635.     outer.data.data = 1;
  1636.     runLua("outer.data.data = 10");
  1637.     ASSERT_EQ(10, outer.data.data);
  1638.  
  1639.     runLua("result = outer.data.data");
  1640.     ASSERT_EQ(10, result<int>());
  1641. }
  1642.  
  1643. // namespace {
  1644.  
  1645. struct InnerClass
  1646. {
  1647.     ~InnerClass() { ++destructorCallCount; }
  1648.  
  1649.     static unsigned destructorCallCount;
  1650. };
  1651.  
  1652. unsigned InnerClass::destructorCallCount;
  1653.  
  1654. struct OuterClass
  1655. {
  1656.     OuterClass() { throw std::runtime_error("Exception"); }
  1657.  
  1658.     ~OuterClass() { ++destructorCallCount; }
  1659.  
  1660.     static unsigned destructorCallCount;
  1661.     InnerClass inner;
  1662. };
  1663.  
  1664. unsigned OuterClass::destructorCallCount;
  1665.  
  1666. //} // namespace
  1667.  
  1668. TEST_F(ClassTests, DestructorIsNotCalledIfConstructorThrows)
  1669. {
  1670.     luabridge::getGlobalNamespace(L)
  1671.         .beginClass<OuterClass>("OuterClass")
  1672.         .addConstructor<void (*)()>()
  1673.         .endClass();
  1674.  
  1675.     InnerClass::destructorCallCount = 0;
  1676.     OuterClass::destructorCallCount = 0;
  1677.     ASSERT_THROW(runLua("result = OuterClass ()"), std::exception);
  1678.     ASSERT_EQ(1, InnerClass::destructorCallCount);
  1679.  
  1680.     lua_close(L);
  1681.     L = nullptr;
  1682.     ASSERT_EQ(1, InnerClass::destructorCallCount);
  1683.     ASSERT_EQ(0, OuterClass::destructorCallCount);
  1684. }
  1685.  
  1686. TEST_F(ClassTests, DestructorIsCalledOnce)
  1687. {
  1688.     luabridge::getGlobalNamespace(L)
  1689.         .beginClass<InnerClass>("InnerClass")
  1690.         .addConstructor<void (*)()>()
  1691.         .endClass();
  1692.  
  1693.     InnerClass::destructorCallCount = 0;
  1694.     runLua("result = InnerClass ()");
  1695.  
  1696.     lua_close(L);
  1697.     L = nullptr;
  1698.     ASSERT_EQ(1, InnerClass::destructorCallCount);
  1699. }
  1700.