1 #define SOL_CHECK_ARGUMENTS 2 3 #include <sol.hpp> 4 #include <catch.hpp> 5 6 #include <iostream> 7 #include <list> 8 #include <memory> 9 #include <mutex> 10 11 TEST_CASE("usertype/simple-usertypes", "Ensure that simple usertypes properly work here") { 12 struct marker { 13 bool value = false; 14 }; 15 struct bark { 16 int var = 50; 17 marker mark; 18 funbark19 void fun() { 20 var = 51; 21 } 22 getbark23 int get() const { 24 return var; 25 } 26 setbark27 int set(int x) { 28 var = x; 29 return var; 30 } 31 specialbark32 std::string special() const { 33 return mark.value ? "woof" : "pantpant"; 34 } 35 the_markerbark36 const marker& the_marker() const { 37 return mark; 38 } 39 }; 40 41 sol::state lua; 42 lua.new_simple_usertype<bark>("bark", 43 "fun", &bark::fun, 44 "get", &bark::get, 45 "var", sol::as_function( &bark::var ), 46 "the_marker", sol::as_function(&bark::the_marker), 47 "x", sol::overload(&bark::get), 48 "y", sol::overload(&bark::set), 49 "z", sol::overload(&bark::get, &bark::set) 50 ); 51 52 lua.script("b = bark.new()"); 53 bark& b = lua["b"]; 54 55 lua.script("b:fun()"); 56 int var = b.var; 57 REQUIRE(var == 51); 58 59 lua.script("b:var(20)"); 60 lua.script("v = b:var()"); 61 int v = lua["v"]; 62 REQUIRE(v == 20); 63 REQUIRE(b.var == 20); 64 65 lua.script("m = b:the_marker()"); 66 marker& m = lua["m"]; 67 REQUIRE_FALSE(b.mark.value); 68 REQUIRE_FALSE(m.value); 69 m.value = true; 70 REQUIRE(&b.mark == &m); 71 REQUIRE(b.mark.value); 72 73 sol::table barktable = lua["bark"]; 74 barktable["special"] = &bark::special; 75 76 lua.script("s = b:special()"); 77 std::string s = lua["s"]; 78 REQUIRE(s == "woof"); 79 80 lua.script("b:y(24)"); 81 lua.script("x = b:x()"); 82 int x = lua["x"]; 83 REQUIRE(x == 24); 84 85 lua.script("z = b:z(b:z() + 5)"); 86 int z = lua["z"]; 87 REQUIRE(z == 29); 88 } 89 90 TEST_CASE("usertype/simple-usertypes-constructors", "Ensure that calls with specific arguments work") { 91 struct marker { 92 bool value = false; 93 }; 94 struct bark { 95 int var = 50; 96 marker mark; 97 barkbark98 bark() {} barkbark99 bark(int v) : var(v) {} 100 funbark101 void fun() { 102 var = 51; 103 } 104 getbark105 int get() const { 106 return var; 107 } 108 setbark109 int set(int x) { 110 var = x; 111 return var; 112 } 113 specialbark114 std::string special() const { 115 return mark.value ? "woof" : "pantpant"; 116 } 117 the_markerbark118 const marker& the_marker() const { 119 return mark; 120 } 121 }; 122 123 sol::state lua; 124 lua.new_simple_usertype<bark>("bark", 125 sol::constructors<sol::types<>, sol::types<int>>(), 126 "fun", sol::protect( &bark::fun ), 127 "get", &bark::get, 128 "var", sol::as_function( &bark::var ), 129 "the_marker", &bark::the_marker, 130 "x", sol::overload(&bark::get), 131 "y", sol::overload(&bark::set), 132 "z", sol::overload(&bark::get, &bark::set) 133 ); 134 135 lua.script("bx = bark.new(760)"); 136 bark& bx = lua["bx"]; 137 REQUIRE(bx.var == 760); 138 139 lua.script("b = bark.new()"); 140 bark& b = lua["b"]; 141 142 lua.script("b:fun()"); 143 int var = b.var; 144 REQUIRE(var == 51); 145 146 lua.script("b:var(20)"); 147 lua.script("v = b:var()"); 148 int v = lua["v"]; 149 REQUIRE(v == 20); 150 151 lua.script("m = b:the_marker()"); 152 marker& m = lua["m"]; 153 REQUIRE_FALSE(b.mark.value); 154 REQUIRE_FALSE(m.value); 155 m.value = true; 156 REQUIRE(&b.mark == &m); 157 REQUIRE(b.mark.value); 158 159 sol::table barktable = lua["bark"]; 160 barktable["special"] = &bark::special; 161 162 lua.script("s = b:special()"); 163 std::string s = lua["s"]; 164 REQUIRE(s == "woof"); 165 166 lua.script("b:y(24)"); 167 lua.script("x = b:x()"); 168 int x = lua["x"]; 169 REQUIRE(x == 24); 170 171 lua.script("z = b:z(b:z() + 5)"); 172 int z = lua["z"]; 173 REQUIRE(z == 29); 174 } 175 176 TEST_CASE("usertype/simple-shared-ptr-regression", "simple usertype metatables should not screw over unique usertype metatables") { 177 static int created = 0; 178 static int destroyed = 0; 179 struct test { testtest180 test() { 181 ++created; 182 } 183 ~testtest184 ~test() { 185 ++destroyed; 186 } 187 }; 188 { 189 std::list<std::shared_ptr<test>> tests; 190 sol::state lua; 191 lua.open_libraries(); 192 193 lua.new_simple_usertype<test>("test", __anonfb40a62e0102() 194 "create", [&]() -> std::shared_ptr<test> { 195 tests.push_back(std::make_shared<test>()); 196 return tests.back(); 197 } 198 ); 199 REQUIRE(created == 0); 200 REQUIRE(destroyed == 0); 201 lua.script("x = test.create()"); 202 REQUIRE(created == 1); 203 REQUIRE(destroyed == 0); 204 REQUIRE_FALSE(tests.empty()); 205 std::shared_ptr<test>& x = lua["x"]; 206 std::size_t xuse = x.use_count(); 207 std::size_t tuse = tests.back().use_count(); 208 REQUIRE(xuse == tuse); 209 } 210 REQUIRE(created == 1); 211 REQUIRE(destroyed == 1); 212 } 213 214 TEST_CASE("usertype/simple-vars", "simple usertype vars can bind various values (no ref)") { 215 int muh_variable = 10; 216 int through_variable = 25; 217 218 sol::state lua; 219 lua.open_libraries(); 220 221 struct test {}; 222 lua.new_simple_usertype<test>("test", 223 "straight", sol::var(2), 224 "global", sol::var(muh_variable), 225 "global2", sol::var(through_variable), 226 "global3", sol::var(std::ref(through_variable)) 227 ); 228 229 through_variable = 20; 230 231 lua.script(R"( 232 print(test.straight) 233 s = test.straight 234 print(test.global) 235 g = test.global 236 print(test.global2) 237 g2 = test.global2 238 print(test.global3) 239 g3 = test.global3 240 )"); 241 242 int s = lua["s"]; 243 int g = lua["g"]; 244 int g2 = lua["g2"]; 245 int g3 = lua["g3"]; 246 REQUIRE(s == 2); 247 REQUIRE(g == 10); 248 REQUIRE(g2 == 25); 249 REQUIRE(g3 == 20); 250 } 251 252 TEST_CASE("usertypes/simple-variable-control", "test to see if usertypes respond to inheritance and variable controls") { 253 class A { 254 public: a()255 virtual void a() { throw std::runtime_error("entered base pure virtual implementation"); }; 256 }; 257 258 class B : public A { 259 public: a()260 virtual void a() override { } 261 }; 262 263 class sA { 264 public: a()265 virtual void a() { throw std::runtime_error("entered base pure virtual implementation"); }; 266 }; 267 268 class sB : public sA { 269 public: a()270 virtual void a() override { } 271 }; 272 273 struct sV { 274 int a = 10; 275 int b = 20; 276 get_bsV277 int get_b() const { 278 return b + 2; 279 } 280 set_bsV281 void set_b(int value) { 282 b = value; 283 } 284 }; 285 286 struct sW : sV {}; 287 288 sol::state lua; 289 lua.open_libraries(); 290 291 lua.new_usertype<A>("A", "a", &A::a); 292 lua.new_usertype<B>("B", sol::base_classes, sol::bases<A>()); 293 lua.new_simple_usertype<sA>("sA", "a", &sA::a); 294 lua.new_simple_usertype<sB>("sB", sol::base_classes, sol::bases<sA>()); 295 lua.new_simple_usertype<sV>("sV", "a", &sV::a, "b", &sV::b, "pb", sol::property(&sV::get_b, &sV::set_b)); 296 lua.new_simple_usertype<sW>("sW", sol::base_classes, sol::bases<sV>()); 297 298 B b; 299 lua.set("b", &b); 300 lua.script("b:a()"); 301 302 sB sb; 303 lua.set("sb", &sb); 304 lua.script("sb:a()"); 305 306 sV sv; 307 lua.set("sv", &sv); 308 lua.script("print(sv.b)assert(sv.b == 20)"); 309 310 sW sw; 311 lua.set("sw", &sw); 312 lua.script("print(sw.a)assert(sw.a == 10)"); 313 lua.script("print(sw.b)assert(sw.b == 20)"); 314 lua.script("print(sw.pb)assert(sw.pb == 22)"); 315 lua.script("sw.a = 11"); 316 lua.script("sw.b = 21"); 317 lua.script("print(sw.a)assert(sw.a == 11)"); 318 lua.script("print(sw.b)assert(sw.b == 21)"); 319 lua.script("print(sw.pb)assert(sw.pb == 23)"); 320 lua.script("sw.pb = 25"); 321 lua.script("print(sw.b)assert(sw.b == 25)"); 322 lua.script("print(sw.pb)assert(sw.pb == 27)"); 323 } 324 325 TEST_CASE("usertype/simple-factory-constructor-overload-usage", "simple usertypes should probably invoke types") { 326 class A { 327 public: a()328 virtual void a() { throw std::runtime_error("entered base pure virtual implementation"); }; 329 }; 330 331 class B : public A { 332 public: 333 int bvar = 24; a()334 virtual void a() override { } f()335 void f() {} 336 }; 337 338 sol::state lua; 339 lua.open_libraries(); 340 sol::constructors<sol::types<>, sol::types<const B&>> c; 341 lua.new_simple_usertype<B>("B", 342 sol::call_constructor, c, __anonfb40a62e0202() 343 "new", sol::factories([]() { return B(); }), __anonfb40a62e0402(B& mem, int v) 344 "new2", sol::initializers([](B& mem) { new(&mem)B(); }, [](B& mem, int v) { new(&mem)B(); mem.bvar = v; }), 345 "f", sol::as_function(&B::bvar), __anonfb40a62e0602(B&, int v) 346 "g", sol::overload([](B&) { return 2; }, [](B&, int v) { return v; }) 347 ); 348 349 lua.script("b = B()"); 350 lua.script("b2 = B.new()"); 351 lua.script("b3 = B.new2()"); 352 lua.script("b4 = B.new2(11)"); 353 354 lua.script("x = b:f()"); 355 lua.script("x2 = b2:f()"); 356 lua.script("x3 = b3:f()"); 357 lua.script("x4 = b4:f()"); 358 int x = lua["x"]; 359 int x2 = lua["x2"]; 360 int x3 = lua["x3"]; 361 int x4 = lua["x4"]; 362 REQUIRE(x == 24); 363 REQUIRE(x2 == 24); 364 REQUIRE(x3 == 24); 365 REQUIRE(x4 == 11); 366 367 lua.script("y = b:g()"); 368 lua.script("y2 = b2:g(3)"); 369 lua.script("y3 = b3:g()"); 370 lua.script("y4 = b4:g(3)"); 371 int y = lua["y"]; 372 int y2 = lua["y2"]; 373 int y3 = lua["y3"]; 374 int y4 = lua["y4"]; 375 REQUIRE(y == 2); 376 REQUIRE(y2 == 3); 377 REQUIRE(y3 == 2); 378 REQUIRE(y4 == 3); 379 } 380 381 TEST_CASE("usertype/simple-runtime-append", "allow extra functions to be appended at runtime directly to the metatable itself") { 382 class A { 383 }; 384 385 class B : public A { 386 }; 387 388 sol::state lua; 389 lua.new_simple_usertype<A>("A"); 390 lua.new_simple_usertype<B>("B", sol::base_classes, sol::bases<A>()); 391 lua.set("b", std::make_unique<B>()); __anonfb40a62e0702() 392 lua["A"]["method"] = []() { return 200; }; __anonfb40a62e0802(B&) 393 lua["B"]["method2"] = [](B&) { return 100; }; 394 lua.script("x = b.method()"); 395 lua.script("y = b:method()"); 396 397 int x = lua["x"]; 398 int y = lua["y"]; 399 REQUIRE(x == 200); 400 REQUIRE(y == 200); 401 402 lua.script("z = b.method2(b)"); 403 lua.script("w = b:method2()"); 404 int z = lua["z"]; 405 int w = lua["w"]; 406 REQUIRE(z == 100); 407 REQUIRE(w == 100); 408 } 409 410 TEST_CASE("usertype/simple-destruction-test", "make sure usertypes are properly destructed and don't double-delete memory or segfault") { 411 sol::state lua; 412 413 class CrashClass { 414 public: CrashClass()415 CrashClass() { 416 } 417 ~CrashClass()418 ~CrashClass() { 419 a = 10; // This will cause a crash. 420 } 421 422 private: 423 int a; 424 }; 425 426 lua.new_simple_usertype<CrashClass>("CrashClass", 427 sol::call_constructor, sol::constructors<sol::types<>>() 428 ); 429 430 lua.script(R"( 431 function testCrash() 432 local x = CrashClass() 433 end 434 )"); 435 436 for (int i = 0; i < 1000; ++i) { 437 lua["testCrash"](); 438 } 439 } 440 441 TEST_CASE("usertype/simple-table-append", "Ensure that appending to the meta table also affects the internal function table for pointers as well") { 442 struct A { funcA443 int func() { 444 return 5000; 445 } 446 }; 447 448 sol::state lua; 449 lua.open_libraries(); 450 451 lua.new_simple_usertype<A>("A"); 452 sol::table table = lua["A"]; 453 table["func"] = &A::func; 454 A a; 455 lua.set("a", &a); 456 lua.set("pa", &a); 457 lua.set("ua", std::make_unique<A>()); 458 REQUIRE_NOTHROW( 459 lua.script("assert(a:func() == 5000)"); 460 lua.script("assert(pa:func() == 5000)"); 461 lua.script("assert(ua:func() == 5000)"); 462 ); 463 } 464