user_type.cpp (4620B)
1 #include "libshit/lua/user_type.hpp" 2 3 #include "libshit/doctest.hpp" 4 #include "libshit/lua/dynamic_object.hpp" 5 #include "libshit/meta.hpp" 6 #include "libshit/shared_ptr.hpp" 7 8 namespace Libshit::Lua::Test 9 { 10 TEST_SUITE_BEGIN("Libshit::Lua::UserType"); 11 static int global; 12 13 namespace 14 { 15 struct Smart final : public SmartObject 16 { 17 int x = 0; 18 19 LIBSHIT_LUA_CLASS; 20 }; 21 22 struct Foo final : public RefCounted, public DynamicObject 23 { 24 int local_var = 0; 25 LIBSHIT_LUAGEN(get: "::Libshit::Lua::GetRefCountedOwnedMember") 26 Smart smart; 27 void DoIt(int x) { local_var = x; } 28 29 Foo() = default; // no ctor generated otherwise.. (bug?) 30 ~Foo() noexcept override { global += 13; } 31 32 LIBSHIT_DYNAMIC_OBJECT; 33 }; 34 35 namespace Bar::Baz 36 { 37 struct Asdfgh final : public DynamicObject 38 { 39 Asdfgh() = default; 40 LIBSHIT_DYNAMIC_OBJECT; 41 }; 42 } 43 44 struct Baz : public DynamicObject 45 { 46 Baz() = default; 47 void SetGlobal(int val) { global = val; } 48 int GetRandom() { return 4; } 49 50 LIBSHIT_DYNAMIC_OBJECT; 51 }; 52 } 53 54 TEST_CASE("shared check memory") 55 { 56 { 57 State vm; 58 59 global = 0; 60 const char* str; 61 SUBCASE("normal") str = "local x = libshit.lua.test.foo.new()"; 62 SUBCASE("short-cut") str = "local x = libshit.lua.test.foo()"; 63 SUBCASE("explicit call") str = "local x = libshit.lua.test.foo():__gc()"; 64 65 vm.DoString(str); 66 } 67 CHECK(global == 13); 68 } 69 70 TEST_CASE("resurrect shared object") 71 { 72 global = 0; 73 74 { 75 State vm; 76 vm.TranslateException([&]() 77 { 78 auto ptr = MakeSmart<Foo>(); 79 vm.Push(ptr); 80 lua_setglobal(vm, "fooobj"); 81 82 vm.DoString("fooobj:__gc() assert(getmetatable(fooobj) == nil)"); 83 REQUIRE(global == 0); 84 85 vm.Push(ptr); 86 lua_setglobal(vm, "fooobj"); 87 vm.DoString("fooobj:do_it(123)"); 88 CHECK(global == 0); 89 CHECK(ptr->local_var == 123); 90 }); 91 } 92 CHECK(global == 13); 93 } 94 95 TEST_CASE("member function without helpers") 96 { 97 State vm; 98 99 vm.DoString("local x = libshit.lua.test.foo() x:do_it(77) return x"); 100 CHECK(vm.TranslateException([&]() { return vm.Get<Foo>().local_var; }) == 77); 101 } 102 103 TEST_CASE("member function with helpers") 104 { 105 State vm; 106 107 const char* str; 108 int val; 109 SUBCASE("normal call") 110 { str = "libshit.lua.test.baz():set_global(42)"; val = 42; } 111 SUBCASE("sugar") 112 { str = "libshit.lua.test.baz().global = 43"; val = 43; } 113 SUBCASE("read") 114 { str = "local x = libshit.lua.test.baz() x.global = x.random"; val = 4; } 115 116 vm.DoString(str); 117 CHECK(global == val); 118 } 119 120 TEST_CASE("field access") 121 { 122 State vm; 123 auto ptr = MakeSmart<Foo>(); 124 vm.TranslateException([&]() 125 { 126 vm.Push(ptr); 127 lua_setglobal(vm, "foo"); 128 ptr->local_var = 13; 129 }); 130 131 SUBCASE("get") 132 { 133 const char* str; 134 SUBCASE("plain") { str = "return foo:get_local_var()"; } 135 SUBCASE("sugar") { str = "return foo.local_var"; } 136 vm.DoString(str); 137 CHECK(vm.Get<int>() == 13); 138 } 139 140 SUBCASE("set") 141 { 142 const char* str; 143 SUBCASE("plain") { str = "foo:set_local_var(42)"; } 144 SUBCASE("sugar") { str = "foo.local_var = 42"; } 145 vm.DoString(str); 146 CHECK(ptr->local_var == 42); 147 } 148 } 149 150 TEST_CASE("invalid field access yields nil") 151 { 152 State vm; 153 vm.DoString("return libshit.lua.test.foo().bar"); 154 CHECK(lua_isnil(vm, -1)); 155 } 156 157 TEST_CASE("dotted type name") 158 { 159 State vm; 160 vm.DoString("local x = libshit.lua.test.bar.baz.asdfgh()"); 161 } 162 163 TEST_CASE("aliased objects") 164 { 165 State vm; 166 vm.DoString(R"( 167 local f = libshit.lua.test.foo() 168 assert(f ~= f.smart and f.smart == f.smart) 169 f.smart.x = 7 170 assert(f.smart.x == 7) 171 )"); 172 } 173 174 namespace 175 { 176 struct A : public DynamicObject 177 { 178 int x = 0; 179 180 LIBSHIT_DYNAMIC_OBJECT; 181 }; 182 183 struct B : public DynamicObject 184 { 185 int y = 1; 186 187 LIBSHIT_DYNAMIC_OBJECT; 188 }; 189 190 struct Multi : public A, public B 191 { 192 Multi() = default; 193 SharedPtr<B> ptr; 194 195 LIBSHIT_DYNAMIC_OBJECT; 196 }; 197 198 static DynamicObject& GetDynamicObject(Multi& m) { return static_cast<A&>(m); } 199 } 200 201 TEST_CASE("multiple inheritance") 202 { 203 State vm; 204 vm.DoString(R"( 205 local m = libshit.lua.test.multi() 206 m.ptr = libshit.lua.test.multi() 207 m.y = 7 208 m.ptr.x = 5 209 m.ptr.y = 13 210 assert(m.x == 0, "m.x") 211 assert(m.y == 7, "m.y") 212 assert(m.ptr.x == 5, "m.ptr.x") 213 assert(m.ptr.y == 13, "m.ptr.y") 214 )"); 215 } 216 217 TEST_SUITE_END(); 218 } 219 220 #include "user_type.binding.hpp"