From fa07e54e08031b2137eb820d310eeff9393d3180 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Mon, 15 Oct 2018 21:53:16 -0400 Subject: [PATCH] some small fixes for usertypes, still need a few more drastic improvements... --- include/sol/usertype_core.hpp | 4 +- include/sol/usertype_storage.hpp | 36 +- tests/test_simple_usertypes.cpp | 977 ------------------------------- tests/tests.cpp | 19 +- 4 files changed, 42 insertions(+), 994 deletions(-) delete mode 100644 tests/test_simple_usertypes.cpp diff --git a/include/sol/usertype_core.hpp b/include/sol/usertype_core.hpp index 0a1650ea..25144dc4 100644 --- a/include/sol/usertype_core.hpp +++ b/include/sol/usertype_core.hpp @@ -203,13 +203,13 @@ namespace sol { void insert_default_registrations(IFx&& ifx, Fx&& fx) { if constexpr (is_automagical::value) { if (fx(meta_function::less_than)) { - if constexpr (meta::supports_op_equal::value) { + if constexpr (meta::supports_op_less::value) { lua_CFunction f = &comparsion_operator_wrap>; ifx(meta_function::less_than, f); } } if (fx(meta_function::less_than_or_equal_to)) { - if constexpr (meta::supports_op_equal::value) { + if constexpr (meta::supports_op_less_equal::value) { lua_CFunction f = &comparsion_operator_wrap>; ifx(meta_function::less_than_or_equal_to, f); } diff --git a/include/sol/usertype_storage.hpp b/include/sol/usertype_storage.hpp index 9d8e1e49..c5ce2e16 100644 --- a/include/sol/usertype_storage.hpp +++ b/include/sol/usertype_storage.hpp @@ -126,14 +126,24 @@ namespace u_detail { stack::get_field(L, stack_reference(L, raw_index(2)), metatarget); return 1; } - // With runtime extensibility, we can't hard-error things. They have to return nil, like regular table types + // With runtime extensibility, we can't + // hard-error things. They have to + // return nil, like regular table types return stack::push(L, lua_nil); } + inline int index_target_fail(lua_State* L, void*) { + return index_fail(L); + } + inline int new_index_fail(lua_State* L) { return luaL_error(L, "sol: cannot set (new_index) into this object: no defined new_index operation on usertype"); } + inline int new_index_target_fail(lua_State* L, void*) { + return new_index_fail(L); + } + struct usertype_storage_base { public: std::vector> storage; @@ -149,13 +159,19 @@ namespace u_detail { reference gc_names_table; reference metametatable; std::bitset<64> properties; - lua_CFunction base_index; - lua_CFunction base_new_index; + index_call_storage base_index; + index_call_storage base_new_index; bool is_using_index; bool is_using_new_index; usertype_storage_base(lua_State* L) - : storage(), string_keys(), auxiliary_keys(), value_index_table(), reference_index_table(), unique_index_table(), const_reference_index_table(), type_table(make_reference(L, create)), gc_names_table(make_reference(L, create)), metametatable(make_reference(L, create)), properties(), base_index(index_fail), base_new_index(new_index_fail), is_using_index(false), is_using_new_index(false) { + : storage(), string_keys(), auxiliary_keys(), value_index_table(), reference_index_table(), unique_index_table(), const_reference_index_table(), type_table(make_reference(L, create)), gc_names_table(make_reference(L, create)), metametatable(make_reference(L, create)), properties(), base_index(), base_new_index(), is_using_index(false), is_using_new_index(false) { + base_index.binding_data = nullptr; + base_index.index = index_target_fail; + base_index.new_index = index_target_fail; + base_new_index.binding_data = nullptr; + base_new_index.index = new_index_target_fail; + base_new_index.new_index = new_index_target_fail; } void clear() { @@ -244,7 +260,7 @@ namespace u_detail { return index_fail(L); } else { - return self.base_index(L); + return self.base_index.index(L, self.base_index.binding_data); } } @@ -300,7 +316,7 @@ namespace u_detail { return 0; } else { - return self.base_new_index(L); + return self.base_new_index.new_index(L, self.base_new_index.binding_data); } } @@ -438,7 +454,7 @@ namespace u_detail { ics.new_index = &b.index_call_with_; // need to swap everything to use fast indexing here auto fet = [&](lua_State* L, submetatable submetatable_type, reference& fast_index_table) { - if (submetatable_type == submetatable::named && no_use_named) { + if (submetatable_type == submetatable::named && (no_use_named || is_index || is_new_index)) { // do not override __call or // other specific meta functions on named metatable: // we need that for call construction @@ -458,6 +474,12 @@ namespace u_detail { } t.pop(); }; + if (is_index) { + this->base_index = ics; + } + if (is_new_index) { + this->base_new_index = ics; + } this->for_each_table(L, fet); this->string_keys.insert_or_assign(std::move(s), std::move(ics)); } diff --git a/tests/test_simple_usertypes.cpp b/tests/test_simple_usertypes.cpp deleted file mode 100644 index 98c278e5..00000000 --- a/tests/test_simple_usertypes.cpp +++ /dev/null @@ -1,977 +0,0 @@ -// sol3 - -// The MIT License (MIT) - -// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors - -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#include "test_sol.hpp" - -#include - -#include -#include -#include -#include - -TEST_CASE("simple_usertype/usertypes", "Ensure that simple usertypes properly work here") { - struct marker { - bool value = false; - }; - struct bark { - int var = 50; - marker mark; - - void fun() { - var = 51; - } - - int get() const { - return var; - } - - int set(int x) { - var = x; - return var; - } - - std::string special() const { - return mark.value ? "woof" : "pantpant"; - } - - const marker& the_marker() const { - return mark; - } - }; - - sol::state lua; - lua.new_simple_usertype("bark", - "fun", &bark::fun, - "get", &bark::get, - "var", sol::as_function(&bark::var), - "the_marker", sol::as_function(&bark::the_marker), - "x", sol::overload(&bark::get), - "y", sol::overload(&bark::set), - "z", sol::overload(&bark::get, &bark::set)); - - lua.safe_script("b = bark.new()"); - bark& b = lua["b"]; - - lua.safe_script("b:fun()"); - int var = b.var; - REQUIRE(var == 51); - - lua.safe_script("b:var(20)"); - lua.safe_script("v = b:var()"); - int v = lua["v"]; - REQUIRE(v == 20); - REQUIRE(b.var == 20); - - lua.safe_script("m = b:the_marker()"); - marker& m = lua["m"]; - REQUIRE_FALSE(b.mark.value); - REQUIRE_FALSE(m.value); - m.value = true; - REQUIRE(&b.mark == &m); - REQUIRE(b.mark.value); - - sol::table barktable = lua["bark"]; - barktable["special"] = &bark::special; - - lua.safe_script("s = b:special()"); - std::string s = lua["s"]; - REQUIRE(s == "woof"); - - lua.safe_script("b:y(24)"); - lua.safe_script("x = b:x()"); - int x = lua["x"]; - REQUIRE(x == 24); - - lua.safe_script("z = b:z(b:z() + 5)"); - int z = lua["z"]; - REQUIRE(z == 29); -} - -TEST_CASE("simple_usertype/usertype constructors", "Ensure that calls with specific arguments work") { - struct marker { - bool value = false; - }; - struct bark { - int var = 50; - marker mark; - - bark() { - } - bark(int v) - : var(v) { - } - - void fun() { - var = 51; - } - - int get() const { - return var; - } - - int set(int x) { - var = x; - return var; - } - - std::string special() const { - return mark.value ? "woof" : "pantpant"; - } - - const marker& the_marker() const { - return mark; - } - }; - - sol::state lua; - lua.new_simple_usertype("bark", - sol::constructors, sol::types>(), - "fun", sol::protect(&bark::fun), - "get", &bark::get, - "var", sol::as_function(&bark::var), - "the_marker", &bark::the_marker, - "x", sol::overload(&bark::get), - "y", sol::overload(&bark::set), - "z", sol::overload(&bark::get, &bark::set)); - - lua.safe_script("bx = bark.new(760)"); - bark& bx = lua["bx"]; - REQUIRE(bx.var == 760); - - lua.safe_script("b = bark.new()"); - bark& b = lua["b"]; - - lua.safe_script("b:fun()"); - int var = b.var; - REQUIRE(var == 51); - - lua.safe_script("b:var(20)"); - lua.safe_script("v = b:var()"); - int v = lua["v"]; - REQUIRE(v == 20); - - lua.safe_script("m = b:the_marker()"); - marker& m = lua["m"]; - REQUIRE_FALSE(b.mark.value); - REQUIRE_FALSE(m.value); - m.value = true; - REQUIRE(&b.mark == &m); - REQUIRE(b.mark.value); - - sol::table barktable = lua["bark"]; - barktable["special"] = &bark::special; - - lua.safe_script("s = b:special()"); - std::string s = lua["s"]; - REQUIRE(s == "woof"); - - lua.safe_script("b:y(24)"); - lua.safe_script("x = b:x()"); - int x = lua["x"]; - REQUIRE(x == 24); - - lua.safe_script("z = b:z(b:z() + 5)"); - int z = lua["z"]; - REQUIRE(z == 29); -} - -TEST_CASE("simple_usertype/vars", "simple usertype vars can bind various values (no ref)") { - int muh_variable = 10; - int through_variable = 25; - - sol::state lua; - lua.open_libraries(); - - struct test {}; - lua.new_simple_usertype("test", - "straight", sol::var(2), - "global", sol::var(muh_variable), - "global2", sol::var(through_variable), - "global3", sol::var(std::ref(through_variable))); - - through_variable = 20; - - lua.safe_script(R"( -print(test.straight) -s = test.straight -print(test.global) -g = test.global -print(test.global2) -g2 = test.global2 -print(test.global3) -g3 = test.global3 -)"); - - int s = lua["s"]; - int g = lua["g"]; - int g2 = lua["g2"]; - int g3 = lua["g3"]; - REQUIRE(s == 2); - REQUIRE(g == 10); - REQUIRE(g2 == 25); - REQUIRE(g3 == 20); -} - -TEST_CASE("simple_usertype/variable-control", "test to see if usertypes respond to inheritance and variable controls") { - class A { - public: - virtual void a() { - throw std::runtime_error("entered base pure virtual implementation"); - }; - }; - - class B : public A { - public: - virtual void a() override { - } - }; - - class sA { - public: - virtual void a() { - throw std::runtime_error("entered base pure virtual implementation"); - }; - }; - - class sB : public sA { - public: - virtual void a() override { - } - }; - - struct sV { - int a = 10; - int b = 20; - - int get_b() const { - return b + 2; - } - - void set_b(int value) { - b = value; - } - }; - - struct sW : sV {}; - - sol::state lua; - lua.open_libraries(); - - lua.new_usertype("A", "a", &A::a); - lua.new_usertype("B", sol::base_classes, sol::bases()); - lua.new_simple_usertype("sA", "a", &sA::a); - lua.new_simple_usertype("sB", sol::base_classes, sol::bases()); - lua.new_simple_usertype("sV", "a", &sV::a, "b", &sV::b, "pb", sol::property(&sV::get_b, &sV::set_b)); - lua.new_simple_usertype("sW", sol::base_classes, sol::bases()); - - B b; - lua.set("b", &b); - lua.safe_script("b:a()"); - - sB sb; - lua.set("sb", &sb); - lua.safe_script("sb:a()"); - - sV sv; - lua.set("sv", &sv); - lua.safe_script("print(sv.b)assert(sv.b == 20)"); - - sW sw; - lua.set("sw", &sw); - lua.safe_script("print(sw.a)assert(sw.a == 10)"); - lua.safe_script("print(sw.b)assert(sw.b == 20)"); - lua.safe_script("print(sw.pb)assert(sw.pb == 22)"); - lua.safe_script("sw.a = 11"); - lua.safe_script("sw.b = 21"); - lua.safe_script("print(sw.a)assert(sw.a == 11)"); - lua.safe_script("print(sw.b)assert(sw.b == 21)"); - lua.safe_script("print(sw.pb)assert(sw.pb == 23)"); - lua.safe_script("sw.pb = 25"); - lua.safe_script("print(sw.b)assert(sw.b == 25)"); - lua.safe_script("print(sw.pb)assert(sw.pb == 27)"); -} - -TEST_CASE("simple_usertype/factory constructor overloads", "simple usertypes should invoke the proper factories") { - class A { - public: - virtual void a() { - throw std::runtime_error("entered base pure virtual implementation"); - }; - }; - - class B : public A { - public: - int bvar = 24; - virtual void a() override { - } - void f() { - } - }; - - sol::state lua; - lua.open_libraries(); - sol::constructors, sol::types> c; - lua.new_simple_usertype("B", - sol::call_constructor, c, - "new", sol::factories([]() { - return B(); - }), - "new2", sol::initializers([](B& mem) { new (&mem) B(); }, [](B& mem, int v) { - new(&mem)B(); mem.bvar = v; }), - "f", sol::as_function(&B::bvar), - "g", sol::overload([](B&) { return 2; }, [](B&, int v) { return v; })); - - lua.safe_script("b = B()"); - lua.safe_script("b2 = B.new()"); - lua.safe_script("b3 = B.new2()"); - lua.safe_script("b4 = B.new2(11)"); - - lua.safe_script("x = b:f()"); - lua.safe_script("x2 = b2:f()"); - lua.safe_script("x3 = b3:f()"); - lua.safe_script("x4 = b4:f()"); - int x = lua["x"]; - int x2 = lua["x2"]; - int x3 = lua["x3"]; - int x4 = lua["x4"]; - REQUIRE(x == 24); - REQUIRE(x2 == 24); - REQUIRE(x3 == 24); - REQUIRE(x4 == 11); - - lua.safe_script("y = b:g()"); - lua.safe_script("y2 = b2:g(3)"); - lua.safe_script("y3 = b3:g()"); - lua.safe_script("y4 = b4:g(3)"); - int y = lua["y"]; - int y2 = lua["y2"]; - int y3 = lua["y3"]; - int y4 = lua["y4"]; - REQUIRE(y == 2); - REQUIRE(y2 == 3); - REQUIRE(y3 == 2); - REQUIRE(y4 == 3); -} - -TEST_CASE("simple_usertype/runtime append", "allow extra functions to be appended at runtime directly to the metatable itself") { - class A { - }; - - class B : public A { - }; - - sol::state lua; - lua.new_simple_usertype("A"); - lua.new_simple_usertype("B", sol::base_classes, sol::bases()); - lua.set("b", std::make_unique()); - lua["A"]["method"] = []() { return 200; }; - lua["B"]["method2"] = [](B&) { return 100; }; - lua.safe_script("x = b.method()"); - lua.safe_script("y = b:method()"); - - int x = lua["x"]; - int y = lua["y"]; - REQUIRE(x == 200); - REQUIRE(y == 200); - - lua.safe_script("z = b.method2(b)"); - lua.safe_script("w = b:method2()"); - int z = lua["z"]; - int w = lua["w"]; - REQUIRE(z == 100); - REQUIRE(w == 100); -} - -TEST_CASE("simple_usertype/table append", "Ensure that appending to the meta table also affects the internal function table for pointers as well") { - struct A { - int func() { - return 5000; - } - }; - - sol::state lua; - lua.open_libraries(); - - lua.new_simple_usertype("A"); - sol::table table = lua["A"]; - table["func"] = &A::func; - A a; - lua.set("a", &a); - lua.set("pa", &a); - lua.set("ua", std::make_unique()); - REQUIRE_NOTHROW([&] { - lua.safe_script("assert(a:func() == 5000)"); - lua.safe_script("assert(pa:func() == 5000)"); - lua.safe_script("assert(ua:func() == 5000)"); - }()); -} - -TEST_CASE("simple_usertype/class call propogation", "make sure methods and variables from base classes work properly in SAFE_USERTYPE mode") { - class A { - public: - int var = 200; - int thing() const { - return 123; - } - }; - - class B : public A { - }; - - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_simple_usertype("B", - sol::default_constructor, - "thing", &B::thing, - "var", &B::var); - - lua.safe_script(R"( - b = B.new() - print(b.var) - b:thing() -)"); -} - -TEST_CASE("simple_usertype/call constructor", "ensure that all kinds of call-based constructors can be serialized") { - struct thing {}; - struct v_test { - }; - struct f_test { - int i; - f_test(int i) - : i(i) { - } - }; - struct i_test { - int i; - i_test(int i) - : i(i) { - } - }; - struct r_test { - int i; - r_test(int i) - : i(i) { - } - }; - - sol::state lua; - lua.open_libraries(sol::lib::base); - - auto f = sol::factories([]() { return f_test(30); }); - lua.new_simple_usertype("f_test", - sol::call_constructor, sol::factories([]() { - return f_test(20); - }), - "new", f); - - lua.new_simple_usertype("i_test", - sol::call_constructor, sol::initializers([](i_test& obj) { - new (&obj) i_test(21); - })); - - lua.new_simple_usertype("r_test", - sol::call_constructor, [](sol::table) { - return r_test(22); - }); - - lua.safe_script("a = f_test()"); - lua.safe_script("b = i_test()"); - lua.safe_script("c = r_test()"); - lua.safe_script("d = f_test.new()"); - f_test& a = lua["a"]; - f_test& d = lua["d"]; - i_test& b = lua["b"]; - r_test& c = lua["c"]; - REQUIRE(a.i == 20); - REQUIRE(b.i == 21); - REQUIRE(c.i == 22); - REQUIRE(d.i == 30); - - auto vfactories = sol::factories( - [](const sol::table& tbl) { - for (auto v : tbl) { - REQUIRE(v.second.valid()); - REQUIRE(v.second.is()); - } - return v_test(); - }); - - lua.new_simple_usertype("v_test", - sol::meta_function::construct, vfactories, - sol::call_constructor, vfactories); - - lua.new_simple_usertype("thing"); - lua.safe_script("things = {thing.new(), thing.new()}"); - - SECTION("new") { - { - auto result = lua.safe_script("a = v_test.new(things)", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - } - SECTION("call_constructor") { - { - auto result = lua.safe_script("b = v_test(things)", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - } -} - -TEST_CASE("simple_usertype/no_constructor", "make sure simple usertype errors when no-constructor types are called") { - struct thing {}; - - SECTION("new no_constructor") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_simple_usertype("thing", - sol::meta_function::construct, sol::no_constructor); - auto result = lua.safe_script("a = thing.new()", sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); - } - - SECTION("call no_constructor") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_simple_usertype("thing", - sol::call_constructor, sol::no_constructor); - auto result = lua.safe_script("a = thing()", sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); - } -} - -TEST_CASE("simple_usertype/missing key", "make sure a missing key returns nil") { - struct thing {}; - - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_simple_usertype("thing"); - { - auto result = lua.safe_script("print(thing.missingKey)", sol::script_pass_on_error); - REQUIRE(result.valid()); - } -} - -TEST_CASE("simple_usertype/runtime extensibility", "Check if usertypes are runtime extensible") { - struct thing { - int v = 20; - int func(int a) { - return a; - } - }; - int val = 0; - - SECTION("just functions") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_simple_usertype("thing", - "func", &thing::func); - - lua.safe_script(R"( -t = thing.new() - )"); - - { - auto result = lua.safe_script(R"( -t.runtime_func = function (a) - return a + 50 -end - )", - sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); - } - - { - auto result = lua.safe_script(R"( -function t:runtime_func(a) - return a + 52 -end - )", - sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); - } - - lua.safe_script("val = t:func(2)"); - val = lua["val"]; - REQUIRE(val == 2); - - REQUIRE_NOTHROW([&lua]() { - lua.safe_script(R"( -function thing:runtime_func(a) - return a + 1 -end - )"); - }()); - - lua.safe_script("val = t:runtime_func(2)"); - val = lua["val"]; - REQUIRE(val == 3); - } - SECTION("with variable") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_simple_usertype("thing", - "func", &thing::func, - "v", &thing::v); - - lua.safe_script(R"( -t = thing.new() - )"); - - { - auto result = lua.safe_script(R"( -t.runtime_func = function (a) - return a + 50 -end - )", - sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); - } - - { - auto result = lua.safe_script(R"( -function t:runtime_func(a) - return a + 52 -end - )", sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); - } - - lua.safe_script("val = t:func(2)"); - val = lua["val"]; - REQUIRE(val == 2); - - REQUIRE_NOTHROW([&lua]() { - lua.safe_script(R"( -function thing:runtime_func(a) - return a + 1 -end - )"); - }()); - - lua.safe_script("val = t:runtime_func(2)"); - val = lua["val"]; - REQUIRE(val == 3); - } -} - -TEST_CASE("simple_usertype/runtime replacement", "ensure that functions can be properly replaced at runtime for non-indexed things") { - struct heart_base_t {}; - struct heart_t : heart_base_t { - void func() { - } - }; - - SECTION("plain") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_simple_usertype("a"); - REQUIRE_NOTHROW([&lua]() { - lua.safe_script("obj = a.new()"); - lua.safe_script("function a:heartbeat () print('arf') return 1 end"); - lua.safe_script("v1 = obj:heartbeat()"); - lua.safe_script("function a:heartbeat () print('bark') return 2 end"); - lua.safe_script("v2 = obj:heartbeat()"); - lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end"); - lua.safe_script("v3 = obj:heartbeat()"); - }()); - int v1 = lua["v1"]; - int v2 = lua["v2"]; - int v3 = lua["v3"]; - REQUIRE(v1 == 1); - REQUIRE(v2 == 2); - REQUIRE(v3 == 3); - } - SECTION("variables") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_simple_usertype("a", - sol::base_classes, sol::bases()); - - REQUIRE_NOTHROW([&lua]() { - lua.safe_script("obj = a.new()"); - lua.safe_script("function a:heartbeat () print('arf') return 1 end"); - lua.safe_script("v1 = obj:heartbeat()"); - lua.safe_script("function a:heartbeat () print('bark') return 2 end"); - lua.safe_script("v2 = obj:heartbeat()"); - lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end"); - lua.safe_script("v3 = obj:heartbeat()"); - }()); - int v1 = lua["v1"]; - int v2 = lua["v2"]; - int v3 = lua["v3"]; - REQUIRE(v1 == 1); - REQUIRE(v2 == 2); - REQUIRE(v3 == 3); - } - SECTION("methods") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_simple_usertype("a", - "func", &heart_t::func, - sol::base_classes, sol::bases()); - - REQUIRE_NOTHROW([&lua]() { - lua.safe_script("obj = a.new()"); - lua.safe_script("function a:heartbeat () print('arf') return 1 end"); - lua.safe_script("v1 = obj:heartbeat()"); - lua.safe_script("function a:heartbeat () print('bark') return 2 end"); - lua.safe_script("v2 = obj:heartbeat()"); - lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end"); - lua.safe_script("v3 = obj:heartbeat()"); - }()); - int v1 = lua["v1"]; - int v2 = lua["v2"]; - int v3 = lua["v3"]; - REQUIRE(v1 == 1); - REQUIRE(v2 == 2); - REQUIRE(v3 == 3); - } -} - -TEST_CASE("simple_usertype/runtime additions with newindex", "ensure that additions when new_index is overriden don't hit the specified new_index function") { - class newindex_object {}; - sol::state lua; - lua.open_libraries(sol::lib::base); - lua.new_simple_usertype("object", - sol::meta_function::new_index, [](newindex_object& o, sol::object key, sol::object value) { - return; - }); - - lua["object"]["test"] = [](newindex_object& o) { - std::cout << "test" << std::endl; - return 446; - }; - - auto result1 = lua.safe_script("o = object.new()", sol::script_pass_on_error); - REQUIRE(result1.valid()); - auto result2 = lua.safe_script("assert(o:test() == 446)", sol::script_pass_on_error); - REQUIRE(result2.valid()); -} - -TEST_CASE("simple_usertype/meta key retrievals", "allow for special meta keys (__index, __newindex) to trigger methods even if overwritten directly") { - SECTION("dynamically") { - static int writes = 0; - static std::string keys[4] = {}; - static int values[4] = {}; - struct d_sample { - void foo(std::string k, int v) { - keys[writes] = k; - values[writes] = v; - ++writes; - } - }; - - sol::state lua; - lua.new_simple_usertype("sample"); - sol::table s = lua["sample"]["new"](); - s[sol::metatable_key][sol::meta_function::new_index] = &d_sample::foo; - lua["var"] = s; - - lua.safe_script("var = sample.new()"); - lua.safe_script("var.key = 2"); - lua.safe_script("var.__newindex = 4"); - lua.safe_script("var.__index = 3"); - lua.safe_script("var.__call = 1"); - REQUIRE(values[0] == 2); - REQUIRE(values[1] == 4); - REQUIRE(values[2] == 3); - REQUIRE(values[3] == 1); - REQUIRE(keys[0] == "key"); - REQUIRE(keys[1] == "__newindex"); - REQUIRE(keys[2] == "__index"); - REQUIRE(keys[3] == "__call"); - } - - SECTION("statically") { - static int writes = 0; - static std::string keys[4] = {}; - static int values[4] = {}; - struct sample { - void foo(std::string k, int v) { - keys[writes] = k; - values[writes] = v; - ++writes; - } - }; - - sol::state lua; - lua.new_simple_usertype("sample", sol::meta_function::new_index, &sample::foo); - - lua.safe_script("var = sample.new()"); - lua.safe_script("var.key = 2"); - lua.safe_script("var.__newindex = 4"); - lua.safe_script("var.__index = 3"); - lua.safe_script("var.__call = 1"); - REQUIRE(values[0] == 2); - REQUIRE(values[1] == 4); - REQUIRE(values[2] == 3); - REQUIRE(values[3] == 1); - REQUIRE(keys[0] == "key"); - REQUIRE(keys[1] == "__newindex"); - REQUIRE(keys[2] == "__index"); - REQUIRE(keys[3] == "__call"); - } -} - -TEST_CASE("simple_usertype/static properties", "allow for static functions to get and set things as a property") { - static int b = 50; - struct test_t { - static double s_func() { - return b + 0.5; - } - - static void g_func(int v) { - b = v; - } - - std::size_t func() { - return 24; - } - }; - test_t manager; - - sol::state lua; - - lua.new_simple_usertype("test", - "f", std::function(std::bind(std::mem_fn(&test_t::func), &manager)), - "g", sol::property(&test_t::s_func, &test_t::g_func)); - - lua.safe_script("v1 = test.f()"); - lua.safe_script("v2 = test.g"); - lua.safe_script("test.g = 60"); - lua.safe_script("v2a = test.g"); - int v1 = lua["v1"]; - REQUIRE(v1 == 24); - double v2 = lua["v2"]; - REQUIRE(v2 == 50.5); - double v2a = lua["v2a"]; - REQUIRE(v2a == 60.5); -} - -TEST_CASE("simple_usertype/indexing", "make sure simple usertypes can be indexed/new_indexed properly without breaking") { - static int val = 0; - - class indexing_test { - public: - indexing_test() { - val = 0; - } - - sol::object getter(const std::string& name, sol::this_state _s) { - REQUIRE(name == "a"); - return sol::make_object(_s, 2); - } - - void setter(std::string name, sol::object n) { - REQUIRE(name == "unknown"); - val = n.as(); - } - - int hi() { - std::cout << "hi" << std::endl; - return 25; - } - }; - - SECTION("no runtime additions") { - sol::state lua; - lua.open_libraries(sol::lib::base); - lua.new_simple_usertype("test", - sol::meta_function::index, &indexing_test::getter, - sol::meta_function::new_index, &indexing_test::setter); - - lua.safe_script(R"( - local t = test.new() - v = t.a - print(v) - t.unknown = 50 - )"); - int v = lua["v"]; - REQUIRE(v == 2); - REQUIRE(val == 50); - } - SECTION("runtime additions") { - sol::state lua; - lua.open_libraries(sol::lib::base); - lua.new_simple_usertype("test", - sol::meta_function::index, &indexing_test::getter, - sol::meta_function::new_index, &indexing_test::setter); - - lua["test"]["hi"] = [](indexing_test& _self) -> int { return _self.hi(); }; - - lua.safe_script(R"( - local t = test.new() - v = t.a; - print(v) - t.unknown = 50 - u = t:hi() - )"); - int v = lua["v"]; - int u = lua["u"]; - REQUIRE(v == 2); - REQUIRE(u == 25); - REQUIRE(val == 50); - } -} - -TEST_CASE("simple_usertype/basic type information", "check that we can query some basic type information") { - struct my_thing {}; - - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_simple_usertype("my_thing"); - - lua.safe_script("obj = my_thing.new()"); - - lua.safe_script("assert(my_thing.__type.is(obj))"); - lua.safe_script("assert(not my_thing.__type.is(1))"); - lua.safe_script("assert(not my_thing.__type.is(\"not a thing\"))"); - lua.safe_script("print(my_thing.__type.name)"); - - lua.safe_script("assert(obj.__type.is(obj))"); - lua.safe_script("assert(not obj.__type.is(1))"); - lua.safe_script("assert(not obj.__type.is(\"not a thing\"))"); - lua.safe_script("print(obj.__type.name)"); - - lua.safe_script("assert(getmetatable(my_thing).__type.is(obj))"); - lua.safe_script("assert(not getmetatable(my_thing).__type.is(1))"); - lua.safe_script("assert(not getmetatable(my_thing).__type.is(\"not a thing\"))"); - lua.safe_script("print(getmetatable(my_thing).__type.name)"); - - lua.safe_script("assert(getmetatable(obj).__type.is(obj))"); - lua.safe_script("assert(not getmetatable(obj).__type.is(1))"); - lua.safe_script("assert(not getmetatable(obj).__type.is(\"not a thing\"))"); - lua.safe_script("print(getmetatable(obj).__type.name)"); -} diff --git a/tests/tests.cpp b/tests/tests.cpp index ca3df292..f53bf1bd 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -1,4 +1,4 @@ -// sol3 +// sol3 // The MIT License (MIT) @@ -277,7 +277,7 @@ TEST_CASE("object/conversions", "make sure all basic reference types can be made struct d {}; lua.safe_script("function f () print('bark') end"); - lua["d"] = d{}; + lua["d"] = d {}; lua["l"] = static_cast(nullptr); sol::table t = lua.create_table(); @@ -331,7 +331,7 @@ TEST_CASE("object/main_* conversions", "make sure all basic reference types can struct d {}; lua.safe_script("function f () print('bark') end"); - lua["d"] = d{}; + lua["d"] = d {}; lua["l"] = static_cast(nullptr); sol::main_table t = lua.create_table(); @@ -403,8 +403,11 @@ TEST_CASE("feature/indexing overrides", "make sure index functions can be overri sol::state lua; lua.open_libraries(sol::lib::base); - lua.new_usertype("PropertySet", sol::meta_function::new_index, &PropertySet::set_property_lua, sol::meta_function::index, &PropertySet::get_property_lua); - lua.new_usertype("DynamicObject", "props", sol::property(&DynamicObject::get_dynamic_props)); + sol::usertype utps = lua.new_usertype("PropertySet"); + utps[sol::meta_function::new_index] = &PropertySet::set_property_lua; + utps[sol::meta_function::index] = &PropertySet::get_property_lua; + sol::usertype utdo = lua.new_usertype("DynamicObject"); + utdo["props"] = sol::property(&DynamicObject::get_dynamic_props); lua.safe_script(R"__( obj = DynamicObject:new() @@ -422,7 +425,7 @@ TEST_CASE("features/indexing numbers", "make sure indexing functions can be over double data[3]; vector() - : data{ 0, 0, 0 } { + : data { 0, 0, 0 } { } double& operator[](int i) { @@ -634,7 +637,7 @@ TEST_CASE("object/is", "test whether or not the is abstraction works properly fo sol::state lua; lua.open_libraries(sol::lib::base); lua.set_function("is_thing", [](sol::stack_object obj) { return obj.is(); }); - lua["a"] = thing{}; + lua["a"] = thing {}; { auto result = lua.safe_script("assert(is_thing(a))", sol::script_pass_on_error); REQUIRE(result.valid()); @@ -645,7 +648,7 @@ TEST_CASE("object/is", "test whether or not the is abstraction works properly fo sol::state lua; lua.open_libraries(sol::lib::base); lua.set_function("is_thing", [](sol::object obj) { return obj.is(); }); - lua["a"] = thing{}; + lua["a"] = thing {}; { auto result = lua.safe_script("assert(is_thing(a))", sol::script_pass_on_error); REQUIRE(result.valid());