From b938e42af60441aeb9b14ec37809df3fa2d39fe5 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Thu, 14 Feb 2019 02:40:57 -0500 Subject: [PATCH] SUPER DUPER UPDATE WOO --- examples/CMakeLists.txt | 2 +- .../interop/LuaBridge/source/LuaBridge.cpp | 49 +- examples/interop/kaguya/source/kaguya.cpp | 69 +- examples/interop/luwra/source/luwra.cpp | 61 +- examples/interop/tolua/source/tolua.cpp | 33 +- include/sol/ebco.hpp | 4 +- include/sol/optional_implementation.hpp | 12 +- include/sol/stack_check_unqualified.hpp | 19 +- include/sol/stack_core.hpp | 176 ++- include/sol/stack_get_unqualified.hpp | 37 +- single/include/sol/forward.hpp | 4 +- single/include/sol/sol.hpp | 249 ++-- tests/runtime_tests/CMakeLists.txt | 2 +- tests/runtime_tests/source/common_classes.hpp | 25 + .../source/container_semantics.cpp | 1147 ++--------------- .../source/container_semantics.custom.cpp | 297 +++++ .../source/container_semantics.ordered.cpp | 377 ++++++ .../source/container_semantics.unordered.cpp | 269 ++++ tests/runtime_tests/source/containers.cpp | 352 +---- .../source/containers.roundtrip.cpp | 172 +++ .../runtime_tests/source/containers.table.cpp | 222 ++++ .../runtime_tests/source/usertypes.basic.cpp | 289 +++++ .../source/usertypes.constructors.cpp | 206 +++ tests/runtime_tests/source/usertypes.cpp | 678 ---------- ...eritance.cpp => usertypes.inheritance.cpp} | 30 + .../source/usertypes.member_variables.cpp | 126 ++ .../source/usertypes.overload.cpp | 89 ++ ...roperties.cpp => usertypes.properties.cpp} | 0 ...type_runtime.cpp => usertypes.runtime.cpp} | 0 ...ertype_unique.cpp => usertypes.unique.cpp} | 0 tests/runtime_tests/source/utility.cpp | 21 +- 31 files changed, 2663 insertions(+), 2354 deletions(-) create mode 100644 tests/runtime_tests/source/container_semantics.custom.cpp create mode 100644 tests/runtime_tests/source/container_semantics.ordered.cpp create mode 100644 tests/runtime_tests/source/container_semantics.unordered.cpp create mode 100644 tests/runtime_tests/source/containers.roundtrip.cpp create mode 100644 tests/runtime_tests/source/containers.table.cpp create mode 100644 tests/runtime_tests/source/usertypes.basic.cpp create mode 100644 tests/runtime_tests/source/usertypes.constructors.cpp rename tests/runtime_tests/source/{inheritance.cpp => usertypes.inheritance.cpp} (87%) create mode 100644 tests/runtime_tests/source/usertypes.member_variables.cpp create mode 100644 tests/runtime_tests/source/usertypes.overload.cpp rename tests/runtime_tests/source/{usertype_properties.cpp => usertypes.properties.cpp} (100%) rename tests/runtime_tests/source/{usertype_runtime.cpp => usertypes.runtime.cpp} (100%) rename tests/runtime_tests/source/{usertype_unique.cpp => usertypes.unique.cpp} (100%) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 19c6a3b0..f2f61fa7 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -85,7 +85,7 @@ function (MAKE_EXAMPLE example_source_file example_suffix target_sol) else() target_compile_options(${example_name} PRIVATE -std=c++1z - -Wall -Wpendatic -Werror -pedantic -pedantic-errors + -Wall -Wpedantic -Werror -pedantic -pedantic-errors -Wno-noexcept-type -Wno-unknown-warning -Wno-unknown-warning-option) endif() diff --git a/examples/interop/LuaBridge/source/LuaBridge.cpp b/examples/interop/LuaBridge/source/LuaBridge.cpp index e77d30a8..72d9ccc7 100644 --- a/examples/interop/LuaBridge/source/LuaBridge.cpp +++ b/examples/interop/LuaBridge/source/LuaBridge.cpp @@ -29,36 +29,27 @@ private: int v_ = 50; }; -namespace sol { -namespace stack { - template - struct userdata_checker> { - template - static bool check(lua_State* L, int relindex, type index_type, Handler&& handler, record& tracking) { - // just marking unused parameters for no compiler warnings - (void)index_type; - (void)handler; - tracking.use(1); - int index = lua_absindex(L, relindex); - T* corrected = luabridge::Userdata::get(L, index, true); - return corrected != nullptr; - } - }; - - template - struct userdata_getter> { - static std::pair get(lua_State* L, int relindex, void* unadjusted_pointer, record& tracking) { - (void)unadjusted_pointer; - int index = lua_absindex(L, relindex); - if (!userdata_checker>::check(L, index, type::userdata, no_panic, tracking)) { - return { false, nullptr }; - } - T* corrected = luabridge::Userdata::get(L, index, true); - return { true, corrected }; - } - }; +template +inline bool sol_lua_interop_check(sol::types, lua_State* L, int relindex, sol::type index_type, Handler&& handler, sol::stack::record& tracking) { + // just marking unused parameters for no compiler warnings + (void)index_type; + (void)handler; + tracking.use(1); + int index = lua_absindex(L, relindex); + T* corrected = luabridge::Userdata::get(L, index, true); + return corrected != nullptr; +} + +template +inline std::pair sol_lua_interop_get(sol::types t, lua_State* L, int relindex, void* unadjusted_pointer, sol::stack::record& tracking) { + (void)unadjusted_pointer; + int index = lua_absindex(L, relindex); + if (!sol_lua_interop_check(t, L, index, sol::type::userdata, sol::no_panic, tracking)) { + return { false, nullptr }; + } + T* corrected = luabridge::Userdata::get(L, index, true); + return { true, corrected }; } -} // namespace sol::stack void register_sol_stuff(lua_State* L) { // grab raw state and put into state_view diff --git a/examples/interop/kaguya/source/kaguya.cpp b/examples/interop/kaguya/source/kaguya.cpp index 33292f08..564f38ec 100644 --- a/examples/interop/kaguya/source/kaguya.cpp +++ b/examples/interop/kaguya/source/kaguya.cpp @@ -39,46 +39,37 @@ private: int v_; }; -namespace sol { -namespace stack { - template - struct userdata_checker> { - template - static bool check(lua_State* L, int relindex, type index_type, Handler&& handler, record& tracking) { - // just marking unused parameters for no compiler warnings - (void)index_type; - (void)handler; - // using 1 element - tracking.use(1); - int index = lua_absindex(L, relindex); - // use kaguya's own detail wrapper check to see if it's correct - bool is_correct_type = kaguya::detail::object_wrapper_type_check(L, index); - return is_correct_type; - } - }; - - template - struct userdata_getter> { - static std::pair get(lua_State* L, int relindex, void* unadjusted_pointer, record& tracking) { - // you may not need to specialize this method every time: - // some libraries are compatible with sol2's layout - - // kaguya's storage of data is incompatible with sol's - // it stores the data directly in the pointer, not a pointer inside of the `void*` - // therefore, leave the raw userdata pointer as-is, - // if it's of the right type - int index = lua_absindex(L, relindex); - if (!kaguya::detail::object_wrapper_type_check(L, index)) { - return { false, nullptr }; - } - // using 1 element - tracking.use(1); - kaguya::ObjectWrapperBase* base = kaguya::object_wrapper(L, index); - return { true, static_cast(base->get()) }; - } - }; +template +inline bool sol_lua_interop_check(sol::types, lua_State* L, int relindex, sol::type index_type, Handler&& handler, sol::stack::record& tracking) { + // just marking unused parameters for no compiler warnings + (void)index_type; + (void)handler; + // using 1 element + tracking.use(1); + int index = lua_absindex(L, relindex); + // use kaguya's own detail wrapper check to see if it's correct + bool is_correct_type = kaguya::detail::object_wrapper_type_check(L, index); + return is_correct_type; +} + +template +inline std::pair sol_lua_interop_get(sol::types, lua_State* L, int relindex, void* unadjusted_pointer, sol::stack::record& tracking) { + // you may not need to specialize this method every time: + // some libraries are compatible with sol2's layout + + // kaguya's storage of data is incompatible with sol's + // it stores the data directly in the pointer, not a pointer inside of the `void*` + // therefore, leave the raw userdata pointer as-is, + // if it's of the right type + int index = lua_absindex(L, relindex); + if (!kaguya::detail::object_wrapper_type_check(L, index)) { + return { false, nullptr }; + } + // using 1 element + tracking.use(1); + kaguya::ObjectWrapperBase* base = kaguya::object_wrapper(L, index); + return { true, static_cast(base->get()) }; } -} // namespace sol::stack void register_sol_stuff(lua_State* L) { // grab raw state and put into state_view diff --git a/examples/interop/luwra/source/luwra.cpp b/examples/interop/luwra/source/luwra.cpp index 85c0c2d6..6710194c 100644 --- a/examples/interop/luwra/source/luwra.cpp +++ b/examples/interop/luwra/source/luwra.cpp @@ -35,42 +35,33 @@ private: int v_; }; -namespace sol { -namespace stack { - template - struct userdata_checker> { - template - static bool check(lua_State* L, int relindex, type index_type, Handler&& handler, record& tracking) { - // just marking unused parameters for no compiler warnings - (void)index_type; - (void)handler; - // using 1 element - tracking.use(1); - int index = lua_absindex(L, relindex); - if (lua_getmetatable(L, index) == 1) { - luaL_getmetatable(L, luwra::internal::UserTypeReg::name.c_str()); - bool is_correct_type = lua_rawequal(L, -2, -1) == 1; - lua_pop(L, 2); - return is_correct_type; - } - return false; - } - }; - - template - struct userdata_getter> { - static std::pair get(lua_State* L, int relindex, void* unadjusted_pointer, record& tracking) { - // you may not need to specialize this method every time: - // some libraries are compatible with sol2's layout - int index = lua_absindex(L, relindex); - if (!userdata_checker>::check(L, index, type::userdata, no_panic, tracking)) { - return { false, nullptr }; - } - return { true, static_cast(unadjusted_pointer) }; - } - }; +template +inline bool sol_lua_interop_check(sol::types, lua_State* L, int relindex, sol::type index_type, Handler&& handler, sol::stack::record& tracking) { + // just marking unused parameters for no compiler warnings + (void)index_type; + (void)handler; + // using 1 element + tracking.use(1); + int index = lua_absindex(L, relindex); + if (lua_getmetatable(L, index) == 1) { + luaL_getmetatable(L, luwra::internal::UserTypeReg::name.c_str()); + bool is_correct_type = lua_rawequal(L, -2, -1) == 1; + lua_pop(L, 2); + return is_correct_type; + } + return false; +} + +template +inline std::pair sol_lua_interop_get(sol::types t, lua_State* L, int relindex, void* unadjusted_pointer, sol::stack::record& tracking) { + // you may not need to specialize this method every time: + // some libraries are compatible with sol2's layout + int index = lua_absindex(L, relindex); + if (!sol_lua_interop_check(t, L, index, sol::type::userdata, sol::no_panic, tracking)) { + return { false, nullptr }; + } + return { true, static_cast(unadjusted_pointer) }; } -} // namespace sol::stack void register_sol_stuff(lua_State* L) { // grab raw state and put into state_view diff --git a/examples/interop/tolua/source/tolua.cpp b/examples/interop/tolua/source/tolua.cpp index 9ff1618d..9555d54a 100644 --- a/examples/interop/tolua/source/tolua.cpp +++ b/examples/interop/tolua/source/tolua.cpp @@ -15,24 +15,23 @@ // I don't know where else you're gonna find the reference, // http://usefulgamedev.weebly.com/tolua-example.html -namespace sol { -namespace stack { - template - struct userdata_checker> { - template - static bool check(lua_State* L, int relindex, type index_type, Handler&& handler, record& tracking) { - tracking.use(1); - // just marking unused parameters for no compiler warnings - (void)index_type; - (void)handler; - int index = lua_absindex(L, relindex); - std::string name = sol::detail::short_demangle(); - tolua_Error tolua_err; - return tolua_isusertype(L, index, name.c_str(), 0, &tolua_err); - } - }; + +/* NOTE: there is no sol_lua_interop_get here, + because tolua types are -- thankfully -- memory-compatible + in most cases with sol. + Please check other examples like kaguya or LuaBribe for an example + of how to also write the getter for your type*/ +template +inline bool sol_lua_interop_check(sol::types, lua_State* L, int relindex, sol::type index_type, Handler&& handler, sol::stack::record& tracking) { + tracking.use(1); + // just marking unused parameters for no compiler warnings + (void)index_type; + (void)handler; + int index = lua_absindex(L, relindex); + std::string name = sol::detail::short_demangle(); + tolua_Error tolua_err; + return tolua_isusertype(L, index, name.c_str(), 0, &tolua_err); } -} // namespace sol::stack void register_sol_stuff(lua_State* L) { // grab raw state and put into state_view diff --git a/include/sol/ebco.hpp b/include/sol/ebco.hpp index c4815d3c..d43022b9 100644 --- a/include/sol/ebco.hpp +++ b/include/sol/ebco.hpp @@ -49,7 +49,7 @@ namespace sol { namespace detail { template >, ebco> && !std::is_same_v>, T>>> - ebco(Arg&& arg, Args&&... args) : T(std::forward(arg), std::forward(args)...){}; + ebco(Arg&& arg, Args&&... args) : T(std::forward(arg), std::forward(args)...){} T& value() { return value_; @@ -70,7 +70,7 @@ namespace sol { namespace detail { template >, ebco> && !std::is_same_v>, T>>> - ebco(Arg&& arg, Args&&... args) : T(std::forward(arg), std::forward(args)...){}; + ebco(Arg&& arg, Args&&... args) : T(std::forward(arg), std::forward(args)...){} ebco& operator=(const ebco&) = default; ebco& operator=(ebco&&) = default; diff --git a/include/sol/optional_implementation.hpp b/include/sol/optional_implementation.hpp index d48af999..c05fe8bf 100644 --- a/include/sol/optional_implementation.hpp +++ b/include/sol/optional_implementation.hpp @@ -1149,20 +1149,26 @@ namespace sol { /// \synopsis template optional(const optional &rhs); template * = nullptr, detail::enable_if_t::value>* = nullptr> optional(const optional& rhs) { - this->construct(*rhs); + if (rhs.has_value()) { + this->construct(*rhs); + } } /// \exclude template * = nullptr, detail::enable_if_t::value>* = nullptr> explicit optional(const optional& rhs) { - this->construct(*rhs); + if (rhs.has_value()) { + this->construct(*rhs); + } } /// Converting move constructor. /// \synopsis template optional(optional &&rhs); template * = nullptr, detail::enable_if_t::value>* = nullptr> optional(optional&& rhs) { - this->construct(std::move(*rhs)); + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } } /// \exclude diff --git a/include/sol/stack_check_unqualified.hpp b/include/sol/stack_check_unqualified.hpp index f830f602..9d44e999 100644 --- a/include/sol/stack_check_unqualified.hpp +++ b/include/sol/stack_check_unqualified.hpp @@ -71,13 +71,21 @@ namespace sol { namespace stack { } // namespace stack_detail template - struct userdata_checker { + struct unqualified_interop_checker { template static bool check(lua_State*, int, type, Handler&&, record&) { return false; } }; + template + struct qualified_interop_checker { + template + static bool check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { + return stack_detail::unqualified_interop_check(L, index, index_type, std::forward(handler), tracking); + } + }; + template struct unqualified_checker { template @@ -446,15 +454,13 @@ namespace sol { namespace stack { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { const type indextype = type_of(L, index); - return check(types(), L, index, indextype, handler, tracking); + return check(types(), L, index, indextype, std::forward(handler), tracking); } template static bool check(types, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { #if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP - userdata_checker> uc; - (void)uc; - if (uc.check(L, index, indextype, handler, tracking)) { + if (stack_detail::interop_check(L, index, indextype, handler, tracking)) { return true; } #endif // interop extensibility @@ -463,8 +469,7 @@ namespace sol { namespace stack { handler(L, index, type::userdata, indextype, "value is not a valid userdata"); return false; } - if (meta::any, std::is_same, std::is_same, std::is_same>:: - value) + if (meta::any, std::is_same, std::is_same, std::is_same>::value) return true; if (lua_getmetatable(L, index) == 0) { return true; diff --git a/include/sol/stack_core.hpp b/include/sol/stack_core.hpp index 209036b3..84c5fa85 100644 --- a/include/sol/stack_core.hpp +++ b/include/sol/stack_core.hpp @@ -98,14 +98,13 @@ namespace sol { } inline void* align_usertype_pointer(void* ptr) { - typedef std::integral_constant::value > 1) #endif - > - use_align; + >; if (!use_align::value) { return ptr; } @@ -115,14 +114,13 @@ namespace sol { template inline void* align_usertype_unique_destructor(void* ptr) { - typedef std::integral_constant::value > 1) #endif - > - use_align; + >; if (!pre_aligned) { ptr = align_usertype_pointer(ptr); } @@ -138,14 +136,13 @@ namespace sol { template inline void* align_usertype_unique_tag(void* ptr) { - typedef std::integral_constant::value > 1) #endif - > - use_align; + >; if (!pre_aligned) { ptr = align_usertype_unique_destructor(ptr); } @@ -590,7 +587,9 @@ namespace sol { template struct qualified_getter; template - struct userdata_getter; + struct qualified_interop_getter; + template + struct unqualified_interop_getter; template struct popper; template @@ -600,7 +599,9 @@ namespace sol { template ::value, typename = void> struct qualified_checker; template - struct userdata_checker; + struct qualified_interop_checker; + template + struct unqualified_interop_checker; template struct unqualified_check_getter; template @@ -646,6 +647,19 @@ namespace sol { static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; }; + template + struct is_adl_sol_lua_interop_get { + private: + template + static meta::sfinae_yes_t test( + std::remove_reference_t(), static_cast(nullptr), -1, static_cast(nullptr), std::declval()))>*); + template + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; + }; + template struct is_adl_sol_lua_check { private: @@ -659,6 +673,19 @@ namespace sol { static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; }; + template + struct is_adl_sol_lua_interop_check { + private: + template + static meta::sfinae_yes_t test(std::remove_reference_t(), static_cast(nullptr), -1, type::none, no_panic, std::declval()))>*); + template + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; + }; + template struct is_adl_sol_lua_check_get { private: @@ -700,9 +727,15 @@ namespace sol { template inline constexpr bool is_adl_sol_lua_get_v = is_adl_sol_lua_get::value; + template + inline constexpr bool is_adl_sol_lua_interop_get_v = is_adl_sol_lua_interop_get::value; + template inline constexpr bool is_adl_sol_lua_check_v = is_adl_sol_lua_check::value; + template + inline constexpr bool is_adl_sol_lua_interop_check_v = is_adl_sol_lua_interop_check::value; + template inline constexpr bool is_adl_sol_lua_check_get_v = is_adl_sol_lua_check_get::value; @@ -792,6 +825,58 @@ namespace sol { return g.get(L, index, tracking); } } + + template + inline decltype(auto) unqualified_interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { + using Tu = meta::unqualified_t; + if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v) { + return sol_lua_interop_get(types(), L, index, unadjusted_pointer, tracking); + } + else { + unqualified_interop_getter g{}; + (void)g; + return g.get(L, index, unadjusted_pointer, tracking); + } + } + + template + inline decltype(auto) interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { + if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v) { + return sol_lua_interop_get(types(), L, index, unadjusted_pointer, tracking); + } + else { + qualified_interop_getter g{}; + (void)g; + return g.get(L, index, unadjusted_pointer, tracking); + } + } + + template + bool unqualified_interop_check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { + using Tu = meta::unqualified_t; + if constexpr (meta::meta_detail::is_adl_sol_lua_interop_check_v) { + return sol_lua_interop_check(types(), L, index, index_type, std::forward(handler), tracking); + } + else { + unqualified_interop_checker c; + // VC++ has a bad warning here: shut it up + (void)c; + return c.check(L, index, index_type, std::forward(handler), tracking); + } + } + + template + bool interop_check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { + if constexpr (meta::meta_detail::is_adl_sol_lua_interop_check_v) { + return sol_lua_interop_check(types(), L, index, index_type, std::forward(handler), tracking); + } + else { + qualified_interop_checker c; + // VC++ has a bad warning here: shut it up + (void)c; + return c.check(L, index, index_type, std::forward(handler), tracking); + } + } } // namespace stack_detail inline bool maybe_indexable(lua_State* L, int index = -1) { @@ -868,11 +953,10 @@ namespace sol { template inline int push_reference(lua_State* L, Arg&& arg, Args&&... args) { - typedef meta::all, + using use_reference_tag = meta::all, meta::neg>, meta::neg>>, - meta::neg>>> - use_reference_tag; + meta::neg>>>; using Tr = meta::conditional_t>; return stack::push(L, std::forward(arg), std::forward(args)...); } @@ -913,6 +997,32 @@ namespace sol { return pushcount; } + template + bool unqualified_check(lua_State* L, int index, Handler&& handler, record& tracking) { + using Tu = meta::unqualified_t; + if constexpr (meta::meta_detail::is_adl_sol_lua_check_v) { + return sol_lua_check(types(), L, index, std::forward(handler), tracking); + } + else { + unqualified_checker c; + // VC++ has a bad warning here: shut it up + (void)c; + return c.check(L, index, std::forward(handler), tracking); + } + } + + template + bool unqualified_check(lua_State* L, int index, Handler&& handler) { + record tracking{}; + return unqualified_check(L, index, std::forward(handler), tracking); + } + + template + bool unqualified_check(lua_State* L, int index = -lua_size>::value) { + auto handler = no_panic; + return unqualified_check(L, index, handler); + } + template bool check(lua_State* L, int index, Handler&& handler, record& tracking) { if constexpr (meta::meta_detail::is_adl_sol_lua_check_v) { @@ -938,32 +1048,6 @@ namespace sol { return check(L, index, handler); } - template - bool unqualified_check(lua_State* L, int index, Handler&& handler, record& tracking) { - typedef meta::unqualified_t Tu; - if constexpr (meta::meta_detail::is_adl_sol_lua_check_v) { - return sol_lua_check(types(), L, index, std::forward(handler), tracking); - } - else { - unqualified_checker c; - // VC++ has a bad warning here: shut it up - (void)c; - return c.check(L, index, std::forward(handler), tracking); - } - } - - template - bool unqualified_check(lua_State* L, int index, Handler&& handler) { - record tracking{}; - return unqualified_check(L, index, std::forward(handler), tracking); - } - - template - bool unqualified_check(lua_State* L, int index = -lua_size>::value) { - auto handler = no_panic; - return unqualified_check(L, index, handler); - } - template bool check_usertype(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { using Tu = meta::unqualified_t; @@ -1067,6 +1151,8 @@ namespace sol { } }; + + } // namespace stack_detail template @@ -1159,7 +1245,6 @@ namespace sol { return get(L, index, tracking); } - template inline decltype(auto) get_usertype(lua_State* L, int index, record& tracking) { using UT = meta::conditional_t::value, detail::as_pointer_tag>, detail::as_value_tag>; @@ -1239,7 +1324,7 @@ namespace sol { template inline void modify_unique_usertype_as(const stack_reference& obj, F&& f) { - typedef unique_usertype_traits u_traits; + using u_traits = unique_usertype_traits; void* raw = lua_touserdata(obj.lua_state(), obj.stack_index()); void* ptr_memory = detail::align_usertype_pointer(raw); void* uu_memory = detail::align_usertype_unique(raw); @@ -1250,9 +1335,10 @@ namespace sol { template inline void modify_unique_usertype(const stack_reference& obj, F&& f) { - typedef meta::bind_traits> bt; - typedef typename bt::template arg_at<0> T; - modify_unique_usertype_as>(obj, std::forward(f)); + using bt = meta::bind_traits>; + using T = typename bt::template arg_at<0>; + using Tu = meta::unqualified_t; + modify_unique_usertype_as(obj, std::forward(f)); } } // namespace stack diff --git a/include/sol/stack_get_unqualified.hpp b/include/sol/stack_get_unqualified.hpp index 34887d06..ad3c91c5 100644 --- a/include/sol/stack_get_unqualified.hpp +++ b/include/sol/stack_get_unqualified.hpp @@ -97,7 +97,7 @@ namespace sol { namespace stack { template inline S get_into(lua_State* L, int index, record& tracking) { - typedef typename S::value_type Ch; + using Ch = typename S::value_type; tracking.use(1); size_t len; auto utf8p = lua_tolstring(L, index, &len); @@ -114,16 +114,7 @@ namespace sol { namespace stack { convert(strb, stre, copy_units); return r; } - } - - template - struct userdata_getter { - typedef stack_detail::strip_extensible_t T; - - static std::pair get(lua_State*, int, void*, record&) { - return { false, nullptr }; - } - }; + } // namespace stack_detail template struct unqualified_getter { @@ -139,6 +130,22 @@ namespace sol { namespace stack { } }; + template + struct unqualified_interop_getter { + using T = stack_detail::strip_extensible_t; + + static std::pair get(lua_State*, int, void*, record&) { + return { false, nullptr }; + } + }; + + template + struct qualified_interop_getter { + static decltype(auto) get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { + return stack_detail::unqualified_interop_get(L, index, unadjusted_pointer, tracking); + } + }; + template struct unqualified_getter::value>> { static T get(lua_State* L, int index, record& tracking) { @@ -796,9 +803,7 @@ namespace sol { namespace stack { static T* get_no_lua_nil(lua_State* L, int index, record& tracking) { void* memory = lua_touserdata(L, index); #if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP - userdata_getter> ug; - (void)ug; - auto ugr = ug.get(L, index, memory, tracking); + auto ugr = stack_detail::interop_get(L, index, memory, tracking); if (ugr.first) { return ugr.second; } @@ -951,9 +956,9 @@ namespace sol { namespace stack { return V(); } else { - using T = std::variant_alternative_t<0, V>; + //using T = std::variant_alternative_t<0, V>; std::abort(); - /*return V(std::in_place_index<0>, stack::get(L, index, tracking));*/ + //return V(std::in_place_index<0>, stack::get(L, index, tracking)); } } diff --git a/single/include/sol/forward.hpp b/single/include/sol/forward.hpp index e3bd1163..1673b895 100644 --- a/single/include/sol/forward.hpp +++ b/single/include/sol/forward.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2019-02-11 10:50:20.059748 UTC -// This header was generated with sol v2.20.6 (revision 4fd197d) +// Generated 2019-02-14 07:36:40.809154 UTC +// This header was generated with sol v2.20.6 (revision ffe77cc) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP diff --git a/single/include/sol/sol.hpp b/single/include/sol/sol.hpp index a5b50df1..37c3b8c1 100644 --- a/single/include/sol/sol.hpp +++ b/single/include/sol/sol.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2019-02-11 10:50:18.478770 UTC -// This header was generated with sol v2.20.6 (revision 4fd197d) +// Generated 2019-02-14 07:36:40.566598 UTC +// This header was generated with sol v2.20.6 (revision ffe77cc) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -4485,20 +4485,26 @@ namespace sol { /// \synopsis template optional(const optional &rhs); template * = nullptr, detail::enable_if_t::value>* = nullptr> optional(const optional& rhs) { - this->construct(*rhs); + if (rhs.has_value()) { + this->construct(*rhs); + } } /// \exclude template * = nullptr, detail::enable_if_t::value>* = nullptr> explicit optional(const optional& rhs) { - this->construct(*rhs); + if (rhs.has_value()) { + this->construct(*rhs); + } } /// Converting move constructor. /// \synopsis template optional(optional &&rhs); template * = nullptr, detail::enable_if_t::value>* = nullptr> optional(optional&& rhs) { - this->construct(std::move(*rhs)); + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } } /// \exclude @@ -5847,7 +5853,7 @@ namespace sol { namespace detail { template >, ebco> && !std::is_same_v>, T>>> - ebco(Arg&& arg, Args&&... args) : T(std::forward(arg), std::forward(args)...){}; + ebco(Arg&& arg, Args&&... args) : T(std::forward(arg), std::forward(args)...){} T& value() { return value_; @@ -5868,7 +5874,7 @@ namespace sol { namespace detail { template >, ebco> && !std::is_same_v>, T>>> - ebco(Arg&& arg, Args&&... args) : T(std::forward(arg), std::forward(args)...){}; + ebco(Arg&& arg, Args&&... args) : T(std::forward(arg), std::forward(args)...){} ebco& operator=(const ebco&) = default; ebco& operator=(ebco&&) = default; @@ -8751,14 +8757,13 @@ namespace sol { } inline void* align_usertype_pointer(void* ptr) { - typedef std::integral_constant::value > 1) #endif - > - use_align; + >; if (!use_align::value) { return ptr; } @@ -8768,14 +8773,13 @@ namespace sol { template inline void* align_usertype_unique_destructor(void* ptr) { - typedef std::integral_constant::value > 1) #endif - > - use_align; + >; if (!pre_aligned) { ptr = align_usertype_pointer(ptr); } @@ -8791,14 +8795,13 @@ namespace sol { template inline void* align_usertype_unique_tag(void* ptr) { - typedef std::integral_constant::value > 1) #endif - > - use_align; + >; if (!pre_aligned) { ptr = align_usertype_unique_destructor(ptr); } @@ -9243,7 +9246,9 @@ namespace sol { template struct qualified_getter; template - struct userdata_getter; + struct qualified_interop_getter; + template + struct unqualified_interop_getter; template struct popper; template @@ -9253,7 +9258,9 @@ namespace sol { template ::value, typename = void> struct qualified_checker; template - struct userdata_checker; + struct qualified_interop_checker; + template + struct unqualified_interop_checker; template struct unqualified_check_getter; template @@ -9299,6 +9306,19 @@ namespace sol { static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; }; + template + struct is_adl_sol_lua_interop_get { + private: + template + static meta::sfinae_yes_t test( + std::remove_reference_t(), static_cast(nullptr), -1, static_cast(nullptr), std::declval()))>*); + template + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; + }; + template struct is_adl_sol_lua_check { private: @@ -9312,6 +9332,19 @@ namespace sol { static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; }; + template + struct is_adl_sol_lua_interop_check { + private: + template + static meta::sfinae_yes_t test(std::remove_reference_t(), static_cast(nullptr), -1, type::none, no_panic, std::declval()))>*); + template + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; + }; + template struct is_adl_sol_lua_check_get { private: @@ -9353,9 +9386,15 @@ namespace sol { template inline constexpr bool is_adl_sol_lua_get_v = is_adl_sol_lua_get::value; + template + inline constexpr bool is_adl_sol_lua_interop_get_v = is_adl_sol_lua_interop_get::value; + template inline constexpr bool is_adl_sol_lua_check_v = is_adl_sol_lua_check::value; + template + inline constexpr bool is_adl_sol_lua_interop_check_v = is_adl_sol_lua_interop_check::value; + template inline constexpr bool is_adl_sol_lua_check_get_v = is_adl_sol_lua_check_get::value; @@ -9444,6 +9483,58 @@ namespace sol { return g.get(L, index, tracking); } } + + template + inline decltype(auto) unqualified_interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { + using Tu = meta::unqualified_t; + if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v) { + return sol_lua_interop_get(types(), L, index, unadjusted_pointer, tracking); + } + else { + unqualified_interop_getter g{}; + (void)g; + return g.get(L, index, unadjusted_pointer, tracking); + } + } + + template + inline decltype(auto) interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { + if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v) { + return sol_lua_interop_get(types(), L, index, unadjusted_pointer, tracking); + } + else { + qualified_interop_getter g{}; + (void)g; + return g.get(L, index, unadjusted_pointer, tracking); + } + } + + template + bool unqualified_interop_check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { + using Tu = meta::unqualified_t; + if constexpr (meta::meta_detail::is_adl_sol_lua_interop_check_v) { + return sol_lua_interop_check(types(), L, index, index_type, std::forward(handler), tracking); + } + else { + unqualified_interop_checker c; + // VC++ has a bad warning here: shut it up + (void)c; + return c.check(L, index, index_type, std::forward(handler), tracking); + } + } + + template + bool interop_check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { + if constexpr (meta::meta_detail::is_adl_sol_lua_interop_check_v) { + return sol_lua_interop_check(types(), L, index, index_type, std::forward(handler), tracking); + } + else { + qualified_interop_checker c; + // VC++ has a bad warning here: shut it up + (void)c; + return c.check(L, index, index_type, std::forward(handler), tracking); + } + } } // namespace stack_detail inline bool maybe_indexable(lua_State* L, int index = -1) { @@ -9520,11 +9611,10 @@ namespace sol { template inline int push_reference(lua_State* L, Arg&& arg, Args&&... args) { - typedef meta::all, + using use_reference_tag = meta::all, meta::neg>, meta::neg>>, - meta::neg>>> - use_reference_tag; + meta::neg>>>; using Tr = meta::conditional_t>; return stack::push(L, std::forward(arg), std::forward(args)...); } @@ -9565,6 +9655,32 @@ namespace sol { return pushcount; } + template + bool unqualified_check(lua_State* L, int index, Handler&& handler, record& tracking) { + using Tu = meta::unqualified_t; + if constexpr (meta::meta_detail::is_adl_sol_lua_check_v) { + return sol_lua_check(types(), L, index, std::forward(handler), tracking); + } + else { + unqualified_checker c; + // VC++ has a bad warning here: shut it up + (void)c; + return c.check(L, index, std::forward(handler), tracking); + } + } + + template + bool unqualified_check(lua_State* L, int index, Handler&& handler) { + record tracking{}; + return unqualified_check(L, index, std::forward(handler), tracking); + } + + template + bool unqualified_check(lua_State* L, int index = -lua_size>::value) { + auto handler = no_panic; + return unqualified_check(L, index, handler); + } + template bool check(lua_State* L, int index, Handler&& handler, record& tracking) { if constexpr (meta::meta_detail::is_adl_sol_lua_check_v) { @@ -9590,32 +9706,6 @@ namespace sol { return check(L, index, handler); } - template - bool unqualified_check(lua_State* L, int index, Handler&& handler, record& tracking) { - typedef meta::unqualified_t Tu; - if constexpr (meta::meta_detail::is_adl_sol_lua_check_v) { - return sol_lua_check(types(), L, index, std::forward(handler), tracking); - } - else { - unqualified_checker c; - // VC++ has a bad warning here: shut it up - (void)c; - return c.check(L, index, std::forward(handler), tracking); - } - } - - template - bool unqualified_check(lua_State* L, int index, Handler&& handler) { - record tracking{}; - return unqualified_check(L, index, std::forward(handler), tracking); - } - - template - bool unqualified_check(lua_State* L, int index = -lua_size>::value) { - auto handler = no_panic; - return unqualified_check(L, index, handler); - } - template bool check_usertype(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { using Tu = meta::unqualified_t; @@ -9890,7 +9980,7 @@ namespace sol { template inline void modify_unique_usertype_as(const stack_reference& obj, F&& f) { - typedef unique_usertype_traits u_traits; + using u_traits = unique_usertype_traits; void* raw = lua_touserdata(obj.lua_state(), obj.stack_index()); void* ptr_memory = detail::align_usertype_pointer(raw); void* uu_memory = detail::align_usertype_unique(raw); @@ -9901,9 +9991,10 @@ namespace sol { template inline void modify_unique_usertype(const stack_reference& obj, F&& f) { - typedef meta::bind_traits> bt; - typedef typename bt::template arg_at<0> T; - modify_unique_usertype_as>(obj, std::forward(f)); + using bt = meta::bind_traits>; + using T = typename bt::template arg_at<0>; + using Tu = meta::unqualified_t; + modify_unique_usertype_as(obj, std::forward(f)); } } // namespace stack @@ -10098,13 +10189,21 @@ namespace sol { namespace stack { } // namespace stack_detail template - struct userdata_checker { + struct unqualified_interop_checker { template static bool check(lua_State*, int, type, Handler&&, record&) { return false; } }; + template + struct qualified_interop_checker { + template + static bool check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { + return stack_detail::unqualified_interop_check(L, index, index_type, std::forward(handler), tracking); + } + }; + template struct unqualified_checker { template @@ -10473,15 +10572,13 @@ namespace sol { namespace stack { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { const type indextype = type_of(L, index); - return check(types(), L, index, indextype, handler, tracking); + return check(types(), L, index, indextype, std::forward(handler), tracking); } template static bool check(types, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { #if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP - userdata_checker> uc; - (void)uc; - if (uc.check(L, index, indextype, handler, tracking)) { + if (stack_detail::interop_check(L, index, indextype, handler, tracking)) { return true; } #endif // interop extensibility @@ -10490,8 +10587,7 @@ namespace sol { namespace stack { handler(L, index, type::userdata, indextype, "value is not a valid userdata"); return false; } - if (meta::any, std::is_same, std::is_same, std::is_same>:: - value) + if (meta::any, std::is_same, std::is_same, std::is_same>::value) return true; if (lua_getmetatable(L, index) == 0) { return true; @@ -11175,7 +11271,7 @@ namespace sol { namespace stack { template inline S get_into(lua_State* L, int index, record& tracking) { - typedef typename S::value_type Ch; + using Ch = typename S::value_type; tracking.use(1); size_t len; auto utf8p = lua_tolstring(L, index, &len); @@ -11192,16 +11288,7 @@ namespace sol { namespace stack { convert(strb, stre, copy_units); return r; } - } - - template - struct userdata_getter { - typedef stack_detail::strip_extensible_t T; - - static std::pair get(lua_State*, int, void*, record&) { - return { false, nullptr }; - } - }; + } // namespace stack_detail template struct unqualified_getter { @@ -11217,6 +11304,22 @@ namespace sol { namespace stack { } }; + template + struct unqualified_interop_getter { + using T = stack_detail::strip_extensible_t; + + static std::pair get(lua_State*, int, void*, record&) { + return { false, nullptr }; + } + }; + + template + struct qualified_interop_getter { + static decltype(auto) get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { + return stack_detail::unqualified_interop_get(L, index, unadjusted_pointer, tracking); + } + }; + template struct unqualified_getter::value>> { static T get(lua_State* L, int index, record& tracking) { @@ -11874,9 +11977,7 @@ namespace sol { namespace stack { static T* get_no_lua_nil(lua_State* L, int index, record& tracking) { void* memory = lua_touserdata(L, index); #if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP - userdata_getter> ug; - (void)ug; - auto ugr = ug.get(L, index, memory, tracking); + auto ugr = stack_detail::interop_get(L, index, memory, tracking); if (ugr.first) { return ugr.second; } @@ -12028,9 +12129,9 @@ namespace sol { namespace stack { return V(); } else { - using T = std::variant_alternative_t<0, V>; + //using T = std::variant_alternative_t<0, V>; std::abort(); - /*return V(std::in_place_index<0>, stack::get(L, index, tracking));*/ + //return V(std::in_place_index<0>, stack::get(L, index, tracking)); } } diff --git a/tests/runtime_tests/CMakeLists.txt b/tests/runtime_tests/CMakeLists.txt index 43f57c57..ac4ad440 100644 --- a/tests/runtime_tests/CMakeLists.txt +++ b/tests/runtime_tests/CMakeLists.txt @@ -48,7 +48,7 @@ function(CREATE_TEST test_target_name test_name target_sol) else() target_compile_options(${test_target_name} PRIVATE -std=c++1z - -Wall -Wpendatic -Werror -pedantic -pedantic-errors + -Wall -Wpedantic -Werror -pedantic -pedantic-errors -Wno-noexcept-type -pthread -Wno-unknown-warning -Wno-unknown-warning-option) diff --git a/tests/runtime_tests/source/common_classes.hpp b/tests/runtime_tests/source/common_classes.hpp index 653176ee..42b8a797 100644 --- a/tests/runtime_tests/source/common_classes.hpp +++ b/tests/runtime_tests/source/common_classes.hpp @@ -26,6 +26,31 @@ #include +struct woof { + int var; + + int func(int x) { + return var + x; + } + + double func2(int x, int y) { + return var + x + y + 0.5; + } + + std::string func2s(int x, std::string y) { + return y + " " + std::to_string(x); + } +}; + +struct thing { + int v = 100; + + thing() { + } + thing(int x) : v(x) { + } +}; + struct non_copyable { non_copyable() = default; non_copyable(non_copyable&& other) noexcept = default; diff --git a/tests/runtime_tests/source/container_semantics.cpp b/tests/runtime_tests/source/container_semantics.cpp index 285aff85..6f9da795 100644 --- a/tests/runtime_tests/source/container_semantics.cpp +++ b/tests/runtime_tests/source/container_semantics.cpp @@ -33,112 +33,8 @@ #include #include #include -#include -#include #include // std::iota -struct my_object { -private: - std::vector mdata; - -public: - static const void* last_printed; - - my_object(int sz) - : mdata() { - mdata.resize(sz); - std::iota(mdata.begin(), mdata.end(), 1); - } - - void operator()(std::size_t count, int value) { - for (; count > 0; --count) { - mdata.push_back(value); - } - } - -public: // Container requirements, as per the C++ standard - using value_type = int; - using reference = value_type&; - using const_reference = const value_type&; - using iterator = decltype(mdata)::iterator; - using const_iterator = decltype(mdata)::const_iterator; - using difference_type = decltype(mdata)::difference_type; - using size_type = decltype(mdata)::size_type; - - iterator begin() { - return iterator(mdata.begin()); - } - iterator end() { - return iterator(mdata.end()); - } - const_iterator begin() const { - return const_iterator(mdata.begin()); - } - const_iterator end() const { - return const_iterator(mdata.end()); - } - const_iterator cbegin() const { - return begin(); - } - const_iterator cend() const { - return end(); - } - size_type size() const noexcept { - return mdata.size(); - } - size_type max_size() const noexcept { - return mdata.max_size(); - } - void push_back(const value_type& v) { - mdata.push_back(v); - } - void insert(const_iterator where, const value_type& v) { - mdata.insert(where, v); - } - bool empty() const noexcept { - return mdata.empty(); - } - bool operator==(const my_object& right) const { - return mdata == right.mdata; - } - bool operator!=(const my_object& right) const noexcept { - return mdata != right.mdata; - } - - std::vector& data() { - return mdata; - } - - const std::vector& data() const { - return mdata; - } -}; - -const void* my_object::last_printed = nullptr; - -std::ostream& operator<<(std::ostream& ostr, const my_object& mo) { - my_object::last_printed = static_cast(&mo); - ostr << "{ "; - const auto& v = mo.data(); - if (v.empty()) { - ostr << "empty"; - } - else { - ostr << v[0]; - for (std::size_t i = 1; i < v.size(); ++i) { - ostr << ", " << v[i]; - } - } - ostr << " }"; - - return ostr; -} - -namespace sol { - template <> - struct is_container : std::false_type {}; -} // namespace sol - template void sequence_container_check(sol::state& lua, T& items) { { @@ -152,62 +48,52 @@ end REQUIRE(r1.valid()); } { - auto ffind = [&]() { - auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto findex_of = [&]() { - auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto fget = [&]() { - auto r1 = lua.safe_script("v1 = c:get(1)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("v2 = c:get(3)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto fset = [&]() { - auto r1 = lua.safe_script("c:set(2, 20)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("c:set(6, 16)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto ferase = [&]() { - auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error); - REQUIRE(r5.valid()); - auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error); - REQUIRE(r3.valid()); - auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error); - REQUIRE(r4.valid()); - }; - auto fadd = [&]() { - auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - auto fopset = [&]() { - auto r = lua.safe_script("c[#c + 1] = 18", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - auto fopget = [&]() { - auto r = lua.safe_script("v3 = c[#c]", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - REQUIRE_NOTHROW(ffind()); - REQUIRE_NOTHROW(findex_of()); - REQUIRE_NOTHROW(fget()); - REQUIRE_NOTHROW(fset()); - REQUIRE_NOTHROW(ferase()); - REQUIRE_NOTHROW(fadd()); - REQUIRE_NOTHROW(fopset()); - REQUIRE_NOTHROW(fopget()); + auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("v1 = c:get(1)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("v2 = c:get(3)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("c:set(2, 20)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("c:set(6, 16)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error); + REQUIRE(r5.valid()); + auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error); + REQUIRE(r3.valid()); + auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error); + REQUIRE(r4.valid()); + } + { + auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + { + auto r = lua.safe_script("c[#c + 1] = 18", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + { + auto r = lua.safe_script("v3 = c[#c]", sol::script_pass_on_error); + REQUIRE(r.valid()); } auto backit = items.begin(); std::size_t len = 0; @@ -260,469 +146,6 @@ end REQUIRE((v3 == 18)); } -template -void ordered_container_check(sol::state& lua, T& items) { - { - auto r1 = lua.safe_script(R"( -for i=1,#c do - v = c[(i + 10)] - assert(v == (i + 10)) -end - )", - sol::script_pass_on_error); - REQUIRE(r1.valid()); - } - { - auto ffind = [&]() { - auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto findex_of = [&]() { - auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto fget = [&]() { - auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto fset = [&]() { - auto r1 = lua.safe_script("c:set(20)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("c:set(16)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto ferase = [&]() { - auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error); - REQUIRE(r5.valid()); - auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error); - REQUIRE(r3.valid()); - auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error); - REQUIRE(r4.valid()); - }; - auto fadd = [&]() { - auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - auto fopset = [&]() { - auto r = lua.safe_script("c[18] = true", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - auto fopget = [&]() { - auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - REQUIRE_NOTHROW(ffind()); - REQUIRE_NOTHROW(findex_of()); - REQUIRE_NOTHROW(fget()); - REQUIRE_NOTHROW(fset()); - REQUIRE_NOTHROW(ferase()); - REQUIRE_NOTHROW(fadd()); - REQUIRE_NOTHROW(fopset()); - REQUIRE_NOTHROW(fopget()); - } - auto backit = items.begin(); - std::size_t len = 0; - { - auto e = items.end(); - auto last = backit; - for (; backit != e; ++backit, ++len) { - if (backit == e) { - break; - } - last = backit; - } - backit = last; - } - const int& first = *items.begin(); - const int& last = *backit; - int i1 = lua["i1"]; - int i2 = lua["i2"]; - int io1 = lua["io1"]; - int io2 = lua["io2"]; - std::size_t s1 = lua["s1"]; - std::size_t s2 = lua["s2"]; - std::size_t s3 = lua["s3"]; - int v1 = lua["v1"]; - int v2 = lua["v2"]; - int v3 = lua["v3"]; - int values[] = { - 12, 13, 15, 16, 17, 18, 20 - }; - { - std::size_t idx = 0; - for (const auto& i : items) { - const auto& v = values[idx]; - REQUIRE((i == v)); - ++idx; - } - } - REQUIRE((s1 == 7)); - REQUIRE((s2 == 6)); - REQUIRE((s3 == 5)); - REQUIRE((len == 7)); - REQUIRE((first == 12)); - REQUIRE((last == 20)); - REQUIRE((i1 == 11)); - REQUIRE((i2 == 14)); - REQUIRE((io1 == 2)); - REQUIRE((io2 == 3)); - REQUIRE((v1 == 11)); - REQUIRE((v2 == 13)); - REQUIRE((v3 == 20)); -} - -template -void unordered_container_check(sol::state& lua, T& items) { - { - auto ffind = [&]() { - auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto findex_of = [&]() { - auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); - REQUIRE_FALSE(r1.valid()); - auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); - REQUIRE_FALSE(r2.valid()); - }; - auto fget = [&]() { - auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto fset = [&]() { - auto r1 = lua.safe_script("c:set(20)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("c:set(16)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto ferase = [&]() { - auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error); - REQUIRE(r5.valid()); - auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error); - REQUIRE(r3.valid()); - auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error); - REQUIRE(r4.valid()); - }; - auto fadd = [&]() { - auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - auto fopset = [&]() { - auto r = lua.safe_script("c[18] = true", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - auto fopget = [&]() { - auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - REQUIRE_NOTHROW(ffind()); - REQUIRE_NOTHROW(findex_of()); - REQUIRE_NOTHROW(fget()); - REQUIRE_NOTHROW(fset()); - REQUIRE_NOTHROW(ferase()); - REQUIRE_NOTHROW(fadd()); - REQUIRE_NOTHROW(fopset()); - REQUIRE_NOTHROW(fopget()); - } - std::size_t len = items.size(); - int i1 = lua["i1"]; - int i2 = lua["i2"]; - std::size_t s1 = lua["s1"]; - std::size_t s2 = lua["s2"]; - std::size_t s3 = lua["s3"]; - int v1 = lua["v1"]; - int v2 = lua["v2"]; - int v3 = lua["v3"]; - int values[] = { - 12, 13, 15, 16, 17, 18, 20 - }; - { - for (const auto& v : values) { - auto it = items.find(v); - REQUIRE((it != items.cend())); - REQUIRE((*it == v)); - } - } - REQUIRE((s1 == 7)); - REQUIRE((s2 == 6)); - REQUIRE((s3 == 5)); - REQUIRE((len == 7)); - REQUIRE((i1 == 11)); - REQUIRE((i2 == 14)); - REQUIRE((v1 == 11)); - REQUIRE((v2 == 13)); - REQUIRE((v3 == 20)); -} - -template -void associative_ordered_container_check(sol::state& lua, T& items) { - { - auto r1 = lua.safe_script(R"( -for i=1,#c do - v = c[(i + 10)] - assert(v == (i + 20)) -end - )", - sol::script_pass_on_error); - REQUIRE(r1.valid()); - } - { - auto ffind = [&]() { - auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto findex_of = [&]() { - auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto fget = [&]() { - auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto fset = [&]() { - auto r1 = lua.safe_script("c:set(20, 30)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("c:set(16, 26)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - auto r3 = lua.safe_script("c:set(12, 31)", sol::script_pass_on_error); - REQUIRE(r3.valid()); - }; - auto ferase = [&]() { - auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error); - REQUIRE(r5.valid()); - auto r1 = lua.safe_script("c:erase(11)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error); - REQUIRE(r3.valid()); - auto r2 = lua.safe_script("c:erase(14)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error); - REQUIRE(r4.valid()); - }; - auto fadd = [&]() { - auto r = lua.safe_script("c:add(17, 27)", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - auto fopset = [&]() { - auto r = lua.safe_script("c[18] = 28", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - auto fopget = [&]() { - auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - REQUIRE_NOTHROW(ffind()); - REQUIRE_NOTHROW(findex_of()); - REQUIRE_NOTHROW(fget()); - REQUIRE_NOTHROW(fset()); - REQUIRE_NOTHROW(ferase()); - REQUIRE_NOTHROW(fadd()); - REQUIRE_NOTHROW(fopset()); - REQUIRE_NOTHROW(fopget()); - } - auto backit = items.begin(); - std::size_t len = 0; - { - auto e = items.end(); - auto last = backit; - for (; backit != e; ++backit, ++len) { - if (backit == e) { - break; - } - last = backit; - } - backit = last; - } - const std::pair& first = *items.begin(); - const std::pair& last = *backit; - int i1 = lua["i1"]; - int i2 = lua["i2"]; - int io1 = lua["io1"]; - int io2 = lua["io2"]; - std::size_t s1 = lua["s1"]; - std::size_t s2 = lua["s2"]; - std::size_t s3 = lua["s3"]; - int v1 = lua["v1"]; - int v2 = lua["v2"]; - int v3 = lua["v3"]; - std::pair values[] = { - { (short)12, 31 }, - { (short)13, 23 }, - { (short)15, 25 }, - { (short)16, 26 }, - { (short)17, 27 }, - { (short)18, 28 }, - { (short)20, 30 } - }; - { - std::size_t idx = 0; - for (const auto& i : items) { - const auto& v = values[idx]; - REQUIRE((i == v)); - ++idx; - } - } - REQUIRE((s1 == 7)); - REQUIRE((s2 == 6)); - REQUIRE((s3 == 5)); - REQUIRE((len == 7)); - REQUIRE((first.first == 12)); - REQUIRE((last.first == 20)); - REQUIRE((first.second == 31)); - REQUIRE((last.second == 30)); - REQUIRE((i1 == 21)); - REQUIRE((i2 == 24)); - REQUIRE((io1 == 2)); - REQUIRE((io2 == 3)); - REQUIRE((v1 == 21)); - REQUIRE((v2 == 23)); - REQUIRE((v3 == 30)); -} - -template -void associative_unordered_container_check(sol::state& lua, T& items) { - { - auto ffind = [&]() { - auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto findex_of = [&]() { - auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); - REQUIRE_FALSE(r1.valid()); - auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); - REQUIRE_FALSE(r2.valid()); - }; - auto fget = [&]() { - auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto fset = [&]() { - auto r1 = lua.safe_script("c:set(20, 30)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("c:set(16, 26)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - auto r3 = lua.safe_script("c:set(12, 31)", sol::script_pass_on_error); - REQUIRE(r3.valid()); - }; - auto ferase = [&]() { - auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error); - REQUIRE(r5.valid()); - auto r1 = lua.safe_script("c:erase(11)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error); - REQUIRE(r3.valid()); - auto r2 = lua.safe_script("c:erase(14)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error); - REQUIRE(r4.valid()); - }; - auto fadd = [&]() { - auto r = lua.safe_script("c:add(17, 27)", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - auto fopset = [&]() { - auto r = lua.safe_script("c[18] = 28", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - auto fopget = [&]() { - auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - REQUIRE_NOTHROW(ffind()); - REQUIRE_NOTHROW(findex_of()); - REQUIRE_NOTHROW(fget()); - REQUIRE_NOTHROW(fset()); - REQUIRE_NOTHROW(ferase()); - REQUIRE_NOTHROW(fadd()); - REQUIRE_NOTHROW(fopset()); - REQUIRE_NOTHROW(fopget()); - } - std::size_t len = items.size(); - int i1 = lua["i1"]; - int i2 = lua["i2"]; - std::size_t s1 = lua["s1"]; - std::size_t s2 = lua["s2"]; - std::size_t s3 = lua["s3"]; - int v1 = lua["v1"]; - int v2 = lua["v2"]; - int v3 = lua["v3"]; - std::pair values[] = { - { (short)12, 31 }, - { (short)13, 23 }, - { (short)15, 25 }, - { (short)16, 26 }, - { (short)17, 27 }, - { (short)18, 28 }, - { (short)20, 30 } - }; - { - for (const auto& v : values) { - auto it = items.find(v.first); - REQUIRE((it != items.cend())); - REQUIRE((it->second == v.second)); - } - } - REQUIRE((s1 == 7)); - REQUIRE((s2 == 6)); - REQUIRE((s3 == 5)); - REQUIRE((len == 7)); - REQUIRE((i1 == 21)); - REQUIRE((i2 == 24)); - REQUIRE((v1 == 21)); - REQUIRE((v2 == 23)); - REQUIRE((v3 == 30)); -} - -template -void associative_ordered_container_key_value_check(sol::state& lua, T& data, T& reflect) { - typedef typename T::key_type K; - typedef typename T::mapped_type V; - lua["collect"] = [&reflect](K k, V v) { - reflect.insert({ k, v }); - }; - -#if SOL_LUA_VERSION > 502 - lua["val"] = data; - auto r = lua.safe_script(R"( -for k, v in pairs(val) do - collect(k, v) -end -print() -)", sol::script_pass_on_error); - REQUIRE(r.valid()); -#else - reflect = data; -#endif - REQUIRE((data == reflect)); -} - template void fixed_container_check(sol::state& lua, T& items) { { @@ -735,62 +158,52 @@ end REQUIRE(r1.valid()); } { - auto ffind = [&]() { - auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto findex_of = [&]() { - auto r1 = lua.safe_script("io1 = c:index_of(11)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("io2 = c:index_of(14)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto fget = [&]() { - auto r1 = lua.safe_script("v1 = c:get(2)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("v2 = c:get(5)", sol::script_pass_on_error); - REQUIRE(r2.valid()); - }; - auto fset = [&]() { - auto r1 = lua.safe_script("c:set(2, 20)", sol::script_pass_on_error); - REQUIRE(r1.valid()); - auto r2 = lua.safe_script("c:set(6, 16)", sol::script_pass_on_error); - REQUIRE_FALSE(r2.valid()); - }; - auto ferase = [&]() { - auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error); - REQUIRE(r5.valid()); - auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error); - REQUIRE_FALSE(r1.valid()); - auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error); - REQUIRE(r3.valid()); - auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error); - REQUIRE_FALSE(r2.valid()); - auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error); - REQUIRE(r4.valid()); - }; - auto fadd = [&]() { - auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error); - REQUIRE_FALSE(r.valid()); - }; - auto fopset = [&]() { - auto r = lua.safe_script("c[5] = 18", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - auto fopget = [&]() { - auto r = lua.safe_script("v3 = c[4]", sol::script_pass_on_error); - REQUIRE(r.valid()); - }; - REQUIRE_NOTHROW(ffind()); - REQUIRE_NOTHROW(findex_of()); - REQUIRE_NOTHROW(fget()); - REQUIRE_NOTHROW(fset()); - REQUIRE_NOTHROW(ferase()); - REQUIRE_NOTHROW(fadd()); - REQUIRE_NOTHROW(fopset()); - REQUIRE_NOTHROW(fopget()); + auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("io1 = c:index_of(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("io2 = c:index_of(14)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("v1 = c:get(2)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("v2 = c:get(5)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("c:set(2, 20)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("c:set(6, 16)", sol::script_pass_on_error); + REQUIRE_FALSE(r2.valid()); + } + { + auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error); + REQUIRE(r5.valid()); + auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error); + REQUIRE_FALSE(r1.valid()); + auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error); + REQUIRE(r3.valid()); + auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error); + REQUIRE_FALSE(r2.valid()); + auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error); + REQUIRE(r4.valid()); + } + { + auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error); + REQUIRE_FALSE(r.valid()); + } + { + auto r = lua.safe_script("c[5] = 18", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + { + auto r = lua.safe_script("v3 = c[4]", sol::script_pass_on_error); + REQUIRE(r.valid()); } auto backit = std::begin(items); std::size_t len = 0; @@ -839,16 +252,6 @@ end REQUIRE((v3 == 14)); } -template -void lookup_container_check(sol::state& lua, T&) { - auto result0 = lua.safe_script("assert(c['a'] == 'a')", sol::script_default_on_error); - REQUIRE(result0.valid()); - auto result1 = lua.safe_script("assert(c['b'] == 'b')", sol::script_default_on_error); - REQUIRE(result1.valid()); - auto result2 = lua.safe_script("assert(c['c'] == 'c')", sol::script_default_on_error); - REQUIRE(result2.valid()); -} - TEST_CASE("containers/sequence containers", "check all of the functinos for every single container") { SECTION("vector") { sol::state lua; @@ -919,209 +322,6 @@ TEST_CASE("containers/fixed containers", "check immutable container types") { } } -TEST_CASE("containers/ordered lookup containers", "check ordered container types") { - SECTION("set") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::set items{ 11, 12, 13, 14, 15 }; - lua["c"] = &items; - ordered_container_check(lua, items); - } - SECTION("set string") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::set items({ "a", "b", "c" }); - lua["c"] = &items; - lookup_container_check(lua, items); - } - SECTION("multiset") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::multiset items{ 11, 12, 13, 14, 15 }; - lua["c"] = &items; - ordered_container_check(lua, items); - } - SECTION("multiset string") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::multiset items({ "a", "b", "c" }); - lua["c"] = &items; - lookup_container_check(lua, items); - } -} - -TEST_CASE("containers/unordered lookup containers", "check ordered container types") { - SECTION("unordered_set") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::unordered_set items{ 11, 12, 13, 14, 15 }; - lua["c"] = &items; - unordered_container_check(lua, items); - } - SECTION("unordered_set string") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::unordered_set items({ "a", "b", "c" }); - lua["c"] = &items; - lookup_container_check(lua, items); - } - SECTION("unordered_multiset") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::unordered_multiset items{ 11, 12, 13, 14, 15 }; - lua["c"] = &items; - unordered_container_check(lua, items); - } - SECTION("unordered_multiset string") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::unordered_multiset items({ "a", "b", "c" }); - lua["c"] = &items; - lookup_container_check(lua, items); - } -} - -TEST_CASE("containers/associative ordered containers", "check associative (map) containers that are ordered fulfill basic functionality requirements") { - SECTION("map") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::map items{ - { (short)11, 21 }, - { (short)12, 22 }, - { (short)13, 23 }, - { (short)14, 24 }, - { (short)15, 25 } - }; - lua["c"] = &items; - associative_ordered_container_check(lua, items); - } - SECTION("map string") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::map items{ - { "a", "a" }, - { "b", "b" }, - { "c", "c" } - }; - lua["c"] = &items; - lookup_container_check(lua, items); - } - SECTION("multimap") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::multimap items{ - { (short)11, 21 }, - { (short)12, 22 }, - { (short)13, 23 }, - { (short)14, 24 }, - { (short)15, 25 } - }; - lua["c"] = &items; - associative_ordered_container_check(lua, items); - } - SECTION("multimap string") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::multimap items{ - { "a", "a" }, - { "b", "b" }, - { "c", "c" } - }; - lua["c"] = &items; - lookup_container_check(lua, items); - } -} - -TEST_CASE("containers/associative unordered containers", "check associative (map) containers that are ordered that they fulfill basic functionality requirements") { - SECTION("unordered_map") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::unordered_map items{ - { (short)11, 21 }, - { (short)12, 22 }, - { (short)13, 23 }, - { (short)14, 24 }, - { (short)15, 25 } - }; - lua["c"] = &items; - associative_unordered_container_check(lua, items); - } - SECTION("unordered_map string") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::unordered_map items{ - { "a", "a" }, - { "b", "b" }, - { "c", "c" } - }; - lua["c"] = &items; - lookup_container_check(lua, items); - } - SECTION("unordered_multimap") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::unordered_multimap items{ - { (short)11, 21 }, - { (short)12, 22 }, - { (short)13, 23 }, - { (short)14, 24 }, - { (short)15, 25 } - }; - lua["c"] = &items; - associative_unordered_container_check(lua, items); - } - SECTION("unordered_multimap string") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - std::unordered_multimap items{ - { "a", "a" }, - { "b", "b" }, - { "c", "c" } - }; - lua["c"] = &items; - lookup_container_check(lua, items); - } -} - -TEST_CASE("containers/associative ordered pairs", "check to make sure pairs works properly for key-value types") { - struct bar {}; - std::unique_ptr ua(new bar()), ub(new bar()), uc(new bar()); - bar* a = ua.get(); - bar* b = ub.get(); - bar* c = uc.get(); - - SECTION("map") { - sol::state lua; - lua.open_libraries(sol::lib::base); - std::map data({ { "a", a },{ "b", b },{ "c", c } }); - std::map reflect; - associative_ordered_container_key_value_check(lua, data, reflect); - } - SECTION("multimap") { - sol::state lua; - lua.open_libraries(sol::lib::base); - std::multimap data({ { "a", a },{ "b", b },{ "c", c } }); - std::multimap reflect; - associative_ordered_container_key_value_check(lua, data, reflect); - } -} - TEST_CASE("containers/auxiliary functions test", "make sure the manipulation functions are present and usable and working across various container types") { sol::state lua; lua.open_libraries(); @@ -1224,166 +424,3 @@ c_arr[-1] = 7 } #endif // Something is wrong with g++'s lower versions: it always fails this test... } - -TEST_CASE("containers/as_container reference", "test that we can force a container to be treated like one despite the trait being false using the proper marker") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_usertype("my_object", - sol::constructors(), - sol::call_constructor, sol::constructors(), - "size", &my_object::size, - "iterable", [](my_object& mo) { - return sol::as_container(mo); - }); - -#if SOL_LUA_VERSION > 501 - auto result1 = lua.safe_script(R"( -mop = my_object.new(20) -for i, v in pairs(mop) do - assert(i == v) -end -print(mop) - )", sol::script_pass_on_error); - REQUIRE(result1.valid()); - REQUIRE_NOTHROW([&]() { - my_object& mo = lua["mop"]; - REQUIRE((&mo == my_object::last_printed)); - }()); -#endif - auto result2 = lua.safe_script(R"( -mo = my_object(10) -c_mo = mo -c_iterable = mo:iterable() -)", sol::script_pass_on_error); - REQUIRE(result2.valid()); - - REQUIRE_NOTHROW([&]() { - my_object& mo = lua["c_mo"]; - my_object& mo_iterable = lua["c_iterable"]; - REQUIRE(&mo == &mo_iterable); - REQUIRE(mo == mo_iterable); - }()); - - auto result3 = lua.safe_script(R"( -s1 = c_mo:size() -s1_len = #c_mo -s1_iterable = c_iterable:size() -s1_iterable_len = #c_iterable -)"); - REQUIRE(result3.valid()); - - REQUIRE_NOTHROW([&]() { - std::size_t s1 = lua["s1"]; - std::size_t s1_len = lua["s1_len"]; - std::size_t s1_iterable = lua["s1_iterable"]; - std::size_t s1_iterable_len = lua["s1_iterable_len"]; - REQUIRE(s1 == 10); - REQUIRE(s1 == s1_len); - REQUIRE(s1 == s1_iterable_len); - REQUIRE(s1_iterable == s1_iterable_len); - }()); - - auto result4 = lua.safe_script(R"( -for i=1,#c_mo do - v_iterable = c_iterable[i] - assert(v_iterable == i) -end -)", sol::script_pass_on_error); - REQUIRE(result4.valid()); - - auto result5 = lua.safe_script(R"( -mo(5, 20) -c_iterable:insert(1, 100) -v1 = c_iterable[1] -s2 = c_mo:size() -s2_len = #c_mo -s2_iterable = c_iterable:size() -s2_iterable_len = #c_iterable -print(mo) - )", sol::script_pass_on_error); - REQUIRE(result5.valid()); - - int v1 = lua["v1"]; - std::size_t s2 = lua["s2"]; - std::size_t s2_len = lua["s2_len"]; - std::size_t s2_iterable = lua["s2_iterable"]; - std::size_t s2_iterable_len = lua["s2_iterable_len"]; - REQUIRE(v1 == 100); - REQUIRE(s2 == 16); - REQUIRE(s2 == s2_len); - REQUIRE(s2 == s2_iterable_len); - REQUIRE(s2_iterable == s2_iterable_len); - - my_object& mo = lua["mo"]; - REQUIRE(&mo == my_object::last_printed); -} - -TEST_CASE("containers/as_container", "test that we can force a container to be treated like one despite the trait being false using the proper marker") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.set_function("f", [](int v) { - return sol::as_container(my_object(v)); - }); - -#if SOL_LUA_VERSION > 501 - auto result1 = lua.safe_script(R"( -mop = f(20) -for i, v in pairs(mop) do - assert(i == v) -end - )"); - REQUIRE(result1.valid()); -#endif - auto result2 = lua.safe_script(R"( -mo = f(10) -c_iterable = mo -)"); - REQUIRE(result2.valid()); - - { - my_object& mo = lua["mo"]; - my_object& mo_iterable = lua["c_iterable"]; - REQUIRE(&mo == &mo_iterable); - REQUIRE(mo == mo_iterable); - } - - auto result3 = lua.safe_script(R"( -s1_iterable = c_iterable:size() -s1_iterable_len = #c_iterable -)"); - REQUIRE(result3.valid()); - - { - std::size_t s1_iterable = lua["s1_iterable"]; - std::size_t s1_iterable_len = lua["s1_iterable_len"]; - REQUIRE(s1_iterable == 10); - REQUIRE(s1_iterable == s1_iterable_len); - } - - auto result4 = lua.safe_script(R"( -for i=1,#c_iterable do - v_iterable = c_iterable[i] - assert(v_iterable == i) -end -)"); - REQUIRE(result4.valid()); - - auto result5 = lua.safe_script(R"( -c_iterable:insert(1, 100) -v1 = c_iterable:get(1) -s2_iterable = c_iterable:size() -s2_iterable_len = #c_iterable - )"); - REQUIRE(result5.valid()); - - { - int v1 = lua["v1"]; - std::size_t s2_iterable = lua["s2_iterable"]; - std::size_t s2_iterable_len = lua["s2_iterable_len"]; - REQUIRE(v1 == 100); - REQUIRE(s2_iterable_len == 11); - REQUIRE(s2_iterable == s2_iterable_len); - } -} diff --git a/tests/runtime_tests/source/container_semantics.custom.cpp b/tests/runtime_tests/source/container_semantics.custom.cpp new file mode 100644 index 00000000..6126c77d --- /dev/null +++ b/tests/runtime_tests/source/container_semantics.custom.cpp @@ -0,0 +1,297 @@ +// 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 "sol_test.hpp" + +#include + +#include +#include // std::iota + + +struct my_object { +private: + std::vector mdata; + +public: + static const void* last_printed; + + my_object(int sz) : mdata() { + mdata.resize(sz); + std::iota(mdata.begin(), mdata.end(), 1); + } + + void operator()(std::size_t count, int value) { + for (; count > 0; --count) { + mdata.push_back(value); + } + } + +public: // Container requirements, as per the C++ standard + using value_type = int; + using reference = value_type&; + using const_reference = const value_type&; + using iterator = decltype(mdata)::iterator; + using const_iterator = decltype(mdata)::const_iterator; + using difference_type = decltype(mdata)::difference_type; + using size_type = decltype(mdata)::size_type; + + iterator begin() { + return iterator(mdata.begin()); + } + iterator end() { + return iterator(mdata.end()); + } + const_iterator begin() const { + return const_iterator(mdata.begin()); + } + const_iterator end() const { + return const_iterator(mdata.end()); + } + const_iterator cbegin() const { + return begin(); + } + const_iterator cend() const { + return end(); + } + size_type size() const noexcept { + return mdata.size(); + } + size_type max_size() const noexcept { + return mdata.max_size(); + } + void push_back(const value_type& v) { + mdata.push_back(v); + } + void insert(const_iterator where, const value_type& v) { + mdata.insert(where, v); + } + bool empty() const noexcept { + return mdata.empty(); + } + bool operator==(const my_object& right) const { + return mdata == right.mdata; + } + bool operator!=(const my_object& right) const noexcept { + return mdata != right.mdata; + } + + std::vector& data() { + return mdata; + } + + const std::vector& data() const { + return mdata; + } +}; + +const void* my_object::last_printed = nullptr; + +std::ostream& operator<<(std::ostream& ostr, const my_object& mo) { + my_object::last_printed = static_cast(&mo); + ostr << "{ "; + const auto& v = mo.data(); + if (v.empty()) { + ostr << "empty"; + } + else { + ostr << v[0]; + for (std::size_t i = 1; i < v.size(); ++i) { + ostr << ", " << v[i]; + } + } + ostr << " }"; + + return ostr; +} + +namespace sol { + template <> + struct is_container : std::false_type {}; +} // namespace sol + +TEST_CASE("containers/as_container reference", "test that we can force a container to be treated like one despite is_container being false_type") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("my_object", + sol::constructors(), + sol::call_constructor, + sol::constructors(), + "size", + &my_object::size, + "iterable", + [](my_object& mo) { return sol::as_container(mo); }); + +#if SOL_LUA_VERSION > 501 + auto result1 = lua.safe_script(R"( +mop = my_object.new(20) +for i, v in pairs(mop) do + assert(i == v) +end +print(mop) + )", + sol::script_pass_on_error); + REQUIRE(result1.valid()); + REQUIRE_NOTHROW([&]() { + my_object& mo = lua["mop"]; + REQUIRE((&mo == my_object::last_printed)); + }()); +#endif + auto result2 = lua.safe_script(R"( +mo = my_object(10) +c_mo = mo +c_iterable = mo:iterable() +)", + sol::script_pass_on_error); + REQUIRE(result2.valid()); + + REQUIRE_NOTHROW([&]() { + my_object& mo = lua["c_mo"]; + my_object& mo_iterable = lua["c_iterable"]; + REQUIRE(&mo == &mo_iterable); + REQUIRE(mo == mo_iterable); + }()); + + auto result3 = lua.safe_script(R"( +s1 = c_mo:size() +s1_len = #c_mo +s1_iterable = c_iterable:size() +s1_iterable_len = #c_iterable +)"); + REQUIRE(result3.valid()); + + REQUIRE_NOTHROW([&]() { + std::size_t s1 = lua["s1"]; + std::size_t s1_len = lua["s1_len"]; + std::size_t s1_iterable = lua["s1_iterable"]; + std::size_t s1_iterable_len = lua["s1_iterable_len"]; + REQUIRE(s1 == 10); + REQUIRE(s1 == s1_len); + REQUIRE(s1 == s1_iterable_len); + REQUIRE(s1_iterable == s1_iterable_len); + }()); + + auto result4 = lua.safe_script(R"( +for i=1,#c_mo do + v_iterable = c_iterable[i] + assert(v_iterable == i) +end +)", + sol::script_pass_on_error); + REQUIRE(result4.valid()); + + auto result5 = lua.safe_script(R"( +mo(5, 20) +c_iterable:insert(1, 100) +v1 = c_iterable[1] +s2 = c_mo:size() +s2_len = #c_mo +s2_iterable = c_iterable:size() +s2_iterable_len = #c_iterable +print(mo) + )", + sol::script_pass_on_error); + REQUIRE(result5.valid()); + + int v1 = lua["v1"]; + std::size_t s2 = lua["s2"]; + std::size_t s2_len = lua["s2_len"]; + std::size_t s2_iterable = lua["s2_iterable"]; + std::size_t s2_iterable_len = lua["s2_iterable_len"]; + REQUIRE(v1 == 100); + REQUIRE(s2 == 16); + REQUIRE(s2 == s2_len); + REQUIRE(s2 == s2_iterable_len); + REQUIRE(s2_iterable == s2_iterable_len); + + my_object& mo = lua["mo"]; + REQUIRE(&mo == my_object::last_printed); +} + +TEST_CASE("containers/as_container", "test that we can force a container to be treated like one despite the trait being false using the proper marker") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.set_function("f", [](int v) { return sol::as_container(my_object(v)); }); + +#if SOL_LUA_VERSION > 501 + auto result1 = lua.safe_script(R"( +mop = f(20) +for i, v in pairs(mop) do + assert(i == v) +end + )"); + REQUIRE(result1.valid()); +#endif + auto result2 = lua.safe_script(R"( +mo = f(10) +c_iterable = mo +)"); + REQUIRE(result2.valid()); + + { + my_object& mo = lua["mo"]; + my_object& mo_iterable = lua["c_iterable"]; + REQUIRE(&mo == &mo_iterable); + REQUIRE(mo == mo_iterable); + } + + auto result3 = lua.safe_script(R"( +s1_iterable = c_iterable:size() +s1_iterable_len = #c_iterable +)"); + REQUIRE(result3.valid()); + + { + std::size_t s1_iterable = lua["s1_iterable"]; + std::size_t s1_iterable_len = lua["s1_iterable_len"]; + REQUIRE(s1_iterable == 10); + REQUIRE(s1_iterable == s1_iterable_len); + } + + auto result4 = lua.safe_script(R"( +for i=1,#c_iterable do + v_iterable = c_iterable[i] + assert(v_iterable == i) +end +)"); + REQUIRE(result4.valid()); + + auto result5 = lua.safe_script(R"( +c_iterable:insert(1, 100) +v1 = c_iterable:get(1) +s2_iterable = c_iterable:size() +s2_iterable_len = #c_iterable + )"); + REQUIRE(result5.valid()); + + { + int v1 = lua["v1"]; + std::size_t s2_iterable = lua["s2_iterable"]; + std::size_t s2_iterable_len = lua["s2_iterable_len"]; + REQUIRE(v1 == 100); + REQUIRE(s2_iterable_len == 11); + REQUIRE(s2_iterable == s2_iterable_len); + } +} diff --git a/tests/runtime_tests/source/container_semantics.ordered.cpp b/tests/runtime_tests/source/container_semantics.ordered.cpp new file mode 100644 index 00000000..ec55395f --- /dev/null +++ b/tests/runtime_tests/source/container_semantics.ordered.cpp @@ -0,0 +1,377 @@ +// 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 "sol_test.hpp" + +#include + +#include +#include + +template +void ordered_container_check(sol::state& lua, T& items) { + { + auto r1 = lua.safe_script(R"( +for i=1,#c do + v = c[(i + 10)] + assert(v == (i + 10)) +end + )", + sol::script_pass_on_error); + REQUIRE(r1.valid()); + } + { + auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("c:set(20)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("c:set(16)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error); + REQUIRE(r5.valid()); + auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error); + REQUIRE(r3.valid()); + auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error); + REQUIRE(r4.valid()); + } + { + auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + { + auto r = lua.safe_script("c[18] = true", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + { + auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + auto backit = items.begin(); + std::size_t len = 0; + { + auto e = items.end(); + auto last = backit; + for (; backit != e; ++backit, ++len) { + if (backit == e) { + break; + } + last = backit; + } + backit = last; + } + const int& first = *items.begin(); + const int& last = *backit; + int i1 = lua["i1"]; + int i2 = lua["i2"]; + int io1 = lua["io1"]; + int io2 = lua["io2"]; + std::size_t s1 = lua["s1"]; + std::size_t s2 = lua["s2"]; + std::size_t s3 = lua["s3"]; + int v1 = lua["v1"]; + int v2 = lua["v2"]; + int v3 = lua["v3"]; + int values[] = { 12, 13, 15, 16, 17, 18, 20 }; + { + std::size_t idx = 0; + for (const auto& i : items) { + const auto& v = values[idx]; + REQUIRE((i == v)); + ++idx; + } + } + REQUIRE((s1 == 7)); + REQUIRE((s2 == 6)); + REQUIRE((s3 == 5)); + REQUIRE((len == 7)); + REQUIRE((first == 12)); + REQUIRE((last == 20)); + REQUIRE((i1 == 11)); + REQUIRE((i2 == 14)); + REQUIRE((io1 == 2)); + REQUIRE((io2 == 3)); + REQUIRE((v1 == 11)); + REQUIRE((v2 == 13)); + REQUIRE((v3 == 20)); +} + +template +void associative_ordered_container_check(sol::state& lua, T& items) { + { + auto r1 = lua.safe_script(R"( +for i=1,#c do + v = c[(i + 10)] + assert(v == (i + 20)) +end + )", + sol::script_pass_on_error); + REQUIRE(r1.valid()); + } + { + auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("c:set(20, 30)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("c:set(16, 26)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + auto r3 = lua.safe_script("c:set(12, 31)", sol::script_pass_on_error); + REQUIRE(r3.valid()); + } + { + auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error); + REQUIRE(r5.valid()); + auto r1 = lua.safe_script("c:erase(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error); + REQUIRE(r3.valid()); + auto r2 = lua.safe_script("c:erase(14)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error); + REQUIRE(r4.valid()); + } + { + auto r = lua.safe_script("c:add(17, 27)", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + { + auto r = lua.safe_script("c[18] = 28", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + { + auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + auto backit = items.begin(); + std::size_t len = 0; + { + auto e = items.end(); + auto last = backit; + for (; backit != e; ++backit, ++len) { + if (backit == e) { + break; + } + last = backit; + } + backit = last; + } + const std::pair& first = *items.begin(); + const std::pair& last = *backit; + int i1 = lua["i1"]; + int i2 = lua["i2"]; + int io1 = lua["io1"]; + int io2 = lua["io2"]; + std::size_t s1 = lua["s1"]; + std::size_t s2 = lua["s2"]; + std::size_t s3 = lua["s3"]; + int v1 = lua["v1"]; + int v2 = lua["v2"]; + int v3 = lua["v3"]; + std::pair values[] + = { { (short)12, 31 }, { (short)13, 23 }, { (short)15, 25 }, { (short)16, 26 }, { (short)17, 27 }, { (short)18, 28 }, { (short)20, 30 } }; + { + std::size_t idx = 0; + for (const auto& i : items) { + const auto& v = values[idx]; + REQUIRE((i == v)); + ++idx; + } + } + REQUIRE((s1 == 7)); + REQUIRE((s2 == 6)); + REQUIRE((s3 == 5)); + REQUIRE((len == 7)); + REQUIRE((first.first == 12)); + REQUIRE((last.first == 20)); + REQUIRE((first.second == 31)); + REQUIRE((last.second == 30)); + REQUIRE((i1 == 21)); + REQUIRE((i2 == 24)); + REQUIRE((io1 == 2)); + REQUIRE((io2 == 3)); + REQUIRE((v1 == 21)); + REQUIRE((v2 == 23)); + REQUIRE((v3 == 30)); +} + +template +void associative_ordered_container_key_value_check(sol::state& lua, T& data, T& reflect) { + typedef typename T::key_type K; + typedef typename T::mapped_type V; + lua["collect"] = [&reflect](K k, V v) { reflect.insert({ k, v }); }; + +#if SOL_LUA_VERSION > 502 + lua["val"] = data; + auto r = lua.safe_script(R"( +for k, v in pairs(val) do + collect(k, v) +end +print() +)", + sol::script_pass_on_error); + REQUIRE(r.valid()); +#else + reflect = data; +#endif + REQUIRE((data == reflect)); +} + +template +void ordered_lookup_container_check(sol::state& lua, T&) { + auto result0 = lua.safe_script("assert(c['a'] == 'a')", sol::script_default_on_error); + REQUIRE(result0.valid()); + auto result1 = lua.safe_script("assert(c['b'] == 'b')", sol::script_default_on_error); + REQUIRE(result1.valid()); + auto result2 = lua.safe_script("assert(c['c'] == 'c')", sol::script_default_on_error); + REQUIRE(result2.valid()); +} + +TEST_CASE("containers/ordered lookup containers", "check ordered container types") { + SECTION("set") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::set items{ 11, 12, 13, 14, 15 }; + lua["c"] = &items; + ordered_container_check(lua, items); + } + SECTION("set string") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::set items({ "a", "b", "c" }); + lua["c"] = &items; + ordered_lookup_container_check(lua, items); + } + SECTION("multiset") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::multiset items{ 11, 12, 13, 14, 15 }; + lua["c"] = &items; + ordered_container_check(lua, items); + } + SECTION("multiset string") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::multiset items({ "a", "b", "c" }); + lua["c"] = &items; + ordered_lookup_container_check(lua, items); + } +} + +TEST_CASE("containers/associative ordered containers", "check associative (map) containers that are ordered fulfill basic functionality requirements") { + SECTION("map") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::map items{ { (short)11, 21 }, { (short)12, 22 }, { (short)13, 23 }, { (short)14, 24 }, { (short)15, 25 } }; + lua["c"] = &items; + associative_ordered_container_check(lua, items); + } + SECTION("map string") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::map items{ { "a", "a" }, { "b", "b" }, { "c", "c" } }; + lua["c"] = &items; + ordered_lookup_container_check(lua, items); + } + SECTION("multimap") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::multimap items{ { (short)11, 21 }, { (short)12, 22 }, { (short)13, 23 }, { (short)14, 24 }, { (short)15, 25 } }; + lua["c"] = &items; + associative_ordered_container_check(lua, items); + } + SECTION("multimap string") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::multimap items{ { "a", "a" }, { "b", "b" }, { "c", "c" } }; + lua["c"] = &items; + ordered_lookup_container_check(lua, items); + } +} + +TEST_CASE("containers/associative ordered pairs", "check to make sure pairs works properly for key-value types") { + struct bar {}; + std::unique_ptr ua(new bar()), ub(new bar()), uc(new bar()); + bar* a = ua.get(); + bar* b = ub.get(); + bar* c = uc.get(); + + SECTION("map") { + sol::state lua; + lua.open_libraries(sol::lib::base); + std::map data({ { "a", a }, { "b", b }, { "c", c } }); + std::map reflect; + associative_ordered_container_key_value_check(lua, data, reflect); + } + SECTION("multimap") { + sol::state lua; + lua.open_libraries(sol::lib::base); + std::multimap data({ { "a", a }, { "b", b }, { "c", c } }); + std::multimap reflect; + associative_ordered_container_key_value_check(lua, data, reflect); + } +} diff --git a/tests/runtime_tests/source/container_semantics.unordered.cpp b/tests/runtime_tests/source/container_semantics.unordered.cpp new file mode 100644 index 00000000..2e1fe855 --- /dev/null +++ b/tests/runtime_tests/source/container_semantics.unordered.cpp @@ -0,0 +1,269 @@ +// 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 "sol_test.hpp" + +#include + +#include +#include + + +template +void unordered_container_check(sol::state& lua, T& items) { + { + auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); + REQUIRE_FALSE(r1.valid()); + auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); + REQUIRE_FALSE(r2.valid()); + } + { + auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("c:set(20)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("c:set(16)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error); + REQUIRE(r5.valid()); + auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error); + REQUIRE(r3.valid()); + auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error); + REQUIRE(r4.valid()); + } + { + auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + { + auto r = lua.safe_script("c[18] = true", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + { + auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + std::size_t len = items.size(); + int i1 = lua["i1"]; + int i2 = lua["i2"]; + std::size_t s1 = lua["s1"]; + std::size_t s2 = lua["s2"]; + std::size_t s3 = lua["s3"]; + int v1 = lua["v1"]; + int v2 = lua["v2"]; + int v3 = lua["v3"]; + int values[] = { 12, 13, 15, 16, 17, 18, 20 }; + { + for (const auto& v : values) { + auto it = items.find(v); + REQUIRE((it != items.cend())); + REQUIRE((*it == v)); + } + } + REQUIRE((s1 == 7)); + REQUIRE((s2 == 6)); + REQUIRE((s3 == 5)); + REQUIRE((len == 7)); + REQUIRE((i1 == 11)); + REQUIRE((i2 == 14)); + REQUIRE((v1 == 11)); + REQUIRE((v2 == 13)); + REQUIRE((v3 == 20)); +} + +template +void associative_unordered_container_check(sol::state& lua, T& items) { + { + auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); + REQUIRE_FALSE(r1.valid()); + auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); + REQUIRE_FALSE(r2.valid()); + } + { + auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + } + { + auto r1 = lua.safe_script("c:set(20, 30)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("c:set(16, 26)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + auto r3 = lua.safe_script("c:set(12, 31)", sol::script_pass_on_error); + REQUIRE(r3.valid()); + } + { + auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error); + REQUIRE(r5.valid()); + auto r1 = lua.safe_script("c:erase(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error); + REQUIRE(r3.valid()); + auto r2 = lua.safe_script("c:erase(14)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error); + REQUIRE(r4.valid()); + } + { + auto r = lua.safe_script("c:add(17, 27)", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + { + auto r = lua.safe_script("c[18] = 28", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + { + auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error); + REQUIRE(r.valid()); + } + std::size_t len = items.size(); + int i1 = lua["i1"]; + int i2 = lua["i2"]; + std::size_t s1 = lua["s1"]; + std::size_t s2 = lua["s2"]; + std::size_t s3 = lua["s3"]; + int v1 = lua["v1"]; + int v2 = lua["v2"]; + int v3 = lua["v3"]; + std::pair values[] + = { { (short)12, 31 }, { (short)13, 23 }, { (short)15, 25 }, { (short)16, 26 }, { (short)17, 27 }, { (short)18, 28 }, { (short)20, 30 } }; + { + for (const auto& v : values) { + auto it = items.find(v.first); + REQUIRE((it != items.cend())); + REQUIRE((it->second == v.second)); + } + } + REQUIRE((s1 == 7)); + REQUIRE((s2 == 6)); + REQUIRE((s3 == 5)); + REQUIRE((len == 7)); + REQUIRE((i1 == 21)); + REQUIRE((i2 == 24)); + REQUIRE((v1 == 21)); + REQUIRE((v2 == 23)); + REQUIRE((v3 == 30)); +} + +template +void unordered_lookup_container_check(sol::state& lua, T&) { + auto result0 = lua.safe_script("assert(c['a'] == 'a')", sol::script_default_on_error); + REQUIRE(result0.valid()); + auto result1 = lua.safe_script("assert(c['b'] == 'b')", sol::script_default_on_error); + REQUIRE(result1.valid()); + auto result2 = lua.safe_script("assert(c['c'] == 'c')", sol::script_default_on_error); + REQUIRE(result2.valid()); +} + +TEST_CASE("containers/unordered lookup containers", "check ordered container types") { + SECTION("unordered_set") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::unordered_set items{ 11, 12, 13, 14, 15 }; + lua["c"] = &items; + unordered_container_check(lua, items); + } + SECTION("unordered_set string") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::unordered_set items({ "a", "b", "c" }); + lua["c"] = &items; + unordered_lookup_container_check(lua, items); + } + SECTION("unordered_multiset") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::unordered_multiset items{ 11, 12, 13, 14, 15 }; + lua["c"] = &items; + unordered_container_check(lua, items); + } + SECTION("unordered_multiset string") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::unordered_multiset items({ "a", "b", "c" }); + lua["c"] = &items; + unordered_lookup_container_check(lua, items); + } +} + +TEST_CASE("containers/associative unordered containers", "check associative (map) containers that are ordered that they fulfill basic requirements") { + SECTION("unordered_map") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::unordered_map items{ { (short)11, 21 }, { (short)12, 22 }, { (short)13, 23 }, { (short)14, 24 }, { (short)15, 25 } }; + lua["c"] = &items; + associative_unordered_container_check(lua, items); + } + SECTION("unordered_map string") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::unordered_map items{ { "a", "a" }, { "b", "b" }, { "c", "c" } }; + lua["c"] = &items; + unordered_lookup_container_check(lua, items); + } + SECTION("unordered_multimap") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::unordered_multimap items{ { (short)11, 21 }, { (short)12, 22 }, { (short)13, 23 }, { (short)14, 24 }, { (short)15, 25 } }; + lua["c"] = &items; + associative_unordered_container_check(lua, items); + } + SECTION("unordered_multimap string") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::unordered_multimap items{ { "a", "a" }, { "b", "b" }, { "c", "c" } }; + lua["c"] = &items; + unordered_lookup_container_check(lua, items); + } +} diff --git a/tests/runtime_tests/source/containers.cpp b/tests/runtime_tests/source/containers.cpp index 9b5d8ec7..c522676d 100644 --- a/tests/runtime_tests/source/containers.cpp +++ b/tests/runtime_tests/source/containers.cpp @@ -37,46 +37,6 @@ #include #include -auto test_table_return_one() { - return sol::as_table(std::vector{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); -} - -auto test_table_return_two() { - return sol::as_table(std::vector>{ { "one", 1 }, { "two", 2 }, { "three", 3 } }); -} - -auto test_table_return_three() { - return sol::as_table(std::map{ { "name", "Rapptz" }, { "friend", "ThePhD" }, { "project", "sol" } }); -} - -auto test_table_return_four() { - return sol::as_table(std::array, 4>{ { { "one", 1 }, { "two", 2 }, { "three", 3 }, { "four", 4 } } }); -} - -template -void check_ordered_values(S& src, T& target) { - std::size_t idx = 0; - auto b = std::begin(target); - auto e = std::end(target); - for (; b != e; ++b, ++idx) { - const auto& v = src[idx]; - REQUIRE((*b == v)); - } -} - -template -void check_unordered_values(S& src, T& target) { - std::size_t idx = 0; - auto b = std::begin(target); - auto e = std::end(target); - for (; b != e; ++b, ++idx) { - auto sb = std::begin(src); - auto se = std::end(src); - auto it = std::find(sb, se, *b); - REQUIRE((it != se)); - } -} - TEST_CASE("containers/returns", "make sure that even references to vectors are being serialized as tables") { sol::state lua; std::vector v{ 1, 2, 3 }; @@ -98,123 +58,6 @@ TEST_CASE("containers/returns", "make sure that even references to vectors are b REQUIRE(matching); } -TEST_CASE("containers/vector roundtrip", "make sure vectors can be round-tripped") { - sol::state lua; - std::vector v{ 1, 2, 3 }; - lua.set_function("f", [&]() -> std::vector& { - return v; - }); - auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); - REQUIRE(result1.valid()); - std::vector x = lua["x"]; - bool areequal = x == v; - REQUIRE(areequal); -} - -TEST_CASE("containers/deque roundtrip", "make sure deques can be round-tripped") { - sol::state lua; - std::deque v{ 1, 2, 3 }; - lua.set_function("f", [&]() -> std::deque& { - return v; - }); - auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); - REQUIRE(result1.valid()); - std::deque x = lua["x"]; - bool areequal = x == v; - REQUIRE(areequal); -} - -TEST_CASE("containers/array roundtrip", "make sure arrays can be round-tripped") { - sol::state lua; - std::array v{ { 1, 2, 3 } }; - lua.set_function("f", [&]() -> std::array& { - return v; - }); - auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); - REQUIRE(result1.valid()); - std::array x = lua["x"]; - bool areequal = x == v; - REQUIRE(areequal); -} - -TEST_CASE("containers/list roundtrip", "make sure lists can be round-tripped") { - sol::state lua; - std::list v{ 1, 2, 3 }; - lua.set_function("f", [&]() -> std::list& { - return v; - }); - auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); - REQUIRE(result1.valid()); - std::list x = lua["x"]; - bool areequal = x == v; - REQUIRE(areequal); -} - -TEST_CASE("containers/forward_list roundtrip", "make sure forward_lists can be round-tripped") { - sol::state lua; - std::forward_list v{ 1, 2, 3 }; - lua.set_function("f", [&]() -> std::forward_list& { - return v; - }); - auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); - REQUIRE(result1.valid()); - std::forward_list x = lua["x"]; - bool areequal = x == v; - REQUIRE(areequal); -} - -TEST_CASE("containers/map roundtrip", "make sure maps can be round-tripped") { - sol::state lua; - std::map v{ { "a", 1 }, { "b", 2 }, { "c", 3 } }; - lua.set_function("f", [&]() -> std::map& { - return v; - }); - auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); - REQUIRE(result1.valid()); - std::map x = lua["x"]; - bool areequal = x == v; - REQUIRE(areequal); -} - -TEST_CASE("containers/unordered_map roundtrip", "make sure unordered_maps can be round-tripped") { - sol::state lua; - std::unordered_map v{ { "a", 1 }, { "b", 2 }, { "c", 3 } }; - lua.set_function("f", [&]() -> std::unordered_map& { - return v; - }); - auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); - REQUIRE(result1.valid()); - std::unordered_map x = lua["x"]; - bool areequal = x == v; - REQUIRE(areequal); -} - -TEST_CASE("containers/unordered_set roundtrip", "make sure unordered_sets can be round-tripped") { - sol::state lua; - std::unordered_set v{ 1, 2, 3 }; - lua.set_function("f", [&]() -> std::unordered_set& { - return v; - }); - auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); - REQUIRE(result1.valid()); - std::unordered_set x = lua["x"]; - bool areequal = x == v; - REQUIRE(areequal); -} - -TEST_CASE("containers/set roundtrip", "make sure sets can be round-tripped") { - sol::state lua; - std::set v{ 1, 2, 3 }; - lua.set_function("f", [&]() -> std::set& { - return v; - }); - auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); - REQUIRE(result1.valid()); - std::set x = lua["x"]; - bool areequal = x == v; - REQUIRE(areequal); -} - TEST_CASE("containers/custom usertype", "make sure container usertype metatables can be overridden") { typedef std::unordered_map bark; @@ -305,33 +148,6 @@ TEST_CASE("containers/const serialization", "make sure containers are turned int } #endif -TEST_CASE("containers/table serialization", "ensure types can be serialized as tables still") { - typedef std::vector woof; - sol::state lua; - lua.open_libraries(); - lua.set("b", sol::as_table(woof{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 })); - { - auto result = lua.safe_script("for k, v in ipairs(b) do assert(k == v) end", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - woof w{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }; - lua.set("b", sol::as_table(w)); - { - auto result = lua.safe_script("for k, v in ipairs(b) do assert(k == v) end", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - lua.set("b", sol::as_table(&w)); - { - auto result = lua.safe_script("for k, v in ipairs(b) do assert(k == v) end", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - lua.set("b", sol::as_table(std::ref(w))); - { - auto result = lua.safe_script("for k, v in ipairs(b) do assert(k == v) end", sol::script_pass_on_error); - REQUIRE(result.valid()); - } -} - TEST_CASE("containers/const correctness", "usertype metatable names should reasonably ignore const attributes") { struct Vec { int x, y, z; @@ -369,84 +185,6 @@ end REQUIRE(pfr2.valid()); } -TEST_CASE("containers/arbitrary creation", "userdata and tables should be usable from standard containers") { - sol::state lua; - lua.open_libraries(sol::lib::base); - lua.set_function("test_one", test_table_return_one); - lua.set_function("test_two", test_table_return_two); - lua.set_function("test_three", test_table_return_three); - lua.set_function("test_four", test_table_return_four); - - { - auto result = lua.safe_script("a = test_one()", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("b = test_two()", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("c = test_three()", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("d = test_four()", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - - { - auto result = lua.safe_script("assert(#a == 10, 'error')", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("assert(a[3] == 3, 'error')", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("assert(b.one == 1, 'error')", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("assert(b.three == 3, 'error')", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("assert(c.name == 'Rapptz', 'error')", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("assert(c.project == 'sol', 'error')", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("assert(d.one == 1, 'error')", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("assert(d.three == 3, 'error')", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("assert(d.four == 4, 'error')", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - - sol::table a = lua.get("a"); - sol::table b = lua.get("b"); - sol::table c = lua.get("c"); - sol::table d = lua["d"]; - - REQUIRE(a.size() == 10ULL); - REQUIRE(a.get(3) == 3); - REQUIRE(b.get("one") == 1); - REQUIRE(b.get("three") == 3); - REQUIRE(c.get("name") == "Rapptz"); - REQUIRE(c.get("project") == "sol"); - REQUIRE(d.get("one") == 1); - REQUIRE(d.get("three") == 3); - REQUIRE(d.get("four") == 4); -} - TEST_CASE("containers/usertype transparency", "Make sure containers pass their arguments through transparently and push the results as references, not new values") { class A { public: @@ -616,41 +354,6 @@ TEST_CASE("containers/to_args", "Test that the to_args abstractions works") { REQUIRE(d == 12); } -TEST_CASE("containers/ipairs test", "ensure that abstractions roundtrip properly") { - struct thing { - int x = 20; - }; - thing t{}; - sol::state lua; - lua.open_libraries(); - - lua.set_function("f", [&t]() { - return std::vector(5, &t); - }); - - auto result1 = lua.safe_script(R"( -c = f() -)", sol::script_pass_on_error); - REQUIRE(result1.valid()); - - auto result2 = lua.safe_script(R"( -check = {} -local i = 1 -while c[i] do - check[i] = c[i] - i = i + 1 -end -)", sol::script_pass_on_error); - REQUIRE(result2.valid()); - - sol::table c = lua["check"]; - for (std::size_t i = 1; i < 6; ++i) { - thing& ct = c[i]; - REQUIRE(&t == &ct); - REQUIRE(ct.x == 20); - } -} - TEST_CASE("containers/append idiom", "ensure the append-idiom works as intended") { sol::state lua; lua.open_libraries(sol::lib::base); @@ -670,7 +373,7 @@ function f_append(vec) vec[#vec + 1] = -54 print("#vec in lua: " .. #vec) end -)"); +)", sol::script_pass_on_error); REQUIRE(result1.valid()); std::vector fill_cmp{ 1, 2, 3 }; @@ -716,8 +419,8 @@ TEST_CASE("containers/non_copyable", "make sure non-copyable types in containers } TEST_CASE("containers/pairs", "test how well pairs work with the underlying system") { - typedef std::pair pair_arr_t[5]; - typedef int arr_t[5]; + using pair_arr_t = std::pair[5]; + using arr_t = int[5]; sol::state lua; @@ -825,52 +528,3 @@ TEST_CASE("containers/pointer types", "check that containers with unique usertyp int val2 = b2->get(); REQUIRE(val2 == 500); } - -TEST_CASE("containers/initializer-list", "test initializer lists get pushed as tables directly rather than userdata") { - SECTION("array-like") { - sol::state lua; - lua.open_libraries(sol::lib::base, sol::lib::table); - - lua["c"] = { 1, 2, 3, 4, 5 }; - auto result1 = lua.safe_script(R"lua( -for k, v in pairs(c) do - assert(k == v) -end -)lua", sol::script_pass_on_error); - sol::as_table_t> t1vector = lua["c"]; - sol::as_table_t> t1deque = lua["c"]; - sol::as_table_t> t1list = lua["c"]; - sol::as_table_t> t1flist = lua["c"]; - sol::as_table_t> t1set = lua["c"]; - const int src[5] = { 1, 2, 3, 4, 5 }; - check_ordered_values(src, t1vector.source); - check_ordered_values(src, t1deque.source); - check_ordered_values(src, t1list.source); - check_ordered_values(src, t1flist.source); - check_ordered_values(src, t1set.source); - } - SECTION("map-like") { - sol::state lua; - lua.open_libraries(sol::lib::base, sol::lib::table); - std::pair src[5]{ - { "a", 21 }, - { "b", 22 }, - { "c", 23 }, - { "d", 24 }, - { "e", 25 } - }; - - lua["c"] = std::initializer_list>{ - { "a", 21 }, - { "b", 22 }, - { "c", 23 }, - { "d", 24 }, - { "e", 25 } - }; - - sol::as_table_t> t1umap = lua["c"]; - sol::as_table_t> t1ummap = lua["c"]; - check_unordered_values(src, t1umap.source); - check_unordered_values(src, t1ummap.source); - } -} diff --git a/tests/runtime_tests/source/containers.roundtrip.cpp b/tests/runtime_tests/source/containers.roundtrip.cpp new file mode 100644 index 00000000..dad56323 --- /dev/null +++ b/tests/runtime_tests/source/containers.roundtrip.cpp @@ -0,0 +1,172 @@ +// 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 "sol_test.hpp" +#include "common_classes.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TEST_CASE("containers/vector roundtrip", "make sure vectors can be round-tripped") { + sol::state lua; + std::vector v{ 1, 2, 3 }; + lua.set_function("f", [&]() -> std::vector& { return v; }); + auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); + REQUIRE(result1.valid()); + std::vector x = lua["x"]; + bool areequal = x == v; + REQUIRE(areequal); +} + +TEST_CASE("containers/deque roundtrip", "make sure deques can be round-tripped") { + sol::state lua; + std::deque v{ 1, 2, 3 }; + lua.set_function("f", [&]() -> std::deque& { return v; }); + auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); + REQUIRE(result1.valid()); + std::deque x = lua["x"]; + bool areequal = x == v; + REQUIRE(areequal); +} + +TEST_CASE("containers/array roundtrip", "make sure arrays can be round-tripped") { + sol::state lua; + std::array v{ { 1, 2, 3 } }; + lua.set_function("f", [&]() -> std::array& { return v; }); + auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); + REQUIRE(result1.valid()); + std::array x = lua["x"]; + bool areequal = x == v; + REQUIRE(areequal); +} + +TEST_CASE("containers/list roundtrip", "make sure lists can be round-tripped") { + sol::state lua; + std::list v{ 1, 2, 3 }; + lua.set_function("f", [&]() -> std::list& { return v; }); + auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); + REQUIRE(result1.valid()); + std::list x = lua["x"]; + bool areequal = x == v; + REQUIRE(areequal); +} + +TEST_CASE("containers/forward_list roundtrip", "make sure forward_lists can be round-tripped") { + sol::state lua; + std::forward_list v{ 1, 2, 3 }; + lua.set_function("f", [&]() -> std::forward_list& { return v; }); + auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); + REQUIRE(result1.valid()); + std::forward_list x = lua["x"]; + bool areequal = x == v; + REQUIRE(areequal); +} + +TEST_CASE("containers/map roundtrip", "make sure maps can be round-tripped") { + sol::state lua; + std::map v{ { "a", 1 }, { "b", 2 }, { "c", 3 } }; + lua.set_function("f", [&]() -> std::map& { return v; }); + auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); + REQUIRE(result1.valid()); + std::map x = lua["x"]; + bool areequal = x == v; + REQUIRE(areequal); +} + +TEST_CASE("containers/unordered_map roundtrip", "make sure unordered_maps can be round-tripped") { + sol::state lua; + std::unordered_map v{ { "a", 1 }, { "b", 2 }, { "c", 3 } }; + lua.set_function("f", [&]() -> std::unordered_map& { return v; }); + auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); + REQUIRE(result1.valid()); + std::unordered_map x = lua["x"]; + bool areequal = x == v; + REQUIRE(areequal); +} + +TEST_CASE("containers/unordered_set roundtrip", "make sure unordered_sets can be round-tripped") { + sol::state lua; + std::unordered_set v{ 1, 2, 3 }; + lua.set_function("f", [&]() -> std::unordered_set& { return v; }); + auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); + REQUIRE(result1.valid()); + std::unordered_set x = lua["x"]; + bool areequal = x == v; + REQUIRE(areequal); +} + +TEST_CASE("containers/set roundtrip", "make sure sets can be round-tripped") { + sol::state lua; + std::set v{ 1, 2, 3 }; + lua.set_function("f", [&]() -> std::set& { return v; }); + auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); + REQUIRE(result1.valid()); + std::set x = lua["x"]; + bool areequal = x == v; + REQUIRE(areequal); +} + +TEST_CASE("containers/ipairs test", "ensure that abstractions roundtrip properly") { + struct thing { + int x = 20; + }; + thing t{}; + sol::state lua; + lua.open_libraries(); + + lua.set_function("f", [&t]() { return std::vector(5, &t); }); + + auto result1 = lua.safe_script(R"( +c = f() +)", + sol::script_pass_on_error); + REQUIRE(result1.valid()); + + auto result2 = lua.safe_script(R"( +check = {} +local i = 1 +while c[i] do + check[i] = c[i] + i = i + 1 +end +)", + sol::script_pass_on_error); + REQUIRE(result2.valid()); + + sol::table c = lua["check"]; + for (std::size_t i = 1; i < 6; ++i) { + thing& ct = c[i]; + REQUIRE(&t == &ct); + REQUIRE(ct.x == 20); + } +} diff --git a/tests/runtime_tests/source/containers.table.cpp b/tests/runtime_tests/source/containers.table.cpp new file mode 100644 index 00000000..6fee3f29 --- /dev/null +++ b/tests/runtime_tests/source/containers.table.cpp @@ -0,0 +1,222 @@ +// 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 "sol_test.hpp" +#include "common_classes.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +auto test_table_return_one() { + return sol::as_table(std::vector{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); +} + +auto test_table_return_two() { + return sol::as_table(std::vector>{ { "one", 1 }, { "two", 2 }, { "three", 3 } }); +} + +auto test_table_return_three() { + return sol::as_table(std::map{ { "name", "Rapptz" }, { "friend", "ThePhD" }, { "project", "sol" } }); +} + +auto test_table_return_four() { + return sol::as_table(std::array, 4>{ { { "one", 1 }, { "two", 2 }, { "three", 3 }, { "four", 4 } } }); +} + +template +void check_ordered_values(S& src, T& target) { + std::size_t idx = 0; + auto b = std::begin(target); + auto e = std::end(target); + for (; b != e; ++b, ++idx) { + const auto& v = src[idx]; + REQUIRE((*b == v)); + } +} + +template +void table_check_unordered_values(S& src, T& target) { + std::size_t idx = 0; + auto b = std::begin(target); + auto e = std::end(target); + for (; b != e; ++b, ++idx) { + auto sb = std::begin(src); + auto se = std::end(src); + auto it = std::find(sb, se, *b); + REQUIRE((it != se)); + } +} + +TEST_CASE("containers/arbitrary creation", "userdata and tables should be usable from standard containers") { + sol::state lua; + lua.open_libraries(sol::lib::base); + lua.set_function("test_one", test_table_return_one); + lua.set_function("test_two", test_table_return_two); + lua.set_function("test_three", test_table_return_three); + lua.set_function("test_four", test_table_return_four); + + { + auto result = lua.safe_script("a = test_one()", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("b = test_two()", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("c = test_three()", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("d = test_four()", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + + { + auto result = lua.safe_script("assert(#a == 10, 'error')", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("assert(a[3] == 3, 'error')", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("assert(b.one == 1, 'error')", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("assert(b.three == 3, 'error')", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("assert(c.name == 'Rapptz', 'error')", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("assert(c.project == 'sol', 'error')", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("assert(d.one == 1, 'error')", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("assert(d.three == 3, 'error')", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("assert(d.four == 4, 'error')", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + + sol::table a = lua.get("a"); + sol::table b = lua.get("b"); + sol::table c = lua.get("c"); + sol::table d = lua["d"]; + + REQUIRE(a.size() == 10ULL); + REQUIRE(a.get(3) == 3); + REQUIRE(b.get("one") == 1); + REQUIRE(b.get("three") == 3); + REQUIRE(c.get("name") == "Rapptz"); + REQUIRE(c.get("project") == "sol"); + REQUIRE(d.get("one") == 1); + REQUIRE(d.get("three") == 3); + REQUIRE(d.get("four") == 4); +} + +TEST_CASE("containers/table serialization", "ensure types can be serialized as tables still") { + typedef std::vector woof; + sol::state lua; + lua.open_libraries(); + lua.set("b", sol::as_table(woof{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 })); + { + auto result = lua.safe_script("for k, v in ipairs(b) do assert(k == v) end", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + woof w{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }; + lua.set("b", sol::as_table(w)); + { + auto result = lua.safe_script("for k, v in ipairs(b) do assert(k == v) end", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + lua.set("b", sol::as_table(&w)); + { + auto result = lua.safe_script("for k, v in ipairs(b) do assert(k == v) end", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + lua.set("b", sol::as_table(std::ref(w))); + { + auto result = lua.safe_script("for k, v in ipairs(b) do assert(k == v) end", sol::script_pass_on_error); + REQUIRE(result.valid()); + } +} + +TEST_CASE("containers/initializer-list", "test initializer lists get pushed as tables directly rather than userdata") { + SECTION("array-like") { + sol::state lua; + lua.open_libraries(sol::lib::base, sol::lib::table); + + lua["c"] = { 1, 2, 3, 4, 5 }; + auto result1 = lua.safe_script(R"lua( +for k, v in pairs(c) do + assert(k == v) +end +)lua", + sol::script_pass_on_error); + sol::as_table_t> t1vector = lua["c"]; + sol::as_table_t> t1deque = lua["c"]; + sol::as_table_t> t1list = lua["c"]; + sol::as_table_t> t1flist = lua["c"]; + sol::as_table_t> t1set = lua["c"]; + const int src[5] = { 1, 2, 3, 4, 5 }; + check_ordered_values(src, t1vector.source); + check_ordered_values(src, t1deque.source); + check_ordered_values(src, t1list.source); + check_ordered_values(src, t1flist.source); + check_ordered_values(src, t1set.source); + } + SECTION("map-like") { + sol::state lua; + lua.open_libraries(sol::lib::base, sol::lib::table); + std::pair src[5]{ { "a", 21 }, { "b", 22 }, { "c", 23 }, { "d", 24 }, { "e", 25 } }; + + lua["c"] = std::initializer_list>{ { "a", 21 }, { "b", 22 }, { "c", 23 }, { "d", 24 }, { "e", 25 } }; + + sol::as_table_t> t1umap = lua["c"]; + sol::as_table_t> t1ummap = lua["c"]; + table_check_unordered_values(src, t1umap.source); + table_check_unordered_values(src, t1ummap.source); + } +} diff --git a/tests/runtime_tests/source/usertypes.basic.cpp b/tests/runtime_tests/source/usertypes.basic.cpp new file mode 100644 index 00000000..a35e8c9a --- /dev/null +++ b/tests/runtime_tests/source/usertypes.basic.cpp @@ -0,0 +1,289 @@ +// 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 "sol_test.hpp" + +#include "common_classes.hpp" + +#include + + +TEST_CASE("usertype/usertype", "Show that we can create classes from usertype and use them") { + sol::state lua; + + sol::usertype lc = lua.new_usertype("fuser", "add", &fuser::add, "add2", &fuser::add2); + + lua.safe_script( + "a = fuser:new()\n" + "b = a:add(1)\n" + "c = a:add2(1)\n"); + + sol::object a = lua.get("a"); + sol::object b = lua.get("b"); + sol::object c = lua.get("c"); + REQUIRE((a.is())); + auto atype = a.get_type(); + auto btype = b.get_type(); + auto ctype = c.get_type(); + REQUIRE((atype == sol::type::userdata)); + REQUIRE((btype == sol::type::number)); + REQUIRE((ctype == sol::type::number)); + int bresult = b.as(); + int cresult = c.as(); + REQUIRE(bresult == 1); + REQUIRE(cresult == 3); +} + +TEST_CASE("usertype/usertype fundamentals", "Verify new_usertype registers basic member functions and a constructor") { + sol::state lua; + + lua.new_usertype("fuser", "add", &fuser::add, "add2", &fuser::add2); + + lua.safe_script( + "a = fuser.new()\n" + "b = a:add(1)\n" + "c = a:add2(1)\n"); + + sol::object a = lua.get("a"); + sol::object b = lua.get("b"); + sol::object c = lua.get("c"); + REQUIRE((a.is())); + auto atype = a.get_type(); + auto btype = b.get_type(); + auto ctype = c.get_type(); + REQUIRE((atype == sol::type::userdata)); + REQUIRE((btype == sol::type::number)); + REQUIRE((ctype == sol::type::number)); + int bresult = b.as(); + int cresult = c.as(); + REQUIRE(bresult == 1); + REQUIRE(cresult == 3); +} + +TEST_CASE("usertype/safety", "crash with an exception -- not a segfault -- on bad userdata calls") { + class Test { + public: + void sayHello() { + std::cout << "Hey\n"; + } + }; + + sol::state lua; + lua.new_usertype("Test", "sayHello", &Test::sayHello); + static const std::string code = R"( + local t = Test.new() + t:sayHello() --Works fine + t.sayHello() --Uh oh. + )"; + auto result = lua.safe_script(code, sol::script_pass_on_error); + REQUIRE_FALSE(result.valid()); +} + +TEST_CASE("regressions/one", "issue number 48") { + sol::state lua; + lua.new_usertype("vars", "boop", &vars::boop); + auto code + = "beep = vars.new()\n" + "beep.boop = 1"; + auto result1 = lua.safe_script(code, sol::script_pass_on_error); + REQUIRE(result1.valid()); + // test for segfault + auto my_var = lua.get("beep"); + auto& my_var_ref = lua.get("beep"); + auto* my_var_ptr = lua.get("beep"); + REQUIRE(my_var.boop == 1); + REQUIRE(my_var_ref.boop == 1); + REQUIRE(my_var_ptr->boop == 1); + REQUIRE(std::addressof(my_var_ref) == my_var_ptr); + std::cout << "----- end of 3" << std::endl; +} + +TEST_CASE("usertype/issue-number-twenty-five", "Using pointers and references from C++ classes in Lua") { + struct test { + int x = 0; + test& set() { + x = 10; + return *this; + } + + int get() { + return x; + } + + test* pget() { + return this; + } + + test create_get() { + return *this; + } + + int fun(int xa) { + return xa * 10; + } + }; + + sol::state lua; + lua.open_libraries(sol::lib::base); + lua.new_usertype("test", "set", &test::set, "get", &test::get, "pointer_get", &test::pget, "fun", &test::fun, "create_get", &test::create_get); + { + auto result = lua.safe_script("x = test.new()", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("assert(x:set():get() == 10)", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("y = x:pointer_get()", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("y:set():get()", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("y:fun(10)", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("x:fun(10)", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("assert(y:fun(10) == x:fun(10), '...')", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("assert(y:fun(10) == 100, '...')", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("assert(y:set():get() == y:set():get(), '...')", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("assert(y:set():get() == 10, '...')", sol::script_pass_on_error); + REQUIRE(result.valid()); + } +} + +TEST_CASE("usertype/issue-number-thirty-five", "using value types created from lua-called C++ code, fixing user-defined types with constructors") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + sol::constructors> ctor; + lua.new_usertype("Vec", ctor, "normalized", &Vec::normalized, "length", &Vec::length); + + { + auto result = lua.safe_script( + "v = Vec.new(1, 2, 3)\n" + "print(v:length())"); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script( + "v = Vec.new(1, 2, 3)\n" + "print(v:normalized():length())"); + REQUIRE(result.valid()); + } +} + +TEST_CASE("usertype/lua-stored-usertype", "ensure usertype values can be stored without keeping usertype object alive") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + { + sol::constructors> ctor; + sol::usertype udata = lua.new_usertype("Vec", ctor, "normalized", &Vec::normalized, "length", &Vec::length); + // usertype dies, but still usable in lua! + } + + { + auto result = lua.safe_script( + "collectgarbage()\n" + "v = Vec.new(1, 2, 3)\n" + "print(v:length())"); + REQUIRE(result.valid()); + } + + { + auto result = lua.safe_script( + "v = Vec.new(1, 2, 3)\n" + "print(v:normalized():length())"); + REQUIRE(result.valid()); + } +} + +TEST_CASE("usertype/get-set-references", "properly get and set with std::ref semantics. Note that to get, we must not use Unqualified on the type...") { + std::cout << "----- in 4" << std::endl; + sol::state lua; + + lua.new_usertype("vars", "boop", &vars::boop); + vars var{}; + vars rvar{}; + std::cout << "setting beep" << std::endl; + lua.set("beep", var); + std::cout << "setting rbeep" << std::endl; + lua.set("rbeep", std::ref(rvar)); + std::cout << "getting my_var" << std::endl; + auto& my_var = lua.get("beep"); + std::cout << "setting rbeep" << std::endl; + auto& ref_var = lua.get>("rbeep"); + vars& proxy_my_var = lua["beep"]; + std::reference_wrapper proxy_ref_var = lua["rbeep"]; + var.boop = 2; + rvar.boop = 5; + + // Was return as a value: var must be diferent from "beep" + REQUIRE_FALSE(std::addressof(var) == std::addressof(my_var)); + REQUIRE_FALSE(std::addressof(proxy_my_var) == std::addressof(var)); + REQUIRE((my_var.boop == 0)); + REQUIRE(var.boop != my_var.boop); + + REQUIRE(std::addressof(ref_var) == std::addressof(rvar)); + REQUIRE(std::addressof(proxy_ref_var.get()) == std::addressof(rvar)); + REQUIRE(rvar.boop == 5); + REQUIRE(rvar.boop == ref_var.boop); + std::cout << "----- end of 4" << std::endl; +} + +TEST_CASE("usertype/const-pointer", "Make sure const pointers can be taken") { + struct A_x { + int x = 201; + }; + struct B_foo { + int foo(const A_x* a) { + return a->x; + }; + }; + + sol::state lua; + lua.new_usertype("B", "foo", &B_foo::foo); + lua.set("a", A_x()); + lua.set("b", B_foo()); + lua.safe_script("x = b:foo(a)"); + int x = lua["x"]; + REQUIRE(x == 201); + std::cout << "----- end of 6" << std::endl; +} diff --git a/tests/runtime_tests/source/usertypes.constructors.cpp b/tests/runtime_tests/source/usertypes.constructors.cpp new file mode 100644 index 00000000..532df524 --- /dev/null +++ b/tests/runtime_tests/source/usertypes.constructors.cpp @@ -0,0 +1,206 @@ +// 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 "sol_test.hpp" + +#include "common_classes.hpp" + +#include + + +struct matrix_xf { + float a, b; + + static matrix_xf from_lua_table(sol::table t) { + matrix_xf m; + m.a = t[1][1]; + m.b = t[1][2]; + return m; + } +}; + +struct matrix_xi { + int a, b; + + static matrix_xi from_lua_table(sol::table t) { + matrix_xi m; + m.a = t[1][1]; + m.b = t[1][2]; + return m; + } +}; + +TEST_CASE("usertype/call_constructor", "make sure lua types can be constructed with function call constructors") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("thing", "v", &thing::v, sol::call_constructor, sol::constructors, sol::types>()); + + lua.safe_script(R"( +t = thing(256) +)"); + + thing& y = lua["t"]; + INFO(y.v); + REQUIRE(y.v == 256); +} + +TEST_CASE("usertype/call_constructor factories", "make sure tables can be passed to factory-based call constructors") { + sol::state lua; + lua.open_libraries(); + + lua.new_usertype("mat", sol::call_constructor, sol::factories(&matrix_xf::from_lua_table)); + + lua.safe_script("m = mat{ {1.1, 2.2} }"); + + lua.new_usertype("mati", sol::call_constructor, sol::factories(&matrix_xi::from_lua_table)); + + lua.safe_script("mi = mati{ {1, 2} }"); + + matrix_xf& m = lua["m"]; + REQUIRE(m.a == 1.1f); + REQUIRE(m.b == 2.2f); + matrix_xi& mi = lua["mi"]; + REQUIRE(mi.a == 1); + REQUIRE(mi.b == 2); +} + +TEST_CASE("usertype/call_constructor metatable check", "prevent metatable regression") { + class class01 { + public: + int x = 57; + class01() { + } + }; + + class class02 { + public: + int x = 50; + class02() { + } + class02(const class01& other) : x(other.x) { + } + }; + + sol::state lua; + + lua.new_usertype("class01", sol::call_constructor, sol::constructors, sol::types>()); + + lua.new_usertype("class02", sol::call_constructor, sol::constructors, sol::types, sol::types>()); + + REQUIRE_NOTHROW(lua.safe_script(R"( +x = class01() +y = class02(x) +)")); + class02& y = lua["y"]; + REQUIRE(y.x == 57); +} + +TEST_CASE("usertype/blank_constructor", "make sure lua types cannot be constructed with arguments if a blank / empty constructor is provided") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("thing", "v", &thing::v, sol::call_constructor, sol::constructors<>()); + + auto result = lua.safe_script("t = thing(256)", sol::script_pass_on_error); + REQUIRE_FALSE(result.valid()); +} + +TEST_CASE("usertype/no_constructor", "make sure lua types cannot be constructed if a blank / empty constructor is provided") { + SECTION("order1") { + sol::state lua; + lua.open_libraries(sol::lib::base); + lua.new_usertype("thing", "v", &thing::v, sol::call_constructor, sol::no_constructor); + auto result = lua.safe_script("t = thing()", sol::script_pass_on_error); + REQUIRE_FALSE(result.valid()); + } + + SECTION("order2") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("thing", sol::call_constructor, sol::no_constructor, "v", &thing::v); + auto result = lua.safe_script("t = thing.new()", sol::script_pass_on_error); + REQUIRE_FALSE(result.valid()); + } + + SECTION("new no_constructor") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("thing", sol::meta_function::construct, sol::no_constructor); + auto result = lua.safe_script("t = 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_usertype("thing", sol::call_constructor, sol::no_constructor); + auto result = lua.safe_script("t = thing()", sol::script_pass_on_error); + REQUIRE_FALSE(result.valid()); + } +} + +TEST_CASE("usertype/constructor list", "Show that we can create classes from usertype and use them with multiple constructors") { + + sol::state lua; + + sol::constructors, sol::types, sol::types> con; + sol::usertype lc = lua.new_usertype("fuser", con, "add", &crapola::fuser::add, "add2", &crapola::fuser::add2); + + lua.safe_script( + "a = fuser.new(2)\n" + "u = a:add(1)\n" + "v = a:add2(1)\n" + "b = fuser:new()\n" + "w = b:add(1)\n" + "x = b:add2(1)\n" + "c = fuser.new(2, 3)\n" + "y = c:add(1)\n" + "z = c:add2(1)\n"); + sol::object a = lua.get("a"); + auto atype = a.get_type(); + REQUIRE((atype == sol::type::userdata)); + sol::object u = lua.get("u"); + sol::object v = lua.get("v"); + REQUIRE((u.as() == 3)); + REQUIRE((v.as() == 5)); + + sol::object b = lua.get("b"); + auto btype = b.get_type(); + REQUIRE((btype == sol::type::userdata)); + sol::object w = lua.get("w"); + sol::object x = lua.get("x"); + REQUIRE((w.as() == 1)); + REQUIRE((x.as() == 3)); + + sol::object c = lua.get("c"); + auto ctype = c.get_type(); + REQUIRE((ctype == sol::type::userdata)); + sol::object y = lua.get("y"); + sol::object z = lua.get("z"); + REQUIRE((y.as() == 7)); + REQUIRE((z.as() == 9)); +} diff --git a/tests/runtime_tests/source/usertypes.cpp b/tests/runtime_tests/source/usertypes.cpp index 4b9f7bae..db4304bf 100644 --- a/tests/runtime_tests/source/usertypes.cpp +++ b/tests/runtime_tests/source/usertypes.cpp @@ -31,16 +31,6 @@ #include #include -struct thing { - int v = 100; - - thing() { - } - thing(int x) - : v(x) { - } -}; - struct self_test { int bark; @@ -62,154 +52,6 @@ struct self_test { } }; -struct matrix_xf { - float a, b; - - static matrix_xf from_lua_table(sol::table t) { - matrix_xf m; - m.a = t[1][1]; - m.b = t[1][2]; - return m; - } -}; - -struct matrix_xi { - int a, b; - - static matrix_xi from_lua_table(sol::table t) { - matrix_xi m; - m.a = t[1][1]; - m.b = t[1][2]; - return m; - } -}; - -TEST_CASE("usertype/usertype", "Show that we can create classes from usertype and use them") { - sol::state lua; - - sol::usertype lc = lua.new_usertype("fuser", "add", &fuser::add, "add2", &fuser::add2); - - lua.safe_script( - "a = fuser:new()\n" - "b = a:add(1)\n" - "c = a:add2(1)\n"); - - sol::object a = lua.get("a"); - sol::object b = lua.get("b"); - sol::object c = lua.get("c"); - REQUIRE((a.is())); - auto atype = a.get_type(); - auto btype = b.get_type(); - auto ctype = c.get_type(); - REQUIRE((atype == sol::type::userdata)); - REQUIRE((btype == sol::type::number)); - REQUIRE((ctype == sol::type::number)); - int bresult = b.as(); - int cresult = c.as(); - REQUIRE(bresult == 1); - REQUIRE(cresult == 3); -} - -TEST_CASE("usertype/usertype-constructors", "Show that we can create classes from usertype and use them with multiple constructors") { - - sol::state lua; - - sol::constructors, sol::types, sol::types> con; - sol::usertype lc = lua.new_usertype("fuser", - con, - "add", &crapola::fuser::add, - "add2", &crapola::fuser::add2); - - lua.safe_script( - "a = fuser.new(2)\n" - "u = a:add(1)\n" - "v = a:add2(1)\n" - "b = fuser:new()\n" - "w = b:add(1)\n" - "x = b:add2(1)\n" - "c = fuser.new(2, 3)\n" - "y = c:add(1)\n" - "z = c:add2(1)\n"); - sol::object a = lua.get("a"); - auto atype = a.get_type(); - REQUIRE((atype == sol::type::userdata)); - sol::object u = lua.get("u"); - sol::object v = lua.get("v"); - REQUIRE((u.as() == 3)); - REQUIRE((v.as() == 5)); - - sol::object b = lua.get("b"); - auto btype = b.get_type(); - REQUIRE((btype == sol::type::userdata)); - sol::object w = lua.get("w"); - sol::object x = lua.get("x"); - REQUIRE((w.as() == 1)); - REQUIRE((x.as() == 3)); - - sol::object c = lua.get("c"); - auto ctype = c.get_type(); - REQUIRE((ctype == sol::type::userdata)); - sol::object y = lua.get("y"); - sol::object z = lua.get("z"); - REQUIRE((y.as() == 7)); - REQUIRE((z.as() == 9)); -} - -TEST_CASE("usertype/usertype-utility", "Show internal management of classes registered through new_usertype") { - sol::state lua; - - lua.new_usertype("fuser", "add", &fuser::add, "add2", &fuser::add2); - - lua.safe_script( - "a = fuser.new()\n" - "b = a:add(1)\n" - "c = a:add2(1)\n"); - - sol::object a = lua.get("a"); - sol::object b = lua.get("b"); - sol::object c = lua.get("c"); - REQUIRE((a.is())); - auto atype = a.get_type(); - auto btype = b.get_type(); - auto ctype = c.get_type(); - REQUIRE((atype == sol::type::userdata)); - REQUIRE((btype == sol::type::number)); - REQUIRE((ctype == sol::type::number)); - int bresult = b.as(); - int cresult = c.as(); - REQUIRE(bresult == 1); - REQUIRE(cresult == 3); -} - -TEST_CASE("usertype/usertype-utility-derived", "usertype classes must play nice when a derived class does not overload a publically visible base function") { - sol::state lua; - lua.open_libraries(sol::lib::base); - sol::constructors> basector; - sol::usertype baseusertype = lua.new_usertype("Base", basector, "get_num", &Base::get_num); - - lua.safe_script("base = Base.new(5)"); - { - auto result = lua.safe_script("print(base:get_num())", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - - sol::constructors> derivedctor; - sol::usertype derivedusertype = lua.new_usertype("Derived", derivedctor, - "get_num_10", &Derived::get_num_10, - "get_num", &Derived::get_num); - - lua.safe_script("derived = Derived.new(7)"); - lua.safe_script( - "dgn = derived:get_num()\n" - "print(dgn)"); - lua.safe_script( - "dgn10 = derived:get_num_10()\n" - "print(dgn10)"); - - REQUIRE((lua.get("dgn10") == 70)); - REQUIRE((lua.get("dgn") == 7)); -} - TEST_CASE("usertype/self-referential usertype", "usertype classes must play nice when C++ object types are requested for C++ code") { sol::state lua; lua.open_libraries(sol::lib::base); @@ -224,178 +66,6 @@ TEST_CASE("usertype/self-referential usertype", "usertype classes must play nice REQUIRE(result.valid()); } -TEST_CASE("usertype/issue-number-twenty-five", "Using pointers and references from C++ classes in Lua") { - struct test { - int x = 0; - test& set() { - x = 10; - return *this; - } - - int get() { - return x; - } - - test* pget() { - return this; - } - - test create_get() { - return *this; - } - - int fun(int xa) { - return xa * 10; - } - }; - - sol::state lua; - lua.open_libraries(sol::lib::base); - lua.new_usertype("test", "set", &test::set, "get", &test::get, "pointer_get", &test::pget, "fun", &test::fun, "create_get", &test::create_get); - { - auto result = lua.safe_script("x = test.new()", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("assert(x:set():get() == 10)", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("y = x:pointer_get()", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("y:set():get()", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("y:fun(10)", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("x:fun(10)", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("assert(y:fun(10) == x:fun(10), '...')", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("assert(y:fun(10) == 100, '...')", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("assert(y:set():get() == y:set():get(), '...')", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("assert(y:set():get() == 10, '...')", sol::script_pass_on_error); - REQUIRE(result.valid()); - } -} - -TEST_CASE("usertype/issue-number-thirty-five", "using value types created from lua-called C++ code, fixing user-defined types with constructors") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - sol::constructors> ctor; - sol::usertype udata = lua.new_usertype("Vec", ctor, "normalized", &Vec::normalized, "length", &Vec::length); - - { - auto result = lua.safe_script( - "v = Vec.new(1, 2, 3)\n" - "print(v:length())"); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script( - "v = Vec.new(1, 2, 3)\n" - "print(v:normalized():length())"); - REQUIRE(result.valid()); - } -} - -TEST_CASE("usertype/lua-stored-usertype", "ensure usertype values can be stored without keeping usertype object alive") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - { - sol::constructors> ctor; - sol::usertype udata = lua.new_usertype("Vec", - ctor, - "normalized", &Vec::normalized, - "length", &Vec::length); - - // usertype dies, but still usable in lua! - } - - { - auto result = lua.safe_script( - "collectgarbage()\n" - "v = Vec.new(1, 2, 3)\n" - "print(v:length())"); - REQUIRE(result.valid()); - } - - { - auto result = lua.safe_script( - "v = Vec.new(1, 2, 3)\n" - "print(v:normalized():length())"); - REQUIRE(result.valid()); - } -} - -TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as member variables for usertype") { - sol::state lua; - lua.open_libraries(sol::lib::base); - sol::constructors> ctor; - sol::usertype udata = lua.new_usertype("Vec", - ctor, - "x", &Vec::x, - "y", &Vec::y, - "z", &Vec::z, - "normalized", &Vec::normalized, - "length", &Vec::length); - - REQUIRE_NOTHROW(lua.safe_script( - "v = Vec.new(1, 2, 3)\n" - "v2 = Vec.new(0, 1, 0)\n" - "print(v:length())\n")); - REQUIRE_NOTHROW(lua.safe_script( - "v.x = 2\n" - "v2.y = 2\n" - "print(v.x, v.y, v.z)\n" - "print(v2.x, v2.y, v2.z)\n")); - REQUIRE_NOTHROW(lua.safe_script( - "assert(v.x == 2)\n" - "assert(v2.x == 0)\n" - "assert(v2.y == 2)\n")); - REQUIRE_NOTHROW(lua.safe_script( - "v.x = 3\n" - "local x = v.x\n" - "assert(x == 3)\n")); - - struct breaks { - sol::function f; - }; - - lua.open_libraries(sol::lib::base); - lua.set("b", breaks()); - lua.new_usertype("breaks", - "f", &breaks::f); - - breaks& b = lua["b"]; - { - auto result = lua.safe_script("b.f = function () print('BARK!') end", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - { - auto result = lua.safe_script("b.f()", sol::script_pass_on_error); - REQUIRE(result.valid()); - } - REQUIRE_NOTHROW(b.f()); -} - TEST_CASE("usertype/nonmember-functions", "let users set non-member functions that take unqualified T as first parameter to usertype") { sol::state lua; lua.open_libraries(sol::lib::base); @@ -425,354 +95,6 @@ TEST_CASE("usertype/nonmember-functions", "let users set non-member functions th std::cout << "----- end of 1" << std::endl; } -TEST_CASE("regressions/one", "issue number 48") { - sol::state lua; - lua.new_usertype("vars", - "boop", &vars::boop); - auto code = - "beep = vars.new()\n" - "beep.boop = 1"; - auto result1 = lua.safe_script(code, sol::script_pass_on_error); - REQUIRE(result1.valid()); - // test for segfault - auto my_var = lua.get("beep"); - auto& my_var_ref = lua.get("beep"); - auto* my_var_ptr = lua.get("beep"); - REQUIRE(my_var.boop == 1); - REQUIRE(my_var_ref.boop == 1); - REQUIRE(my_var_ptr->boop == 1); - REQUIRE(std::addressof(my_var_ref) == my_var_ptr); - std::cout << "----- end of 3" << std::endl; -} - -TEST_CASE("usertype/get-set-references", "properly get and set with std::ref semantics. Note that to get, we must not use Unqualified on the type...") { - std::cout << "----- in 4" << std::endl; - sol::state lua; - - lua.new_usertype("vars", - "boop", &vars::boop); - vars var{}; - vars rvar{}; - std::cout << "setting beep" << std::endl; - lua.set("beep", var); - std::cout << "setting rbeep" << std::endl; - lua.set("rbeep", std::ref(rvar)); - std::cout << "getting my_var" << std::endl; - auto& my_var = lua.get("beep"); - std::cout << "setting rbeep" << std::endl; - auto& ref_var = lua.get>("rbeep"); - vars& proxy_my_var = lua["beep"]; - std::reference_wrapper proxy_ref_var = lua["rbeep"]; - var.boop = 2; - rvar.boop = 5; - - // Was return as a value: var must be diferent from "beep" - REQUIRE_FALSE(std::addressof(var) == std::addressof(my_var)); - REQUIRE_FALSE(std::addressof(proxy_my_var) == std::addressof(var)); - REQUIRE((my_var.boop == 0)); - REQUIRE(var.boop != my_var.boop); - - REQUIRE(std::addressof(ref_var) == std::addressof(rvar)); - REQUIRE(std::addressof(proxy_ref_var.get()) == std::addressof(rvar)); - REQUIRE(rvar.boop == 5); - REQUIRE(rvar.boop == ref_var.boop); - std::cout << "----- end of 4" << std::endl; -} - -TEST_CASE("usertype/const-pointer", "Make sure const pointers can be taken") { - struct A_x { - int x = 201; - }; - struct B_foo { - int foo(const A_x* a) { - return a->x; - }; - }; - - sol::state lua; - lua.new_usertype("B", - "foo", &B_foo::foo); - lua.set("a", A_x()); - lua.set("b", B_foo()); - lua.safe_script("x = b:foo(a)"); - int x = lua["x"]; - REQUIRE(x == 201); - std::cout << "----- end of 6" << std::endl; -} - -TEST_CASE("usertype/overloading", "Check if overloading works properly for usertypes") { - struct woof { - int var; - - int func(int x) { - return var + x; - } - - double func2(int x, int y) { - return var + x + y + 0.5; - } - - std::string func2s(int x, std::string y) { - return y + " " + std::to_string(x); - } - }; - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_usertype("woof", - "var", &woof::var, - "func", sol::overload(&woof::func, &woof::func2, &woof::func2s)); - - const std::string bark_58 = "bark 58"; - - REQUIRE_NOTHROW(lua.safe_script( - "r = woof:new()\n" - "a = r:func(1)\n" - "b = r:func(1, 2)\n" - "c = r:func(58, 'bark')\n")); - REQUIRE((lua["a"] == 1)); - REQUIRE((lua["b"] == 3.5)); - REQUIRE((lua["c"] == bark_58)); - auto result = lua.safe_script("r:func(1,2,'meow')", sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); - std::cout << "----- end of 7" << std::endl; -} - -TEST_CASE("usertype/overloading_values", "ensure overloads handle properly") { - struct overloading_test { - int print(int i) { - INFO("Integer print: " << i); - return 500 + i; - } - int print() { - INFO("No param print."); - return 500; - } - }; - - sol::state lua; - lua.new_usertype("overloading_test", sol::constructors<>(), - "print", sol::overload(static_cast(&overloading_test::print), static_cast(&overloading_test::print)), - "print2", sol::overload(static_cast(&overloading_test::print), static_cast(&overloading_test::print))); - lua.set("test", overloading_test()); - - sol::function f0_0 = lua.load("return test:print()"); - sol::function f0_1 = lua.load("return test:print2()"); - sol::function f1_0 = lua.load("return test:print(24)"); - sol::function f1_1 = lua.load("return test:print2(24)"); - int res = f0_0(); - int res2 = f0_1(); - int res3 = f1_0(); - int res4 = f1_1(); - - REQUIRE(res == 500); - REQUIRE(res2 == 500); - - REQUIRE(res3 == 524); - REQUIRE(res4 == 524); - std::cout << "----- end of 8" << std::endl; -} - -TEST_CASE("usertype/reference-and-constness", "Make sure constness compiles properly and errors out at runtime") { - struct bark { - int var = 50; - }; - struct woof { - bark b; - }; - - struct nested { - const int f = 25; - }; - - struct outer { - nested n; - }; - - sol::state lua; - lua.new_usertype("woof", - "b", &woof::b); - lua.new_usertype("bark", - "var", &bark::var); - lua.new_usertype("outer", - "n", &outer::n); - lua.set("w", woof()); - lua.set("n", nested()); - lua.set("o", outer()); - lua.set("f", sol::c_call); - lua.safe_script(R"( - x = w.b - x.var = 20 - val = w.b.var == x.var - v = f(n); - )"); - - woof& w = lua["w"]; - bark& x = lua["x"]; - nested& n = lua["n"]; - int v = lua["v"]; - bool val = lua["val"]; - // enforce reference semantics - REQUIRE(std::addressof(w.b) == std::addressof(x)); - REQUIRE(n.f == 25); - REQUIRE(v == 25); - REQUIRE(val); - - { - auto result = lua.safe_script("f(n, 50)", sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); - } - { - auto result = lua.safe_script("o.n = 25", sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); - } -} - -TEST_CASE("usertype/safety", "crash with an exception -- not a segfault -- on bad userdata calls") { - class Test { - public: - void sayHello() { - std::cout << "Hey\n"; - } - }; - - sol::state lua; - lua.new_usertype("Test", "sayHello", &Test::sayHello); - static const std::string code = R"( - local t = Test.new() - t:sayHello() --Works fine - t.sayHello() --Uh oh. - )"; - auto result = lua.safe_script(code, sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); -} - -TEST_CASE("usertype/call_constructor", "make sure lua types can be constructed with function call constructors") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_usertype("thing", - "v", &thing::v, sol::call_constructor, sol::constructors, sol::types>()); - - lua.safe_script(R"( -t = thing(256) -)"); - - thing& y = lua["t"]; - INFO(y.v); - REQUIRE(y.v == 256); -} - -TEST_CASE("usertype/call_constructor-factories", "make sure tables can be passed to factory-based call constructors") { - sol::state lua; - lua.open_libraries(); - - lua.new_usertype("mat", - sol::call_constructor, sol::factories(&matrix_xf::from_lua_table)); - - lua.safe_script("m = mat{ {1.1, 2.2} }"); - - lua.new_usertype("mati", - sol::call_constructor, sol::factories(&matrix_xi::from_lua_table)); - - lua.safe_script("mi = mati{ {1, 2} }"); - - matrix_xf& m = lua["m"]; - REQUIRE(m.a == 1.1f); - REQUIRE(m.b == 2.2f); - matrix_xi& mi = lua["mi"]; - REQUIRE(mi.a == 1); - REQUIRE(mi.b == 2); -} - -TEST_CASE("usertype/call_constructor_2", "prevent metatable regression") { - class class01 { - public: - int x = 57; - class01() { - } - }; - - class class02 { - public: - int x = 50; - class02() { - } - class02(const class01& other) - : x(other.x) { - } - }; - - sol::state lua; - - lua.new_usertype("class01", - sol::call_constructor, sol::constructors, sol::types>()); - - lua.new_usertype("class02", - sol::call_constructor, sol::constructors, sol::types, sol::types>()); - - REQUIRE_NOTHROW(lua.safe_script(R"( -x = class01() -y = class02(x) -)")); - class02& y = lua["y"]; - REQUIRE(y.x == 57); -} - -TEST_CASE("usertype/blank_constructor", "make sure lua types cannot be constructed with arguments if a blank / empty constructor is provided") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_usertype("thing", - "v", &thing::v, sol::call_constructor, sol::constructors<>()); - - auto result = lua.safe_script("t = thing(256)", sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); -} - -TEST_CASE("usertype/no_constructor", "make sure lua types cannot be constructed if a blank / empty constructor is provided") { - SECTION("order1") { - sol::state lua; - lua.open_libraries(sol::lib::base); - lua.new_usertype("thing", - "v", &thing::v, - sol::call_constructor, sol::no_constructor); - auto result = lua.safe_script("t = thing()", sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); - } - - SECTION("order2") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_usertype("thing", - sol::call_constructor, sol::no_constructor, - "v", &thing::v); - auto result = lua.safe_script("t = thing.new()", sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); - } - - SECTION("new no_constructor") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.new_usertype("thing", - sol::meta_function::construct, sol::no_constructor); - auto result = lua.safe_script("t = 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_usertype("thing", - sol::call_constructor, sol::no_constructor); - auto result = lua.safe_script("t = thing()", sol::script_pass_on_error); - REQUIRE_FALSE(result.valid()); - } -} - TEST_CASE("usertype/abstract-base-class", "Ensure that abstract base classes and such can be registered") { sol::state lua; lua.new_usertype("A", "a", &abstract_A::a); diff --git a/tests/runtime_tests/source/inheritance.cpp b/tests/runtime_tests/source/usertypes.inheritance.cpp similarity index 87% rename from tests/runtime_tests/source/inheritance.cpp rename to tests/runtime_tests/source/usertypes.inheritance.cpp index a732fb3c..723b3552 100644 --- a/tests/runtime_tests/source/inheritance.cpp +++ b/tests/runtime_tests/source/usertypes.inheritance.cpp @@ -23,6 +23,8 @@ #include "sol_test.hpp" +#include "common_classes.hpp" + #include #include @@ -257,3 +259,31 @@ TEST_CASE("inheritance/runtime multi base", "test that multiple bases all work a runtime_A& a_obj = lua["obj"]; REQUIRE(a_obj.a == 5); } + +TEST_CASE("inheritance/usertype derived non-hiding", "usertype classes must play nice when a derived class does not overload a publically visible base function") { + sol::state lua; + lua.open_libraries(sol::lib::base); + sol::constructors> basector; + sol::usertype baseusertype = lua.new_usertype("Base", basector, "get_num", &Base::get_num); + + lua.safe_script("base = Base.new(5)"); + { + auto result = lua.safe_script("print(base:get_num())", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + + sol::constructors> derivedctor; + sol::usertype derivedusertype + = lua.new_usertype("Derived", derivedctor, "get_num_10", &Derived::get_num_10, "get_num", &Derived::get_num); + + lua.safe_script("derived = Derived.new(7)"); + lua.safe_script( + "dgn = derived:get_num()\n" + "print(dgn)"); + lua.safe_script( + "dgn10 = derived:get_num_10()\n" + "print(dgn10)"); + + REQUIRE((lua.get("dgn10") == 70)); + REQUIRE((lua.get("dgn") == 7)); +} diff --git a/tests/runtime_tests/source/usertypes.member_variables.cpp b/tests/runtime_tests/source/usertypes.member_variables.cpp new file mode 100644 index 00000000..13c4e04b --- /dev/null +++ b/tests/runtime_tests/source/usertypes.member_variables.cpp @@ -0,0 +1,126 @@ +// 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 "sol_test.hpp" + +#include "common_classes.hpp" + +#include + + +TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as member variables for usertype") { + sol::state lua; + lua.open_libraries(sol::lib::base); + sol::constructors> ctor; + sol::usertype udata + = lua.new_usertype("Vec", ctor, "x", &Vec::x, "y", &Vec::y, "z", &Vec::z, "normalized", &Vec::normalized, "length", &Vec::length); + + REQUIRE_NOTHROW( + lua.safe_script("v = Vec.new(1, 2, 3)\n" + "v2 = Vec.new(0, 1, 0)\n" + "print(v:length())\n")); + REQUIRE_NOTHROW( + lua.safe_script("v.x = 2\n" + "v2.y = 2\n" + "print(v.x, v.y, v.z)\n" + "print(v2.x, v2.y, v2.z)\n")); + REQUIRE_NOTHROW( + lua.safe_script("assert(v.x == 2)\n" + "assert(v2.x == 0)\n" + "assert(v2.y == 2)\n")); + REQUIRE_NOTHROW( + lua.safe_script("v.x = 3\n" + "local x = v.x\n" + "assert(x == 3)\n")); + + struct breaks { + sol::function f; + }; + + lua.open_libraries(sol::lib::base); + lua.set("b", breaks()); + lua.new_usertype("breaks", "f", &breaks::f); + + breaks& b = lua["b"]; + { + auto result = lua.safe_script("b.f = function () print('BARK!') end", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + { + auto result = lua.safe_script("b.f()", sol::script_pass_on_error); + REQUIRE(result.valid()); + } + REQUIRE_NOTHROW(b.f()); +} + +TEST_CASE("usertype/reference-and-constness", "Make sure constness compiles properly and errors out at runtime") { + struct bark { + int var = 50; + }; + struct woof { + bark b; + }; + + struct nested { + const int f = 25; + }; + + struct outer { + nested n; + }; + + sol::state lua; + lua.new_usertype("woof", "b", &woof::b); + lua.new_usertype("bark", "var", &bark::var); + lua.new_usertype("outer", "n", &outer::n); + lua.set("w", woof()); + lua.set("n", nested()); + lua.set("o", outer()); + lua.set("f", sol::c_call); + lua.safe_script(R"( + x = w.b + x.var = 20 + val = w.b.var == x.var + v = f(n); + )"); + + woof& w = lua["w"]; + bark& x = lua["x"]; + nested& n = lua["n"]; + int v = lua["v"]; + bool val = lua["val"]; + // enforce reference semantics + REQUIRE(std::addressof(w.b) == std::addressof(x)); + REQUIRE(n.f == 25); + REQUIRE(v == 25); + REQUIRE(val); + + { + auto result = lua.safe_script("f(n, 50)", sol::script_pass_on_error); + REQUIRE_FALSE(result.valid()); + } + { + auto result = lua.safe_script("o.n = 25", sol::script_pass_on_error); + REQUIRE_FALSE(result.valid()); + } +} diff --git a/tests/runtime_tests/source/usertypes.overload.cpp b/tests/runtime_tests/source/usertypes.overload.cpp new file mode 100644 index 00000000..1b3f7e80 --- /dev/null +++ b/tests/runtime_tests/source/usertypes.overload.cpp @@ -0,0 +1,89 @@ +// 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 "sol_test.hpp" + +#include "common_classes.hpp" + +#include + +struct overloading_test { + int print(int i) { + INFO("Integer print: " << i); + return 500 + i; + } + int print() { + INFO("No param print."); + return 500; + } +}; + +TEST_CASE("usertype/overloading", "Check if overloading works properly for usertypes") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("woof", "var", &woof::var, "func", sol::overload(&woof::func, &woof::func2, &woof::func2s)); + + const std::string bark_58 = "bark 58"; + + REQUIRE_NOTHROW( + lua.safe_script("r = woof:new()\n" + "a = r:func(1)\n" + "b = r:func(1, 2)\n" + "c = r:func(58, 'bark')\n")); + REQUIRE((lua["a"] == 1)); + REQUIRE((lua["b"] == 3.5)); + REQUIRE((lua["c"] == bark_58)); + auto result = lua.safe_script("r:func(1,2,'meow')", sol::script_pass_on_error); + REQUIRE_FALSE(result.valid()); + std::cout << "----- end of 7" << std::endl; +} + +TEST_CASE("usertype/overloading_values", "ensure overloads handle properly") { + sol::state lua; + lua.new_usertype("overloading_test", + sol::constructors<>(), + "print", + sol::overload( + static_cast(&overloading_test::print), static_cast(&overloading_test::print)), + "print2", + sol::overload( + static_cast(&overloading_test::print), static_cast(&overloading_test::print))); + lua.set("test", overloading_test()); + + sol::function f0_0 = lua.load("return test:print()"); + sol::function f0_1 = lua.load("return test:print2()"); + sol::function f1_0 = lua.load("return test:print(24)"); + sol::function f1_1 = lua.load("return test:print2(24)"); + int res = f0_0(); + int res2 = f0_1(); + int res3 = f1_0(); + int res4 = f1_1(); + + REQUIRE(res == 500); + REQUIRE(res2 == 500); + + REQUIRE(res3 == 524); + REQUIRE(res4 == 524); + std::cout << "----- end of 8" << std::endl; +} diff --git a/tests/runtime_tests/source/usertype_properties.cpp b/tests/runtime_tests/source/usertypes.properties.cpp similarity index 100% rename from tests/runtime_tests/source/usertype_properties.cpp rename to tests/runtime_tests/source/usertypes.properties.cpp diff --git a/tests/runtime_tests/source/usertype_runtime.cpp b/tests/runtime_tests/source/usertypes.runtime.cpp similarity index 100% rename from tests/runtime_tests/source/usertype_runtime.cpp rename to tests/runtime_tests/source/usertypes.runtime.cpp diff --git a/tests/runtime_tests/source/usertype_unique.cpp b/tests/runtime_tests/source/usertypes.unique.cpp similarity index 100% rename from tests/runtime_tests/source/usertype_unique.cpp rename to tests/runtime_tests/source/usertypes.unique.cpp diff --git a/tests/runtime_tests/source/utility.cpp b/tests/runtime_tests/source/utility.cpp index d358b58c..87d55a44 100644 --- a/tests/runtime_tests/source/utility.cpp +++ b/tests/runtime_tests/source/utility.cpp @@ -22,6 +22,7 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "sol_test.hpp" +#include "common_classes.hpp" #include @@ -106,7 +107,25 @@ TEST_CASE("utility/variant", "test that variant can be round-tripped") { #endif // C++17 } -TEST_CASE("utility/optional", "test that shit optional can be round-tripped") { +TEST_CASE("utility/optional-conversion", "test that regular optional will properly catch certain types") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("vars"); + + lua["test"] = [](sol::optional x) { + return static_cast(x); + }; + + const auto result = lua.safe_script(R"( + assert(test(vars:new())) + assert(not test(3)) + assert(not test(nil)) + )", sol::script_pass_on_error); + REQUIRE(result.valid()); +} + +TEST_CASE("utility/std optional", "test that shit optional can be round-tripped") { #ifdef SOL_CXX17_FEATURES SECTION("okay") { sol::state lua;