1 // sol3
2
3 // The MIT License (MIT)
4
5 // Copyright (c) 2013-2021 Rapptz, ThePhD and contributors
6
7 // Permission is hereby granted, free of charge, to any person obtaining a copy of
8 // this software and associated documentation files (the "Software"), to deal in
9 // the Software without restriction, including without limitation the rights to
10 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 // the Software, and to permit persons to whom the Software is furnished to do so,
12 // subject to the following conditions:
13
14 // The above copyright notice and this permission notice shall be included in all
15 // copies or substantial portions of the Software.
16
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 // we have a test for weirdly aligned wrappers
25 // do not make lots of noise about it
26 #ifdef _MSC_VER
27 #pragma warning(disable : 4324)
28 #endif
29
30 #include "sol_test.hpp"
31
32 #include "common_classes.hpp"
33
34 #include <catch2/catch.hpp>
35
something_func_true()36 bool something_func_true() {
37 return true;
38 }
39
40 struct ext_getset {
41
42 int bark = 24;
43 const int meow = 56;
44
45 ext_getset() = default;
ext_getsetext_getset46 ext_getset(int v) : bark(v) {
47 }
48 ext_getset(ext_getset&&) = default;
49 ext_getset(const ext_getset&) = delete;
50 ext_getset& operator=(ext_getset&&) = delete;
51 ext_getset& operator=(const ext_getset&) = delete;
~ext_getsetext_getset52 ~ext_getset() {
53 }
54
xext_getset55 std::string x() {
56 return "bark bark bark";
57 }
58
x2ext_getset59 int x2(std::string x) {
60 return static_cast<int>(x.length());
61 }
62
setext_getset63 void set(sol::variadic_args, sol::this_state, int x) {
64 bark = x;
65 }
66
getext_getset67 int get(sol::this_state, sol::variadic_args) {
68 return bark;
69 }
70
s_setext_getset71 static void s_set(int) {
72 }
73
s_getext_getset74 static int s_get(int x) {
75 return x + 20;
76 }
77 };
78
79 template <typename T>
des(T & e)80 void des(T& e) {
81 e.~T();
82 }
83
84 template <typename SelfType>
85 struct alignas(16) weird_aligned_wrapper {
86 template <typename F, std::enable_if_t<!std::is_same_v<weird_aligned_wrapper, F>, std::nullptr_t> = nullptr>
weird_aligned_wrapperweird_aligned_wrapper87 weird_aligned_wrapper(F&& f) : lambda(std::forward<F>(f)) {
88 }
operator ()weird_aligned_wrapper89 void operator()(SelfType& self, sol::object param) const {
90 lambda(self, param.as<float>());
91 }
92 std::function<void(SelfType&, float)> lambda;
93 };
94
95 TEST_CASE("usertype/properties", "Check if member properties/variables work") {
96 struct bark {
97 int var = 50;
98 int var2 = 25;
99
get_var2bark100 int get_var2() const {
101 return var2;
102 }
103
get_var3bark104 int get_var3() {
105 return var2;
106 }
107
set_var2bark108 void set_var2(int x) {
109 var2 = x;
110 }
111 };
112
113 sol::state lua;
114 sol::stack_guard luasg(lua);
115 lua.open_libraries(sol::lib::base);
116
117 lua.new_usertype<bark>("bark",
118 "var",
119 &bark::var,
120 "var2",
121 sol::readonly(&bark::var2),
122 "a",
123 sol::property(&bark::get_var2, &bark::set_var2),
124 "b",
125 sol::property(&bark::get_var2),
126 "c",
127 sol::property(&bark::get_var3),
128 "d",
129 sol::property(&bark::set_var2));
130
131 bark b;
132 lua.set("b", &b);
133
134 lua.safe_script("b.a = 59");
135 lua.safe_script("var2_0 = b.a");
136 lua.safe_script("var2_1 = b.b");
137 lua.safe_script("b.d = 1568");
138 lua.safe_script("var2_2 = b.c");
139
140 int var2_0 = lua["var2_0"];
141 int var2_1 = lua["var2_1"];
142 int var2_2 = lua["var2_2"];
143 REQUIRE(var2_0 == 59);
144 REQUIRE(var2_1 == 59);
145 REQUIRE(var2_2 == 1568);
146
147 {
148 auto result = lua.safe_script("b.var2 = 24", sol::script_pass_on_error);
149 REQUIRE_FALSE(result.valid());
150 }
151 {
152 auto result = lua.safe_script("r = b.d", sol::script_pass_on_error);
153 REQUIRE_FALSE(result.valid());
154 }
155 {
156 auto result = lua.safe_script("r = b.d", sol::script_pass_on_error);
157 REQUIRE_FALSE(result.valid());
158 }
159 {
160 auto result = lua.safe_script("b.b = 25", sol::script_pass_on_error);
161 REQUIRE_FALSE(result.valid());
162 }
163 {
164 auto result = lua.safe_script("b.c = 11", sol::script_pass_on_error);
165 REQUIRE_FALSE(result.valid());
166 }
167 }
168
169 TEST_CASE("usertype/copyability", "make sure user can write to a class variable even if the class itself isn't copy-safe") {
170 struct NoCopy {
getNoCopy171 int get() const {
172 return _you_can_copy_me;
173 }
setNoCopy174 void set(int val) {
175 _you_can_copy_me = val;
176 }
177
178 int _you_can_copy_me;
179 non_copyable _haha_you_cant_copy_me;
180 };
181
182 sol::state lua;
183 sol::stack_guard luasg(lua);
184
185 lua.new_usertype<NoCopy>("NoCopy", "val", sol::property(&NoCopy::get, &NoCopy::set));
186
187 REQUIRE_NOTHROW(lua.safe_script(R"__(
188 nocopy = NoCopy.new()
189 nocopy.val = 5
190 )__"));
191 }
192
193 TEST_CASE("usertype/protect", "users should be allowed to manually protect a function") {
194 struct protect_me {
genprotect_me195 int gen(int x) {
196 return x;
197 }
198 };
199
200 sol::state lua;
201 lua.open_libraries(sol::lib::base);
202 lua.new_usertype<protect_me>("protect_me", "gen", sol::protect(&protect_me::gen));
203
204 REQUIRE_NOTHROW(lua.safe_script(R"__(
205 pm = protect_me.new()
206 value = pcall(pm.gen,pm)
207 )__"));
208 bool value = lua["value"];
209 REQUIRE_FALSE(value);
210 }
211
212 TEST_CASE("usertype/static-properties", "allow for static functions to get and set things as a property") {
213 static int b = 50;
214 struct test_t {
s_functest_t215 static double s_func() {
216 return b + 0.5;
217 }
218
g_functest_t219 static void g_func(int v) {
220 b = v;
221 }
222
functest_t223 std::size_t func() {
224 return 24;
225 }
226 };
227 test_t manager;
228
229 sol::state lua;
230 sol::stack_guard luasg(lua);
231
232 lua.new_usertype<test_t>(
233 "test", "f", std::function<std::size_t()>(std::bind(std::mem_fn(&test_t::func), &manager)), "g", sol::property(&test_t::s_func, &test_t::g_func));
234
235 lua.safe_script("v1 = test.f()");
236 lua.safe_script("v2 = test.g");
237 lua.safe_script("test.g = 60");
238 lua.safe_script("v2a = test.g");
239 int v1 = lua["v1"];
240 REQUIRE(v1 == 24);
241 double v2 = lua["v2"];
242 REQUIRE(v2 == 50.5);
243 double v2a = lua["v2a"];
244 REQUIRE(v2a == 60.5);
245 }
246
247 TEST_CASE("usertype/var with string literals", "String literals are the bane of my existence and one day C++ will make them not be fucking arrays") {
248 struct blah { };
249
250 sol::state lua;
251 sol::usertype<blah> x = lua.new_usertype<blah>("blah");
252 x["__className"] = sol::var("Entity");
253
254 std::string cxx_name = x["__className"];
255 std::string lua_name = lua.script("return blah.__className");
256 REQUIRE(cxx_name == lua_name);
257 REQUIRE(cxx_name == "Entity");
258 REQUIRE(lua_name == "Entity");
259 }
260
261 TEST_CASE("usertype/var-and-property", "make sure const vars are readonly and properties can handle lambdas") {
262 const static int arf = 20;
263
264 struct test {
265 int value = 10;
266 };
267
268 sol::state lua;
269 sol::stack_guard luasg(lua);
270 lua.open_libraries();
271
272 lua.new_usertype<test>(
__anon9334b35e0202(test& t, int x) 273 "test", "prop", sol::property([](test& t) { return t.value; }, [](test& t, int x) { t.value = x; }), "global", sol::var(std::ref(arf)));
274
275 lua.safe_script(R"(
276 t = test.new()
277 print(t.prop)
278 t.prop = 50
279 print(t.prop)
280 )");
281
282 test& t = lua["t"];
283 REQUIRE(t.value == 50);
284
285 lua.safe_script(R"(
286 t = test.new()
287 print(t.global)
288 )");
289 {
290 auto result = lua.safe_script("t.global = 20", sol::script_pass_on_error);
291 REQUIRE_FALSE(result.valid());
292 }
293 lua.safe_script("print(t.global)");
294 }
295
296 TEST_CASE("usertype/coverage", "try all the things") {
297 sol::state lua;
298 lua.open_libraries(sol::lib::base);
299
300 lua.new_usertype<ext_getset>("ext_getset",
301 sol::call_constructor,
302 sol::constructors<sol::types<>, sol::types<int>>(),
303 sol::meta_function::garbage_collect,
304 sol::destructor(des<ext_getset>),
305 "x",
__anon9334b35e0302(ext_getset& m, std::string x, int y) 306 sol::overload(&ext_getset::x, &ext_getset::x2, [](ext_getset& m, std::string x, int y) { return m.meow + 50 + y + static_cast<int>(x.length()); }),
307 "bark",
308 &ext_getset::bark,
309 "meow",
310 &ext_getset::meow,
311 "readonlybark",
312 sol::readonly(&ext_getset::bark),
313 "set",
314 &ext_getset::set,
315 "get",
316 &ext_getset::get,
317 "sset",
318 &ext_getset::s_set,
319 "sget",
320 &ext_getset::s_get,
321 "propbark",
322 sol::property(&ext_getset::set, &ext_getset::get),
323 "readonlypropbark",
324 sol::property(&ext_getset::get),
325 "writeonlypropbark",
326 sol::property(&ext_getset::set));
327
328 INFO("usertype created");
329
330 lua.safe_script(R"(
331 e = ext_getset()
332 w = e:x(e:x(), e:x(e:x()))
333 print(w)
334 )");
335
336 int w = lua["w"];
337 REQUIRE(w == (56 + 50 + 14 + 14));
338
339 INFO("REQUIRE(w) successful");
340
341 lua.safe_script(R"(
342 e:set(500)
343 e.sset(24)
344 x = e:get()
345 y = e.sget(20)
346 )");
347
348 int x = lua["x"];
349 int y = lua["y"];
350 REQUIRE(x == 500);
351 REQUIRE(y == 40);
352
353 INFO("REQUIRE(x, y) successful");
354
355 lua.safe_script(R"(
356 e.bark = 5001
357 a = e:get()
358 print(e.bark)
359 print(a)
360
361 e.propbark = 9700
362 b = e:get()
363 print(e.propbark)
364 print(b)
365 )");
366 int a = lua["a"];
367 int b = lua["b"];
368
369 REQUIRE(a == 5001);
370 REQUIRE(b == 9700);
371
372 INFO("REQUIRE(a, b) successful");
373
374 lua.safe_script(R"(
375 c = e.readonlybark
376 d = e.meow
377 print(e.readonlybark)
378 print(c)
379 print(e.meow)
380 print(d)
381 )");
382
383 int c = lua["c"];
384 int d = lua["d"];
385 REQUIRE(c == 9700);
386 REQUIRE(d == 56);
387
388 INFO("REQUIRE(c, d) successful");
389
390 lua.safe_script(R"(
391 e.writeonlypropbark = 500
392 z = e.readonlypropbark
393 print(e.readonlybark)
394 print(e.bark)
395 )");
396
397 int z = lua["z"];
398 REQUIRE(z == 500);
399
400 INFO("REQUIRE(z) successful");
401 {
402 auto result = lua.safe_script("e.readonlybark = 24", sol::script_pass_on_error);
403 REQUIRE_FALSE(result.valid());
404 INFO("REQUIRE_FALSE 1 successful");
405 }
406 {
407 auto result = lua.safe_script("e.readonlypropbark = 500", sol::script_pass_on_error);
408 REQUIRE_FALSE(result.valid());
409 INFO("REQUIRE_FALSE 2 successful");
410 }
411 {
412 auto result = lua.safe_script("y = e.writeonlypropbark", sol::script_pass_on_error);
413 REQUIRE_FALSE(result.valid());
414 INFO("REQUIRE_FALSE 3 successful");
415 }
416 }
417
418 TEST_CASE("usertype/alignment", "ensure that alignment does not trigger weird aliasing issues") {
419 struct aligned_base { };
420 struct aligned_derived : aligned_base { };
421
422 sol::state lua;
423 sol::stack_guard luasg(lua);
424
__anon9334b35e0402(aligned_base&, float d) 425 auto f = [](aligned_base&, float d) { REQUIRE(d == 5.0f); };
426 lua.new_usertype<aligned_base>("Base", "x", sol::writeonly_property(weird_aligned_wrapper<aligned_base>(std::ref(f))));
427 lua.new_usertype<aligned_derived>("Derived", sol::base_classes, sol::bases<aligned_base>());
428
429 aligned_derived d;
430 lua["d"] = d;
431
432 auto result = lua.safe_script("d.x = 5");
433 REQUIRE(result.valid());
434 }
435
436 TEST_CASE("usertype/readonly-and-static-functions", "Check if static functions can be called on userdata and from their originating (meta)tables") {
437 struct bark {
438 int var = 50;
439
funcbark440 void func() {
441 }
442
oh_boybark443 static void oh_boy() {
444 }
445
oh_boybark446 static int oh_boy(std::string name) {
447 return static_cast<int>(name.length());
448 }
449
operator ()bark450 int operator()(int x) {
451 return x;
452 }
453 };
454
455 sol::state lua;
456 lua.open_libraries(sol::lib::base);
457 lua.new_usertype<bark>(
458 "bark",
459 "var",
460 &bark::var,
461 "var2",
462 sol::readonly(&bark::var),
463 "something",
464 something_func_true,
465 "something2",
__anon9334b35e0502(int x, int y) 466 [](int x, int y) { return x + y; },
467 "func",
468 &bark::func,
469 "oh_boy",
470 sol::overload(sol::resolve<void()>(&bark::oh_boy), sol::resolve<int(std::string)>(&bark::oh_boy)),
471 sol::meta_function::call_function,
472 &bark::operator());
473
474 {
475 auto result = lua.safe_script("assert(bark.oh_boy('woo') == 3)", sol::script_pass_on_error);
476 REQUIRE(result.valid());
477 }
478 {
479 auto result = lua.safe_script("bark.oh_boy()", sol::script_pass_on_error);
480 REQUIRE(result.valid());
481 }
482
483 bark b;
484 lua.set("b", &b);
485
486 sol::table b_table = lua["b"];
487 sol::function member_func = b_table["func"];
488 sol::function s = b_table["something"];
489 sol::function s2 = b_table["something2"];
490
491 sol::table b_metatable = b_table[sol::metatable_key];
492 bool isvalidmt = b_metatable.valid();
493 REQUIRE(isvalidmt);
494 sol::function b_call = b_metatable["__call"];
495 sol::function b_as_function = lua["b"];
496
497 int x = b_as_function(1);
498 int y = b_call(b, 1);
499 bool z = s();
500 int w = s2(2, 3);
501 REQUIRE(x == 1);
502 REQUIRE(y == 1);
503 REQUIRE(z);
504 REQUIRE(w == 5);
505
506 lua.safe_script(R"(
507 lx = b(1)
508 ly = getmetatable(b).__call(b, 1)
509 lz = b.something()
510 lz2 = bark.something()
511 lw = b.something2(2, 3)
512 lw2 = bark.something2(2, 3)
513 )");
514
515 int lx = lua["lx"];
516 int ly = lua["ly"];
517 bool lz = lua["lz"];
518 int lw = lua["lw"];
519 bool lz2 = lua["lz2"];
520 int lw2 = lua["lw2"];
521 REQUIRE(lx == 1);
522 REQUIRE(ly == 1);
523 REQUIRE(lz);
524 REQUIRE(lz2);
525 REQUIRE(lw == 5);
526 REQUIRE(lw2 == 5);
527 REQUIRE(lx == ly);
528 REQUIRE(lz == lz2);
529 REQUIRE(lw == lw2);
530
531 auto result = lua.safe_script("b.var2 = 2", sol::script_pass_on_error);
532 REQUIRE_FALSE(result.valid());
533 }
534
535 TEST_CASE("usertype/vars", "usertype vars can bind various class items") {
536 static int muh_variable = 25;
537 static int through_variable = 10;
538
539 sol::state lua;
540 lua.open_libraries();
541 struct test { };
542 lua.new_usertype<test>("test",
543 "straight",
544 sol::var(2),
545 "global",
546 sol::var(muh_variable),
547 "ref_global",
548 sol::var(std::ref(muh_variable)),
549 "global2",
550 sol::var(through_variable),
551 "ref_global2",
552 sol::var(std::ref(through_variable)));
553
554 int prets = lua["test"]["straight"];
555 int pretg = lua["test"]["global"];
556 int pretrg = lua["test"]["ref_global"];
557 int pretg2 = lua["test"]["global2"];
558 int pretrg2 = lua["test"]["ref_global2"];
559
560 REQUIRE(prets == 2);
561 REQUIRE(pretg == 25);
562 REQUIRE(pretrg == 25);
563 REQUIRE(pretg2 == 10);
564 REQUIRE(pretrg2 == 10);
565
566 lua.safe_script(R"(
567 print(test.straight)
568 test.straight = 50
569 print(test.straight)
570 )");
571 int s = lua["test"]["straight"];
572 REQUIRE(s == 50);
573
574 lua.safe_script(R"(
575 t = test.new()
576 print(t.global)
577 t.global = 50
578 print(t.global)
579 )");
580 int mv = lua["test"]["global"];
581 REQUIRE(mv == 50);
582 REQUIRE(muh_variable == 25);
583
584 lua.safe_script(R"(
585 print(t.ref_global)
586 t.ref_global = 50
587 print(t.ref_global)
588 )");
589 int rmv = lua["test"]["ref_global"];
590 REQUIRE(rmv == 50);
591 REQUIRE(muh_variable == 50);
592
593 REQUIRE(through_variable == 10);
594 lua.safe_script(R"(
595 print(test.global2)
596 test.global2 = 35
597 print(test.global2)
598 )");
599 int tv = lua["test"]["global2"];
600 REQUIRE(through_variable == 10);
601 REQUIRE(tv == 35);
602
603 lua.safe_script(R"(
604 print(test.ref_global2)
605 test.ref_global2 = 35
606 print(test.ref_global2)
607 )");
608 int rtv = lua["test"]["ref_global2"];
609 REQUIRE(rtv == 35);
610 REQUIRE(through_variable == 35);
611 }
612