This attempts to be more thorough with the validations of the test, avoiding throws wherever possible to help reduce the error surface for debugging x86 builds (which, strangely enough, are not erroring in the same places that appveyor is erroring in...)

Need to begin wrok to fix wstring_convert and replace it with some decent UTF conversion algos. It's surprisingly difficult tof ind such...
Fixes #572
Fixes #569
Fixes #567
This commit is contained in:
ThePhD 2018-01-28 22:21:13 -05:00
parent 143c98450a
commit 57681ab4cd
41 changed files with 1008 additions and 590 deletions

1
.gitignore vendored
View File

@ -113,3 +113,4 @@ desktop.ini
# Miscellaneous # Miscellaneous
external/ external/
scratch/ scratch/
.idea/

View File

@ -22,6 +22,7 @@ members
.. code-block:: cpp .. code-block:: cpp
:caption: constructor: reference :caption: constructor: reference
:name: reference-constructor
reference(lua_State* L, int index = -1); reference(lua_State* L, int index = -1);
reference(lua_State* L, lua_nil_t); reference(lua_State* L, lua_nil_t);
@ -41,6 +42,8 @@ The first constructor creates a reference from the Lua stack at the specified in
Note that the last constructor has ``lua_xmove`` safety built into it. You can pin an object to a certain thread (or the main thread) by initializing it with ``sol::reference pinned(state, other_reference_object);``. This ensures that ``other_reference_object`` will exist in the state/thread of ``state``. Also note that copy/move assignment operations will also use pinning semantics if it detects that the state of the object on the right is ``lua_xmove`` compatible. (But, the ``reference`` object on the left must have a valid state as well. You can have a nil ``reference`` with a valid state by using the ``sol::reference pinned(state, sol::lua_nil)`` constructor as well.) This applies for any ``sol::reference`` derived type. Note that the last constructor has ``lua_xmove`` safety built into it. You can pin an object to a certain thread (or the main thread) by initializing it with ``sol::reference pinned(state, other_reference_object);``. This ensures that ``other_reference_object`` will exist in the state/thread of ``state``. Also note that copy/move assignment operations will also use pinning semantics if it detects that the state of the object on the right is ``lua_xmove`` compatible. (But, the ``reference`` object on the left must have a valid state as well. You can have a nil ``reference`` with a valid state by using the ``sol::reference pinned(state, sol::lua_nil)`` constructor as well.) This applies for any ``sol::reference`` derived type.
You can un-pin and null the state by doing ``ref = sol::lua_nil;``. This applies to **all derived types**, including ``sol::(protected_)function``, ``sol::thread``, ``sol::object``, ``sol::table``, and similar.
.. code-block:: cpp .. code-block:: cpp
:caption: function: push referred-to element from the stack :caption: function: push referred-to element from the stack
@ -82,7 +85,8 @@ non-members
----------- -----------
.. code-block:: cpp .. code-block:: cpp
:caption: functions: reference comparators :caption: operators: reference comparators
:name: reference-operators-comparators
bool operator==(const reference&, const reference&); bool operator==(const reference&, const reference&);
bool operator!=(const reference&, const reference&); bool operator!=(const reference&, const reference&);

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2018-01-24 05:51:13.838328 UTC // Generated 2018-01-29 03:18:59.612757 UTC
// This header was generated with sol v2.19.0 (revision 83f4b4a) // This header was generated with sol v2.19.0 (revision 143c984)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP #ifndef SOL_SINGLE_INCLUDE_HPP
@ -189,6 +189,12 @@
#endif #endif
#endif // avoiding nil defines / keywords #endif // avoiding nil defines / keywords
#ifdef SOL_USE_BOOST
#ifndef SOL_UNORDERED_MAP_COMPATIBLE_HASH
#define SOL_UNORDERED_MAP_COMPATIBLE_HASH
#endif // SOL_UNORDERED_MAP_COMPATIBLE_HASH
#endif // Boost has unordered_map with Compatible Key and CompatibleHash
// end of sol/feature_test.hpp // end of sol/feature_test.hpp
namespace sol { namespace sol {
@ -1485,10 +1491,11 @@ namespace sol {
template <typename T> template <typename T>
using is_string_constructible = any< using is_string_constructible = any<
std::is_same<unqualified_t<T>, const char*>, std::is_same<unqualified_t<T>, char>, std::is_same<unqualified_t<T>, std::string>, std::is_same<unqualified_t<T>, std::initializer_list<char>> meta::all<std::is_array<unqualified_t<T>>, std::is_same<meta::unqualified_t<std::remove_all_extents_t<meta::unqualified_t<T>>>, char>>,
std::is_same<unqualified_t<T>, const char*>,
std::is_same<unqualified_t<T>, char>, std::is_same<unqualified_t<T>, std::string>, std::is_same<unqualified_t<T>, std::initializer_list<char>>
#ifdef SOL_CXX17_FEATURES #ifdef SOL_CXX17_FEATURES
, , std::is_same<unqualified_t<T>, std::string_view>
std::is_same<unqualified_t<T>, std::string_view>
#endif #endif
>; >;
@ -4146,6 +4153,9 @@ namespace sol {
#ifdef SOL_CXX17_FEATURES #ifdef SOL_CXX17_FEATURES
#endif // C++17 features #endif // C++17 features
#ifdef SOL_USE_BOOST
#include <boost/functional/hash.hpp>
#endif
namespace sol { namespace sol {
#ifdef SOL_CXX17_FEATURES #ifdef SOL_CXX17_FEATURES
@ -4153,6 +4163,7 @@ namespace sol {
typedef std::wstring_view wstring_view; typedef std::wstring_view wstring_view;
typedef std::u16string_view u16string_view; typedef std::u16string_view u16string_view;
typedef std::u32string_view u32string_view; typedef std::u32string_view u32string_view;
typedef std::hash<std::string_view> string_view_hash;
#else #else
template <typename Char, typename Traits = std::char_traits<Char>> template <typename Char, typename Traits = std::char_traits<Char>>
struct basic_string_view { struct basic_string_view {
@ -4208,12 +4219,16 @@ namespace sol {
return size(); return size();
} }
operator std::basic_string<Char, Traits>() const {
return std::basic_string<Ch, Tr>(data(), size());
}
bool operator==(const basic_string_view& r) const { bool operator==(const basic_string_view& r) const {
return compare(p, s, r.data(), r.size()) == 0; return compare(p, s, r.data(), r.size()) == 0;
} }
bool operator==(const Char* r) const { bool operator==(const Char* r) const {
return compare(r, std::char_traits<char>::length(r), p, s) == 0; return compare(r, Traits::length(r), p, s) == 0;
} }
bool operator==(const std::basic_string<Char, Traits>& r) const { bool operator==(const std::basic_string<Char, Traits>& r) const {
@ -4233,10 +4248,50 @@ namespace sol {
} }
}; };
template <typename Ch, typename Tr = std::char_traits<Tr>>
struct basic_string_view_hash {
typedef basic_string_view<Ch, Tr> argument_type;
typedef std::size_t result_type;
template <typename Al>
result_type operator()(const std::basic_string<Ch, Tr, Al>& r) const {
return (*this)(basic_string_view<Ch>(r.c_str(), r.size()));
}
result_type operator()(const argument_type& r) const {
#ifdef SOL_USE_BOOST
return boost::hash_range(r.begin(), r.end());
#else
// Modified, from libstdc++
// An implementation attempt at Fowler No Voll, 1a.
// Supposedly, used in MSVC,
// GCC (libstdc++) uses MurmurHash of some sort for 64-bit though...?
// But, well. Can't win them all, right?
// This should normally only apply when NOT using boost,
// so this should almost never be tapped into...
std::size_t hash = 0;
const unsigned char* cptr = reinterpret_cast<const unsigned char*>(r.data());
for (std::size_t sz = r.size(); sz != 0; --sz) {
hash ^= static_cast<size_t>(*cptr++);
hash *= static_cast<size_t>(1099511628211ULL);
}
return hash;
#endif
}
};
} // namespace sol
namespace std {
template <typename Ch, typename Tr>
struct hash< ::sol::basic_string_view<Ch, Tr> > : ::sol::basic_string_view_hash<Ch, Tr> {};
} // namespace std
namespace sol {
using string_view = basic_string_view<char>; using string_view = basic_string_view<char>;
using wstring_view = basic_string_view<wchar_t>; using wstring_view = basic_string_view<wchar_t>;
using u16string_view = basic_string_view<char16_t>; using u16string_view = basic_string_view<char16_t>;
using u32string_view = basic_string_view<char32_t>; using u32string_view = basic_string_view<char32_t>;
using string_view_hash = std::hash<string_view>;
#endif // C++17 Support #endif // C++17 Support
} // namespace sol } // namespace sol
@ -6231,6 +6286,7 @@ namespace sol {
return; return;
} }
if (r.ref == LUA_NOREF) { if (r.ref == LUA_NOREF) {
luastate = r.luastate;
ref = LUA_NOREF; ref = LUA_NOREF;
return; return;
} }
@ -6254,6 +6310,7 @@ namespace sol {
return; return;
} }
if (r.ref == LUA_NOREF) { if (r.ref == LUA_NOREF) {
luastate = r.luastate;
ref = LUA_NOREF; ref = LUA_NOREF;
return; return;
} }
@ -6412,6 +6469,15 @@ namespace sol {
return *this; return *this;
} }
basic_reference& operator=(const lua_nil_t&) noexcept {
if (valid()) {
deref();
}
luastate = nullptr;
ref = LUA_NOREF;
return *this;
}
template <typename Super> template <typename Super>
basic_reference& operator=(proxy_base<Super>&& r); basic_reference& operator=(proxy_base<Super>&& r);
@ -10586,11 +10652,11 @@ namespace sol {
return call_into_lua<check_args, clean_stack>(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); return call_into_lua<check_args, clean_stack>(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
} }
inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) { inline call_syntax get_call_syntax(lua_State* L, const string_view& key, int index) {
if (lua_gettop(L) == 0) { if (lua_gettop(L) == 0) {
return call_syntax::dot; return call_syntax::dot;
} }
luaL_getmetatable(L, key.c_str()); luaL_getmetatable(L, key.data());
auto pn = pop_n(L, 1); auto pn = pop_n(L, 1);
if (lua_compare(L, -1, index, LUA_OPEQ) != 1) { if (lua_compare(L, -1, index, LUA_OPEQ) != 1) {
return call_syntax::dot; return call_syntax::dot;
@ -11916,7 +11982,7 @@ namespace sol {
inline int construct(lua_State* L) { inline int construct(lua_State* L) {
static const auto& meta = usertype_traits<T>::metatable(); static const auto& meta = usertype_traits<T>::metatable();
int argcount = lua_gettop(L); int argcount = lua_gettop(L);
call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits<T>::user_metatable()[0], 1) : call_syntax::dot; call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1) : call_syntax::dot;
argcount -= static_cast<int>(syntax); argcount -= static_cast<int>(syntax);
T* obj = detail::usertype_allocate<T>(L); T* obj = detail::usertype_allocate<T>(L);
@ -12215,7 +12281,7 @@ namespace sol {
static int call(lua_State* L, F&) { static int call(lua_State* L, F&) {
const auto& metakey = usertype_traits<T>::metatable(); const auto& metakey = usertype_traits<T>::metatable();
int argcount = lua_gettop(L); int argcount = lua_gettop(L);
call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits<T>::user_metatable()[0], 1) : call_syntax::dot; call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1) : call_syntax::dot;
argcount -= static_cast<int>(syntax); argcount -= static_cast<int>(syntax);
T* obj = detail::usertype_allocate<T>(L); T* obj = detail::usertype_allocate<T>(L);
@ -12264,7 +12330,7 @@ namespace sol {
}; };
static int call(lua_State* L, F& f) { static int call(lua_State* L, F& f) {
call_syntax syntax = stack::get_call_syntax(L, &usertype_traits<T>::user_metatable()[0], 1); call_syntax syntax = stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1);
int syntaxval = static_cast<int>(syntax); int syntaxval = static_cast<int>(syntax);
int argcount = lua_gettop(L) - syntaxval; int argcount = lua_gettop(L) - syntaxval;
return construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f); return construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);
@ -13511,7 +13577,7 @@ namespace sol {
using base_t::lua_state; using base_t::lua_state;
basic_function() = default; basic_function() = default;
template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_function>>, meta::neg<std::is_same<base_t, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_function>>, meta::neg<std::is_same<base_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_function(T&& r) noexcept basic_function(T&& r) noexcept
: base_t(std::forward<T>(r)) { : base_t(std::forward<T>(r)) {
#ifdef SOL_SAFE_REFERENCES #ifdef SOL_SAFE_REFERENCES
@ -13532,6 +13598,9 @@ namespace sol {
basic_function(stack_reference&& r) basic_function(stack_reference&& r)
: basic_function(r.lua_state(), r.stack_index()) { : basic_function(r.lua_state(), r.stack_index()) {
} }
basic_function(lua_nil_t n)
: base_t(n) {
}
template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_function(lua_State* L, T&& r) basic_function(lua_State* L, T&& r)
: base_t(L, std::forward<T>(r)) { : base_t(L, std::forward<T>(r)) {
@ -13753,7 +13822,7 @@ namespace sol {
handler_t error_handler; handler_t error_handler;
basic_protected_function() = default; basic_protected_function() = default;
template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_protected_function>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_protected_function>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_protected_function(T&& r) noexcept basic_protected_function(T&& r) noexcept
: base_t(std::forward<T>(r)), error_handler(get_default_handler(r.lua_state())) { : base_t(std::forward<T>(r)), error_handler(get_default_handler(r.lua_state())) {
#ifdef SOL_SAFE_REFERENCES #ifdef SOL_SAFE_REFERENCES
@ -13819,6 +13888,10 @@ namespace sol {
stack::check<basic_protected_function>(lua_state(), -1, handler); stack::check<basic_protected_function>(lua_state(), -1, handler);
#endif // Safety #endif // Safety
} }
basic_protected_function(lua_nil_t n)
: base_t(n), error_handler(n) {
}
basic_protected_function(lua_State* L, int index = -1) basic_protected_function(lua_State* L, int index = -1)
: basic_protected_function(L, index, get_default_handler(L)) { : basic_protected_function(L, index, get_default_handler(L)) {
@ -16640,8 +16713,20 @@ namespace sol {
#include <cstdio> #include <cstdio>
#include <bitset> #include <bitset>
#ifdef SOL_USE_BOOST
#include <boost/unordered_map.hpp>
#endif // Using Boost
namespace sol { namespace sol {
namespace usertype_detail { namespace usertype_detail {
#ifdef SOL_USE_BOOST
template <typename K, typename V, typename H = std::hash<K>, typename E = std::equal_to<>>
using map_t = boost::unordered_map<K, V, H, E>;
#else
template <typename K, typename V, typename H = std::hash<K>, typename E = std::equal_to<>>
using map_t = std::unordered_map<K, V, H, E>;
#endif // Boost map target
const int metatable_index = 2; const int metatable_index = 2;
const int metatable_core_index = 3; const int metatable_core_index = 3;
const int filler_index = 4; const int filler_index = 4;
@ -16666,8 +16751,8 @@ namespace sol {
: index(index), new_index(newindex), runtime_target(runtimetarget) { : index(index), new_index(newindex), runtime_target(runtimetarget) {
} }
}; };
typedef std::unordered_map<std::string, call_information> mapping_t; typedef map_t<std::string, call_information> mapping_t;
struct variable_wrapper { struct variable_wrapper {
virtual int index(lua_State* L) = 0; virtual int index(lua_State* L) = 0;
@ -16693,8 +16778,8 @@ namespace sol {
} }
}; };
typedef std::unordered_map<std::string, std::unique_ptr<variable_wrapper>> variable_map; typedef map_t<std::string, std::unique_ptr<variable_wrapper>> variable_map;
typedef std::unordered_map<std::string, object> function_map; typedef map_t<std::string, object> function_map;
struct simple_map { struct simple_map {
const char* metakey; const char* metakey;
@ -16815,8 +16900,8 @@ namespace sol {
inline int indexing_fail(lua_State* L) { inline int indexing_fail(lua_State* L) {
if (is_index) { if (is_index) {
#if 0 //def SOL_SAFE_USERTYPE #if 0 //def SOL_SAFE_USERTYPE
auto maybeaccessor = stack::get<optional<string_detail::string_shim>>(L, is_index ? -1 : -2); auto maybeaccessor = stack::get<optional<string_view>>(L, is_index ? -1 : -2);
string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); string_view accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)"));
return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data()); return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data());
#else #else
if (is_toplevel(L)) { if (is_toplevel(L)) {
@ -16846,13 +16931,21 @@ namespace sol {
if (is_simple) { if (is_simple) {
simple_map& sm = stack::get<user<simple_map>>(L, upvalue_index(simple_metatable_index)); simple_map& sm = stack::get<user<simple_map>>(L, upvalue_index(simple_metatable_index));
function_map& functions = sm.functions; function_map& functions = sm.functions;
optional<std::string> maybeaccessor = stack::get<optional<std::string>>(L, 2); optional<string_view> maybeaccessor = stack::get<optional<string_view>>(L, 2);
if (!maybeaccessor) { if (!maybeaccessor) {
return; return;
} }
std::string& accessor = maybeaccessor.value(); string_view& accessor_view = maybeaccessor.value();
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
auto preexistingit = functions.find(accessor_view, string_view_hash(), std::equal_to<string_view>());
#else
std::string accessor(accessor_view.data(), accessor_view.size());
auto preexistingit = functions.find(accessor); auto preexistingit = functions.find(accessor);
#endif
if (preexistingit == functions.cend()) { if (preexistingit == functions.cend()) {
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
std::string accessor(accessor_view.data(), accessor_view.size());
#endif
functions.emplace_hint(preexistingit, std::move(accessor), object(L, 3)); functions.emplace_hint(preexistingit, std::move(accessor), object(L, 3));
} }
else { else {
@ -16864,18 +16957,26 @@ namespace sol {
bool mustindex = umc.mustindex; bool mustindex = umc.mustindex;
if (!mustindex) if (!mustindex)
return; return;
optional<std::string> maybeaccessor = stack::get<optional<std::string>>(L, 2); optional<string_view> maybeaccessor = stack::get<optional<string_view>>(L, 2);
if (!maybeaccessor) { if (!maybeaccessor) {
return; return;
} }
std::string& accessor = maybeaccessor.value(); string_view& accessor_view = maybeaccessor.value();
mapping_t& mapping = umc.mapping; mapping_t& mapping = umc.mapping;
std::vector<object>& runtime = umc.runtime; std::vector<object>& runtime = umc.runtime;
int target = static_cast<int>(runtime.size()); int target = static_cast<int>(runtime.size());
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
auto preexistingit = mapping.find(accessor_view, string_view_hash(), std::equal_to<string_view>());
#else
std::string accessor(accessor_view.data(), accessor_view.size());
auto preexistingit = mapping.find(accessor); auto preexistingit = mapping.find(accessor);
#endif
if (preexistingit == mapping.cend()) { if (preexistingit == mapping.cend()) {
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
std::string accessor(accessor_view.data(), accessor_view.size());
#endif
runtime.emplace_back(L, 3); runtime.emplace_back(L, 3);
mapping.emplace_hint(mapping.cend(), accessor, call_information(&runtime_object_call, &runtime_new_index, target)); mapping.emplace_hint(mapping.cend(), std::move(accessor), call_information(&runtime_object_call, &runtime_new_index, target));
} }
else { else {
target = preexistingit->second.runtime_target; target = preexistingit->second.runtime_target;
@ -17158,8 +17259,13 @@ namespace sol {
int runtime_target = 0; int runtime_target = 0;
usertype_detail::member_search member = nullptr; usertype_detail::member_search member = nullptr;
{ {
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
string_view name = stack::get<string_view>(L, keyidx);
auto memberit = f.mapping.find(name, string_view_hash(), std::equal_to<string_view>());
#else
std::string name = stack::get<std::string>(L, keyidx); std::string name = stack::get<std::string>(L, keyidx);
auto memberit = f.mapping.find(name); auto memberit = f.mapping.find(name);
#endif
if (memberit != f.mapping.cend()) { if (memberit != f.mapping.cend()) {
const usertype_detail::call_information& ci = memberit->second; const usertype_detail::call_information& ci = memberit->second;
member = is_index ? ci.index : ci.new_index; member = is_index ? ci.index : ci.new_index;
@ -17440,8 +17546,13 @@ namespace sol {
string_view accessor = stack::get<string_view>(L, keyidx); string_view accessor = stack::get<string_view>(L, keyidx);
variable_wrapper* varwrap = nullptr; variable_wrapper* varwrap = nullptr;
{ {
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
string_view& accessorkey = accessor;
auto vit = variables.find(accessorkey, string_view_hash(), std::equal_to<string_view>());
#else
std::string accessorkey(accessor.data(), accessor.size()); std::string accessorkey(accessor.data(), accessor.size());
auto vit = variables.find(accessorkey); auto vit = variables.find(accessorkey);
#endif // Compatible Hash
if (vit != variables.cend()) { if (vit != variables.cend()) {
varwrap = vit->second.get(); varwrap = vit->second.get();
} }
@ -17451,8 +17562,13 @@ namespace sol {
} }
bool function_failed = false; bool function_failed = false;
{ {
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
string_view& accessorkey = accessor;
auto fit = functions.find(accessorkey, string_view_hash(), std::equal_to<string_view>());
#else
std::string accessorkey(accessor.data(), accessor.size()); std::string accessorkey(accessor.data(), accessor.size());
auto fit = functions.find(accessorkey); auto fit = functions.find(accessorkey);
#endif // Compatible Hash
if (fit != functions.cend()) { if (fit != functions.cend()) {
object& func = fit->second; object& func = fit->second;
if (is_index) { if (is_index) {
@ -18344,13 +18460,16 @@ namespace sol {
} }
protected: protected:
basic_table_core(detail::no_safety_tag, lua_nil_t n)
: base_t(n) {
}
basic_table_core(detail::no_safety_tag, lua_State* L, int index) basic_table_core(detail::no_safety_tag, lua_State* L, int index)
: base_t(L, index) { : base_t(L, index) {
} }
basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index)
: base_t(L, index) { : base_t(L, index) {
} }
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_table_core(detail::no_safety_tag, T&& r) noexcept basic_table_core(detail::no_safety_tag, T&& r) noexcept
: base_t(std::forward<T>(r)) { : base_t(std::forward<T>(r)) {
} }
@ -18406,7 +18525,7 @@ namespace sol {
stack::check<basic_table_core>(lua_state(), -1, handler); stack::check<basic_table_core>(lua_state(), -1, handler);
#endif // Safety #endif // Safety
} }
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_table_core(T&& r) noexcept basic_table_core(T&& r) noexcept
: basic_table_core(detail::no_safety, std::forward<T>(r)) { : basic_table_core(detail::no_safety, std::forward<T>(r)) {
#ifdef SOL_SAFE_REFERENCES #ifdef SOL_SAFE_REFERENCES
@ -18417,6 +18536,9 @@ namespace sol {
} }
#endif // Safety #endif // Safety
} }
basic_table_core(lua_nil_t r) noexcept
: basic_table_core(detail::no_safety, r) {
}
iterator begin() const { iterator begin() const {
return iterator(*this); return iterator(*this);
@ -18849,7 +18971,7 @@ namespace sol {
stack::check<basic_environment>(L, -1, handler); stack::check<basic_environment>(L, -1, handler);
#endif // Safety #endif // Safety
} }
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_environment(T&& r) noexcept basic_environment(T&& r) noexcept
: base_t(detail::no_safety, std::forward<T>(r)) { : base_t(detail::no_safety, std::forward<T>(r)) {
#ifdef SOL_SAFE_REFERENCES #ifdef SOL_SAFE_REFERENCES
@ -18860,6 +18982,10 @@ namespace sol {
} }
#endif // Safety #endif // Safety
} }
basic_environment(lua_nil_t r) noexcept
: base_t(detail::no_safety, r) {
}
template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_environment(lua_State* L, T&& r) noexcept basic_environment(lua_State* L, T&& r) noexcept
: base_t(detail::no_safety, L, std::forward<T>(r)) { : base_t(detail::no_safety, L, std::forward<T>(r)) {
@ -19141,14 +19267,14 @@ namespace sol {
return result; return result;
} }
inline protected_function_result script_default_on_error(lua_State* L, protected_function_result pfr) { inline protected_function_result script_throw_on_error(lua_State*L, protected_function_result result) {
type t = type_of(L, pfr.stack_index()); type t = type_of(L, result.stack_index());
std::string err = "sol: "; std::string err = "sol: ";
err += to_string(pfr.status()); err += to_string(result.status());
err += " error:"; err += " error:";
if (t == type::string) { if (t == type::string) {
err += " "; err += " ";
string_view serr = stack::get<string_view>(L, pfr.stack_index()); string_view serr = stack::get<string_view>(L, result.stack_index());
err.append(serr.data(), serr.size()); err.append(serr.data(), serr.size());
} }
#ifdef SOL_NO_EXCEPTIONS #ifdef SOL_NO_EXCEPTIONS
@ -19161,7 +19287,15 @@ namespace sol {
// just throw our error // just throw our error
throw error(detail::direct_error, err); throw error(detail::direct_error, err);
#endif #endif
return pfr; return result;
}
inline protected_function_result script_default_on_error(lua_State* L, protected_function_result pfr) {
#ifdef SOL_DEFAULT_PASS_ON_ERROR
return script_pass_on_error(L, std::move(pfr));
#else
return script_throw_on_error(L, std::move(pfr));
#endif
} }
class state_view { class state_view {
@ -19392,7 +19526,7 @@ namespace sol {
return pf(); return pf();
} }
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler> template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result safe_script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result safe_script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
protected_function_result pfr = do_string(code, chunkname, mode); protected_function_result pfr = do_string(code, chunkname, mode);
if (!pfr.valid()) { if (!pfr.valid()) {
@ -19419,7 +19553,7 @@ namespace sol {
return safe_script(code, script_default_on_error, chunkname, mode); return safe_script(code, script_default_on_error, chunkname, mode);
} }
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler> template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result safe_script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) { protected_function_result safe_script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) {
protected_function_result pfr = do_file(filename, mode); protected_function_result pfr = do_file(filename, mode);
if (!pfr.valid()) { if (!pfr.valid()) {
@ -19494,12 +19628,12 @@ namespace sol {
return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns); return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns);
} }
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler> template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, std::forward<Fx>(on_error), chunkname, mode); return safe_script(code, std::forward<Fx>(on_error), chunkname, mode);
} }
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler> template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) { protected_function_result script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) {
return safe_script_file(filename, std::forward<Fx>(on_error), mode); return safe_script_file(filename, std::forward<Fx>(on_error), mode);
} }

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2018-01-24 05:51:14.129707 UTC // Generated 2018-01-29 03:18:59.904294 UTC
// This header was generated with sol v2.19.0 (revision 83f4b4a) // This header was generated with sol v2.19.0 (revision 143c984)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP
@ -156,6 +156,12 @@
#endif #endif
#endif // avoiding nil defines / keywords #endif // avoiding nil defines / keywords
#ifdef SOL_USE_BOOST
#ifndef SOL_UNORDERED_MAP_COMPATIBLE_HASH
#define SOL_UNORDERED_MAP_COMPATIBLE_HASH
#endif // SOL_UNORDERED_MAP_COMPATIBLE_HASH
#endif // Boost has unordered_map with Compatible Key and CompatibleHash
// end of sol/feature_test.hpp // end of sol/feature_test.hpp
namespace sol { namespace sol {

View File

@ -210,7 +210,7 @@ namespace sol {
inline int construct(lua_State* L) { inline int construct(lua_State* L) {
static const auto& meta = usertype_traits<T>::metatable(); static const auto& meta = usertype_traits<T>::metatable();
int argcount = lua_gettop(L); int argcount = lua_gettop(L);
call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits<T>::user_metatable()[0], 1) : call_syntax::dot; call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1) : call_syntax::dot;
argcount -= static_cast<int>(syntax); argcount -= static_cast<int>(syntax);
T* obj = detail::usertype_allocate<T>(L); T* obj = detail::usertype_allocate<T>(L);
@ -509,7 +509,7 @@ namespace sol {
static int call(lua_State* L, F&) { static int call(lua_State* L, F&) {
const auto& metakey = usertype_traits<T>::metatable(); const auto& metakey = usertype_traits<T>::metatable();
int argcount = lua_gettop(L); int argcount = lua_gettop(L);
call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits<T>::user_metatable()[0], 1) : call_syntax::dot; call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1) : call_syntax::dot;
argcount -= static_cast<int>(syntax); argcount -= static_cast<int>(syntax);
T* obj = detail::usertype_allocate<T>(L); T* obj = detail::usertype_allocate<T>(L);
@ -558,7 +558,7 @@ namespace sol {
}; };
static int call(lua_State* L, F& f) { static int call(lua_State* L, F& f) {
call_syntax syntax = stack::get_call_syntax(L, &usertype_traits<T>::user_metatable()[0], 1); call_syntax syntax = stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1);
int syntaxval = static_cast<int>(syntax); int syntaxval = static_cast<int>(syntax);
int argcount = lua_gettop(L) - syntaxval; int argcount = lua_gettop(L) - syntaxval;
return construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f); return construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);

View File

@ -92,7 +92,7 @@ namespace sol {
stack::check<basic_environment>(L, -1, handler); stack::check<basic_environment>(L, -1, handler);
#endif // Safety #endif // Safety
} }
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_environment(T&& r) noexcept basic_environment(T&& r) noexcept
: base_t(detail::no_safety, std::forward<T>(r)) { : base_t(detail::no_safety, std::forward<T>(r)) {
#ifdef SOL_SAFE_REFERENCES #ifdef SOL_SAFE_REFERENCES
@ -103,6 +103,10 @@ namespace sol {
} }
#endif // Safety #endif // Safety
} }
basic_environment(lua_nil_t r) noexcept
: base_t(detail::no_safety, r) {
}
template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_environment(lua_State* L, T&& r) noexcept basic_environment(lua_State* L, T&& r) noexcept
: base_t(detail::no_safety, L, std::forward<T>(r)) { : base_t(detail::no_safety, L, std::forward<T>(r)) {

View File

@ -181,4 +181,10 @@
#endif #endif
#endif // avoiding nil defines / keywords #endif // avoiding nil defines / keywords
#ifdef SOL_USE_BOOST
#ifndef SOL_UNORDERED_MAP_COMPATIBLE_HASH
#define SOL_UNORDERED_MAP_COMPATIBLE_HASH
#endif // SOL_UNORDERED_MAP_COMPATIBLE_HASH
#endif // Boost has unordered_map with Compatible Key and CompatibleHash
#endif // SOL_FEATURE_TEST_HPP #endif // SOL_FEATURE_TEST_HPP

View File

@ -202,7 +202,7 @@ namespace sol {
handler_t error_handler; handler_t error_handler;
basic_protected_function() = default; basic_protected_function() = default;
template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_protected_function>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_protected_function>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_protected_function(T&& r) noexcept basic_protected_function(T&& r) noexcept
: base_t(std::forward<T>(r)), error_handler(get_default_handler(r.lua_state())) { : base_t(std::forward<T>(r)), error_handler(get_default_handler(r.lua_state())) {
#ifdef SOL_SAFE_REFERENCES #ifdef SOL_SAFE_REFERENCES
@ -268,6 +268,10 @@ namespace sol {
stack::check<basic_protected_function>(lua_state(), -1, handler); stack::check<basic_protected_function>(lua_state(), -1, handler);
#endif // Safety #endif // Safety
} }
basic_protected_function(lua_nil_t n)
: base_t(n), error_handler(n) {
}
basic_protected_function(lua_State* L, int index = -1) basic_protected_function(lua_State* L, int index = -1)
: basic_protected_function(L, index, get_default_handler(L)) { : basic_protected_function(L, index, get_default_handler(L)) {

View File

@ -199,6 +199,7 @@ namespace sol {
return; return;
} }
if (r.ref == LUA_NOREF) { if (r.ref == LUA_NOREF) {
luastate = r.luastate;
ref = LUA_NOREF; ref = LUA_NOREF;
return; return;
} }
@ -222,6 +223,7 @@ namespace sol {
return; return;
} }
if (r.ref == LUA_NOREF) { if (r.ref == LUA_NOREF) {
luastate = r.luastate;
ref = LUA_NOREF; ref = LUA_NOREF;
return; return;
} }
@ -380,6 +382,15 @@ namespace sol {
return *this; return *this;
} }
basic_reference& operator=(const lua_nil_t&) noexcept {
if (valid()) {
deref();
}
luastate = nullptr;
ref = LUA_NOREF;
return *this;
}
template <typename Super> template <typename Super>
basic_reference& operator=(proxy_base<Super>&& r); basic_reference& operator=(proxy_base<Super>&& r);

View File

@ -70,8 +70,13 @@ namespace sol {
string_view accessor = stack::get<string_view>(L, keyidx); string_view accessor = stack::get<string_view>(L, keyidx);
variable_wrapper* varwrap = nullptr; variable_wrapper* varwrap = nullptr;
{ {
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
string_view& accessorkey = accessor;
auto vit = variables.find(accessorkey, string_view_hash(), std::equal_to<string_view>());
#else
std::string accessorkey(accessor.data(), accessor.size()); std::string accessorkey(accessor.data(), accessor.size());
auto vit = variables.find(accessorkey); auto vit = variables.find(accessorkey);
#endif // Compatible Hash
if (vit != variables.cend()) { if (vit != variables.cend()) {
varwrap = vit->second.get(); varwrap = vit->second.get();
} }
@ -81,8 +86,13 @@ namespace sol {
} }
bool function_failed = false; bool function_failed = false;
{ {
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
string_view& accessorkey = accessor;
auto fit = functions.find(accessorkey, string_view_hash(), std::equal_to<string_view>());
#else
std::string accessorkey(accessor.data(), accessor.size()); std::string accessorkey(accessor.data(), accessor.size());
auto fit = functions.find(accessorkey); auto fit = functions.find(accessorkey);
#endif // Compatible Hash
if (fit != functions.cend()) { if (fit != functions.cend()) {
object& func = fit->second; object& func = fit->second;
if (is_index) { if (is_index) {

View File

@ -207,11 +207,11 @@ namespace sol {
return call_into_lua<check_args, clean_stack>(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); return call_into_lua<check_args, clean_stack>(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
} }
inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) { inline call_syntax get_call_syntax(lua_State* L, const string_view& key, int index) {
if (lua_gettop(L) == 0) { if (lua_gettop(L) == 0) {
return call_syntax::dot; return call_syntax::dot;
} }
luaL_getmetatable(L, key.c_str()); luaL_getmetatable(L, key.data());
auto pn = pop_n(L, 1); auto pn = pop_n(L, 1);
if (lua_compare(L, -1, index, LUA_OPEQ) != 1) { if (lua_compare(L, -1, index, LUA_OPEQ) != 1) {
return call_syntax::dot; return call_syntax::dot;

View File

@ -73,14 +73,14 @@ namespace sol {
return result; return result;
} }
inline protected_function_result script_default_on_error(lua_State* L, protected_function_result pfr) { inline protected_function_result script_throw_on_error(lua_State*L, protected_function_result result) {
type t = type_of(L, pfr.stack_index()); type t = type_of(L, result.stack_index());
std::string err = "sol: "; std::string err = "sol: ";
err += to_string(pfr.status()); err += to_string(result.status());
err += " error:"; err += " error:";
if (t == type::string) { if (t == type::string) {
err += " "; err += " ";
string_view serr = stack::get<string_view>(L, pfr.stack_index()); string_view serr = stack::get<string_view>(L, result.stack_index());
err.append(serr.data(), serr.size()); err.append(serr.data(), serr.size());
} }
#ifdef SOL_NO_EXCEPTIONS #ifdef SOL_NO_EXCEPTIONS
@ -93,7 +93,15 @@ namespace sol {
// just throw our error // just throw our error
throw error(detail::direct_error, err); throw error(detail::direct_error, err);
#endif #endif
return pfr; return result;
}
inline protected_function_result script_default_on_error(lua_State* L, protected_function_result pfr) {
#ifdef SOL_DEFAULT_PASS_ON_ERROR
return script_pass_on_error(L, std::move(pfr));
#else
return script_throw_on_error(L, std::move(pfr));
#endif
} }
class state_view { class state_view {
@ -324,7 +332,7 @@ namespace sol {
return pf(); return pf();
} }
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler> template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result safe_script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result safe_script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
protected_function_result pfr = do_string(code, chunkname, mode); protected_function_result pfr = do_string(code, chunkname, mode);
if (!pfr.valid()) { if (!pfr.valid()) {
@ -351,7 +359,7 @@ namespace sol {
return safe_script(code, script_default_on_error, chunkname, mode); return safe_script(code, script_default_on_error, chunkname, mode);
} }
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler> template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result safe_script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) { protected_function_result safe_script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) {
protected_function_result pfr = do_file(filename, mode); protected_function_result pfr = do_file(filename, mode);
if (!pfr.valid()) { if (!pfr.valid()) {
@ -426,12 +434,12 @@ namespace sol {
return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns); return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns);
} }
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler> template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, std::forward<Fx>(on_error), chunkname, mode); return safe_script(code, std::forward<Fx>(on_error), chunkname, mode);
} }
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler> template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) { protected_function_result script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) {
return safe_script_file(filename, std::forward<Fx>(on_error), mode); return safe_script_file(filename, std::forward<Fx>(on_error), mode);
} }

View File

@ -30,6 +30,10 @@
#ifdef SOL_CXX17_FEATURES #ifdef SOL_CXX17_FEATURES
#include <string_view> #include <string_view>
#endif // C++17 features #endif // C++17 features
#include <functional>
#ifdef SOL_USE_BOOST
#include <boost/functional/hash.hpp>
#endif
namespace sol { namespace sol {
#ifdef SOL_CXX17_FEATURES #ifdef SOL_CXX17_FEATURES
@ -37,6 +41,7 @@ namespace sol {
typedef std::wstring_view wstring_view; typedef std::wstring_view wstring_view;
typedef std::u16string_view u16string_view; typedef std::u16string_view u16string_view;
typedef std::u32string_view u32string_view; typedef std::u32string_view u32string_view;
typedef std::hash<std::string_view> string_view_hash;
#else #else
template <typename Char, typename Traits = std::char_traits<Char>> template <typename Char, typename Traits = std::char_traits<Char>>
struct basic_string_view { struct basic_string_view {
@ -92,12 +97,16 @@ namespace sol {
return size(); return size();
} }
operator std::basic_string<Char, Traits>() const {
return std::basic_string<Ch, Tr>(data(), size());
}
bool operator==(const basic_string_view& r) const { bool operator==(const basic_string_view& r) const {
return compare(p, s, r.data(), r.size()) == 0; return compare(p, s, r.data(), r.size()) == 0;
} }
bool operator==(const Char* r) const { bool operator==(const Char* r) const {
return compare(r, std::char_traits<char>::length(r), p, s) == 0; return compare(r, Traits::length(r), p, s) == 0;
} }
bool operator==(const std::basic_string<Char, Traits>& r) const { bool operator==(const std::basic_string<Char, Traits>& r) const {
@ -117,10 +126,50 @@ namespace sol {
} }
}; };
template <typename Ch, typename Tr = std::char_traits<Tr>>
struct basic_string_view_hash {
typedef basic_string_view<Ch, Tr> argument_type;
typedef std::size_t result_type;
template <typename Al>
result_type operator()(const std::basic_string<Ch, Tr, Al>& r) const {
return (*this)(basic_string_view<Ch>(r.c_str(), r.size()));
}
result_type operator()(const argument_type& r) const {
#ifdef SOL_USE_BOOST
return boost::hash_range(r.begin(), r.end());
#else
// Modified, from libstdc++
// An implementation attempt at Fowler No Voll, 1a.
// Supposedly, used in MSVC,
// GCC (libstdc++) uses MurmurHash of some sort for 64-bit though...?
// But, well. Can't win them all, right?
// This should normally only apply when NOT using boost,
// so this should almost never be tapped into...
std::size_t hash = 0;
const unsigned char* cptr = reinterpret_cast<const unsigned char*>(r.data());
for (std::size_t sz = r.size(); sz != 0; --sz) {
hash ^= static_cast<size_t>(*cptr++);
hash *= static_cast<size_t>(1099511628211ULL);
}
return hash;
#endif
}
};
} // namespace sol
namespace std {
template <typename Ch, typename Tr>
struct hash< ::sol::basic_string_view<Ch, Tr> > : ::sol::basic_string_view_hash<Ch, Tr> {};
} // namespace std
namespace sol {
using string_view = basic_string_view<char>; using string_view = basic_string_view<char>;
using wstring_view = basic_string_view<wchar_t>; using wstring_view = basic_string_view<wchar_t>;
using u16string_view = basic_string_view<char16_t>; using u16string_view = basic_string_view<char16_t>;
using u32string_view = basic_string_view<char32_t>; using u32string_view = basic_string_view<char32_t>;
using string_view_hash = std::hash<string_view>;
#endif // C++17 Support #endif // C++17 Support
} // namespace sol } // namespace sol

View File

@ -180,13 +180,16 @@ namespace sol {
} }
protected: protected:
basic_table_core(detail::no_safety_tag, lua_nil_t n)
: base_t(n) {
}
basic_table_core(detail::no_safety_tag, lua_State* L, int index) basic_table_core(detail::no_safety_tag, lua_State* L, int index)
: base_t(L, index) { : base_t(L, index) {
} }
basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index)
: base_t(L, index) { : base_t(L, index) {
} }
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_table_core(detail::no_safety_tag, T&& r) noexcept basic_table_core(detail::no_safety_tag, T&& r) noexcept
: base_t(std::forward<T>(r)) { : base_t(std::forward<T>(r)) {
} }
@ -242,7 +245,7 @@ namespace sol {
stack::check<basic_table_core>(lua_state(), -1, handler); stack::check<basic_table_core>(lua_state(), -1, handler);
#endif // Safety #endif // Safety
} }
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_table_core(T&& r) noexcept basic_table_core(T&& r) noexcept
: basic_table_core(detail::no_safety, std::forward<T>(r)) { : basic_table_core(detail::no_safety, std::forward<T>(r)) {
#ifdef SOL_SAFE_REFERENCES #ifdef SOL_SAFE_REFERENCES
@ -253,6 +256,9 @@ namespace sol {
} }
#endif // Safety #endif // Safety
} }
basic_table_core(lua_nil_t r) noexcept
: basic_table_core(detail::no_safety, r) {
}
iterator begin() const { iterator begin() const {
return iterator(*this); return iterator(*this);

View File

@ -555,10 +555,11 @@ namespace sol {
template <typename T> template <typename T>
using is_string_constructible = any< using is_string_constructible = any<
std::is_same<unqualified_t<T>, const char*>, std::is_same<unqualified_t<T>, char>, std::is_same<unqualified_t<T>, std::string>, std::is_same<unqualified_t<T>, std::initializer_list<char>> meta::all<std::is_array<unqualified_t<T>>, std::is_same<meta::unqualified_t<std::remove_all_extents_t<meta::unqualified_t<T>>>, char>>,
std::is_same<unqualified_t<T>, const char*>,
std::is_same<unqualified_t<T>, char>, std::is_same<unqualified_t<T>, std::string>, std::is_same<unqualified_t<T>, std::initializer_list<char>>
#ifdef SOL_CXX17_FEATURES #ifdef SOL_CXX17_FEATURES
, , std::is_same<unqualified_t<T>, std::string_view>
std::is_same<unqualified_t<T>, std::string_view>
#endif #endif
>; >;

View File

@ -68,7 +68,7 @@ namespace sol {
using base_t::lua_state; using base_t::lua_state;
basic_function() = default; basic_function() = default;
template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_function>>, meta::neg<std::is_same<base_t, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_function>>, meta::neg<std::is_same<base_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_function(T&& r) noexcept basic_function(T&& r) noexcept
: base_t(std::forward<T>(r)) { : base_t(std::forward<T>(r)) {
#ifdef SOL_SAFE_REFERENCES #ifdef SOL_SAFE_REFERENCES
@ -89,6 +89,9 @@ namespace sol {
basic_function(stack_reference&& r) basic_function(stack_reference&& r)
: basic_function(r.lua_state(), r.stack_index()) { : basic_function(r.lua_state(), r.stack_index()) {
} }
basic_function(lua_nil_t n)
: base_t(n) {
}
template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_function(lua_State* L, T&& r) basic_function(lua_State* L, T&& r)
: base_t(L, std::forward<T>(r)) { : base_t(L, std::forward<T>(r)) {

View File

@ -42,8 +42,20 @@
#include <cassert> #include <cassert>
#include <bitset> #include <bitset>
#ifdef SOL_USE_BOOST
#include <boost/unordered_map.hpp>
#endif // Using Boost
namespace sol { namespace sol {
namespace usertype_detail { namespace usertype_detail {
#ifdef SOL_USE_BOOST
template <typename K, typename V, typename H = std::hash<K>, typename E = std::equal_to<>>
using map_t = boost::unordered_map<K, V, H, E>;
#else
template <typename K, typename V, typename H = std::hash<K>, typename E = std::equal_to<>>
using map_t = std::unordered_map<K, V, H, E>;
#endif // Boost map target
const int metatable_index = 2; const int metatable_index = 2;
const int metatable_core_index = 3; const int metatable_core_index = 3;
const int filler_index = 4; const int filler_index = 4;
@ -68,8 +80,8 @@ namespace sol {
: index(index), new_index(newindex), runtime_target(runtimetarget) { : index(index), new_index(newindex), runtime_target(runtimetarget) {
} }
}; };
typedef std::unordered_map<std::string, call_information> mapping_t; typedef map_t<std::string, call_information> mapping_t;
struct variable_wrapper { struct variable_wrapper {
virtual int index(lua_State* L) = 0; virtual int index(lua_State* L) = 0;
@ -95,8 +107,8 @@ namespace sol {
} }
}; };
typedef std::unordered_map<std::string, std::unique_ptr<variable_wrapper>> variable_map; typedef map_t<std::string, std::unique_ptr<variable_wrapper>> variable_map;
typedef std::unordered_map<std::string, object> function_map; typedef map_t<std::string, object> function_map;
struct simple_map { struct simple_map {
const char* metakey; const char* metakey;
@ -217,8 +229,8 @@ namespace sol {
inline int indexing_fail(lua_State* L) { inline int indexing_fail(lua_State* L) {
if (is_index) { if (is_index) {
#if 0 //def SOL_SAFE_USERTYPE #if 0 //def SOL_SAFE_USERTYPE
auto maybeaccessor = stack::get<optional<string_detail::string_shim>>(L, is_index ? -1 : -2); auto maybeaccessor = stack::get<optional<string_view>>(L, is_index ? -1 : -2);
string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); string_view accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)"));
return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data()); return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data());
#else #else
if (is_toplevel(L)) { if (is_toplevel(L)) {
@ -248,13 +260,21 @@ namespace sol {
if (is_simple) { if (is_simple) {
simple_map& sm = stack::get<user<simple_map>>(L, upvalue_index(simple_metatable_index)); simple_map& sm = stack::get<user<simple_map>>(L, upvalue_index(simple_metatable_index));
function_map& functions = sm.functions; function_map& functions = sm.functions;
optional<std::string> maybeaccessor = stack::get<optional<std::string>>(L, 2); optional<string_view> maybeaccessor = stack::get<optional<string_view>>(L, 2);
if (!maybeaccessor) { if (!maybeaccessor) {
return; return;
} }
std::string& accessor = maybeaccessor.value(); string_view& accessor_view = maybeaccessor.value();
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
auto preexistingit = functions.find(accessor_view, string_view_hash(), std::equal_to<string_view>());
#else
std::string accessor(accessor_view.data(), accessor_view.size());
auto preexistingit = functions.find(accessor); auto preexistingit = functions.find(accessor);
#endif
if (preexistingit == functions.cend()) { if (preexistingit == functions.cend()) {
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
std::string accessor(accessor_view.data(), accessor_view.size());
#endif
functions.emplace_hint(preexistingit, std::move(accessor), object(L, 3)); functions.emplace_hint(preexistingit, std::move(accessor), object(L, 3));
} }
else { else {
@ -266,18 +286,26 @@ namespace sol {
bool mustindex = umc.mustindex; bool mustindex = umc.mustindex;
if (!mustindex) if (!mustindex)
return; return;
optional<std::string> maybeaccessor = stack::get<optional<std::string>>(L, 2); optional<string_view> maybeaccessor = stack::get<optional<string_view>>(L, 2);
if (!maybeaccessor) { if (!maybeaccessor) {
return; return;
} }
std::string& accessor = maybeaccessor.value(); string_view& accessor_view = maybeaccessor.value();
mapping_t& mapping = umc.mapping; mapping_t& mapping = umc.mapping;
std::vector<object>& runtime = umc.runtime; std::vector<object>& runtime = umc.runtime;
int target = static_cast<int>(runtime.size()); int target = static_cast<int>(runtime.size());
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
auto preexistingit = mapping.find(accessor_view, string_view_hash(), std::equal_to<string_view>());
#else
std::string accessor(accessor_view.data(), accessor_view.size());
auto preexistingit = mapping.find(accessor); auto preexistingit = mapping.find(accessor);
#endif
if (preexistingit == mapping.cend()) { if (preexistingit == mapping.cend()) {
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
std::string accessor(accessor_view.data(), accessor_view.size());
#endif
runtime.emplace_back(L, 3); runtime.emplace_back(L, 3);
mapping.emplace_hint(mapping.cend(), accessor, call_information(&runtime_object_call, &runtime_new_index, target)); mapping.emplace_hint(mapping.cend(), std::move(accessor), call_information(&runtime_object_call, &runtime_new_index, target));
} }
else { else {
target = preexistingit->second.runtime_target; target = preexistingit->second.runtime_target;
@ -560,8 +588,13 @@ namespace sol {
int runtime_target = 0; int runtime_target = 0;
usertype_detail::member_search member = nullptr; usertype_detail::member_search member = nullptr;
{ {
#ifdef SOL_UNORDERED_MAP_COMPATIBLE_HASH
string_view name = stack::get<string_view>(L, keyidx);
auto memberit = f.mapping.find(name, string_view_hash(), std::equal_to<string_view>());
#else
std::string name = stack::get<std::string>(L, keyidx); std::string name = stack::get<std::string>(L, keyidx);
auto memberit = f.mapping.find(name); auto memberit = f.mapping.find(name);
#endif
if (memberit != f.mapping.cend()) { if (memberit != f.mapping.cend()) {
const usertype_detail::call_information& ci = memberit->second; const usertype_detail::call_information& ci = memberit->second;
member = is_index ? ci.index : ci.new_index; member = is_index ? ci.index : ci.new_index;

View File

@ -40,6 +40,8 @@ function(CREATE_TEST test_target_name test_name is_single)
OUTPUT_NAME ${test_name}) OUTPUT_NAME ${test_name})
if (is_single) if (is_single)
target_link_libraries(${test_target_name} sol2_single) target_link_libraries(${test_target_name} sol2_single)
target_compile_definitions(${test_target_name}
PRIVATE TEST_SINGLE)
else() else()
target_link_libraries(${test_target_name} sol2) target_link_libraries(${test_target_name} sol2)
endif() endif()

View File

@ -21,13 +21,8 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#ifdef TEST_SINGLE
#include <sol_forward.hpp>
#endif // Single
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
#include <iterator> #include <iterator>
@ -668,12 +663,13 @@ void associative_ordered_container_key_value_check(sol::state& lua, T& data, T&
#if SOL_LUA_VERSION > 502 #if SOL_LUA_VERSION > 502
lua["val"] = data; lua["val"] = data;
lua.script(R"( auto r = lua.safe_script(R"(
for k, v in pairs(val) do for k, v in pairs(val) do
collect(k, v) collect(k, v)
end end
print() print()
)"); )", sol::script_pass_on_error);
REQUIRE(r.valid());
#else #else
reflect = data; reflect = data;
#endif #endif
@ -688,8 +684,7 @@ for i=1,#c do
v = c[i] v = c[i]
assert(v == (i + 10)) assert(v == (i + 10))
end end
)", )", sol::script_pass_on_error);
sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
} }
{ {
@ -1077,7 +1072,7 @@ TEST_CASE("containers/auxiliary functions test", "make sure the manipulation fun
sol::state lua; sol::state lua;
lua.open_libraries(); lua.open_libraries();
lua.safe_script(R"( auto result1 = lua.safe_script(R"(
function g (x) function g (x)
x:add(20) x:add(20)
end end
@ -1094,8 +1089,8 @@ function sf (x,v)
return x:find(v) return x:find(v)
end end
)"); )", sol::script_pass_on_error);
REQUIRE(result1.valid());
// Have the function we // Have the function we
// just defined in Lua // just defined in Lua
sol::function g = lua["g"]; sol::function g = lua["g"];
@ -1146,13 +1141,12 @@ end
REQUIRE(map.empty()); REQUIRE(map.empty());
REQUIRE(set.empty()); REQUIRE(set.empty());
REQUIRE_NOTHROW([&]() { auto result2 = lua.safe_script(R"(
lua.safe_script(R"(
c_arr[1] = 7 c_arr[1] = 7
c_arr[2] = 7 c_arr[2] = 7
c_arr[3] = 7 c_arr[3] = 7
)"); )", sol::script_pass_on_error);
}()); REQUIRE(result2.valid());
} }
TEST_CASE("containers/indices test", "test indices on fixed array types") { TEST_CASE("containers/indices test", "test indices on fixed array types") {
@ -1190,27 +1184,25 @@ TEST_CASE("containers/as_container reference", "test that we can force a contain
}); });
#if SOL_LUA_VERSION > 501 #if SOL_LUA_VERSION > 501
REQUIRE_NOTHROW([&]() { auto result1 = lua.safe_script(R"(
lua.safe_script(R"(
mop = my_object.new(20) mop = my_object.new(20)
for i, v in pairs(mop) do for i, v in pairs(mop) do
assert(i == v) assert(i == v)
end end
print(mop) print(mop)
)"); )", sol::script_pass_on_error);
}()); REQUIRE(result1.valid());
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
my_object& mo = lua["mop"]; my_object& mo = lua["mop"];
REQUIRE((&mo == my_object::last_printed)); REQUIRE((&mo == my_object::last_printed));
}()); }());
#endif #endif
REQUIRE_NOTHROW([&]() { auto result2 = lua.safe_script(R"(
lua.safe_script(R"(
mo = my_object(10) mo = my_object(10)
c_mo = mo c_mo = mo
c_iterable = mo:iterable() c_iterable = mo:iterable()
)"); )", sol::script_pass_on_error);
}()); REQUIRE(result2.valid());
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
my_object& mo = lua["c_mo"]; my_object& mo = lua["c_mo"];
@ -1219,14 +1211,13 @@ c_iterable = mo:iterable()
REQUIRE(mo == mo_iterable); REQUIRE(mo == mo_iterable);
}()); }());
REQUIRE_NOTHROW([&]() { auto result3 = lua.safe_script(R"(
lua.safe_script(R"(
s1 = c_mo:size() s1 = c_mo:size()
s1_len = #c_mo s1_len = #c_mo
s1_iterable = c_iterable:size() s1_iterable = c_iterable:size()
s1_iterable_len = #c_iterable s1_iterable_len = #c_iterable
)"); )");
}()); REQUIRE(result3.valid());
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
std::size_t s1 = lua["s1"]; std::size_t s1 = lua["s1"];
@ -1239,17 +1230,15 @@ s1_iterable_len = #c_iterable
REQUIRE(s1_iterable == s1_iterable_len); REQUIRE(s1_iterable == s1_iterable_len);
}()); }());
REQUIRE_NOTHROW([&]() { auto result4 = lua.safe_script(R"(
lua.safe_script(R"(
for i=1,#c_mo do for i=1,#c_mo do
v_iterable = c_iterable[i] v_iterable = c_iterable[i]
assert(v_iterable == i) assert(v_iterable == i)
end end
)"); )", sol::script_pass_on_error);
}()); REQUIRE(result4.valid());
REQUIRE_NOTHROW([&]() { auto result5 = lua.safe_script(R"(
lua.safe_script(R"(
mo(5, 20) mo(5, 20)
c_iterable:insert(1, 100) c_iterable:insert(1, 100)
v1 = c_iterable[1] v1 = c_iterable[1]
@ -1258,25 +1247,22 @@ s2_len = #c_mo
s2_iterable = c_iterable:size() s2_iterable = c_iterable:size()
s2_iterable_len = #c_iterable s2_iterable_len = #c_iterable
print(mo) print(mo)
)"); )", sol::script_pass_on_error);
}()); REQUIRE(result5.valid());
REQUIRE_NOTHROW([&]() { int v1 = lua["v1"];
int v1 = lua["v1"]; std::size_t s2 = lua["s2"];
std::size_t s2 = lua["s2"]; std::size_t s2_len = lua["s2_len"];
std::size_t s2_len = lua["s2_len"]; std::size_t s2_iterable = lua["s2_iterable"];
std::size_t s2_iterable = lua["s2_iterable"]; std::size_t s2_iterable_len = lua["s2_iterable_len"];
std::size_t s2_iterable_len = lua["s2_iterable_len"]; REQUIRE(v1 == 100);
REQUIRE(v1 == 100); REQUIRE(s2 == 16);
REQUIRE(s2 == 16); REQUIRE(s2 == s2_len);
REQUIRE(s2 == s2_len); REQUIRE(s2 == s2_iterable_len);
REQUIRE(s2 == s2_iterable_len); REQUIRE(s2_iterable == s2_iterable_len);
REQUIRE(s2_iterable == s2_iterable_len);
}()); my_object& mo = lua["mo"];
REQUIRE_NOTHROW([&]() { REQUIRE(&mo == my_object::last_printed);
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") { 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") {
@ -1288,21 +1274,19 @@ TEST_CASE("containers/as_container", "test that we can force a container to be t
}); });
#if SOL_LUA_VERSION > 501 #if SOL_LUA_VERSION > 501
REQUIRE_NOTHROW([&]() { auto result1 = lua.safe_script(R"(
lua.safe_script(R"(
mop = f(20) mop = f(20)
for i, v in pairs(mop) do for i, v in pairs(mop) do
assert(i == v) assert(i == v)
end end
)"); )");
}()); REQUIRE(result1.valid());
#endif #endif
REQUIRE_NOTHROW([&]() { auto result2 = lua.safe_script(R"(
lua.safe_script(R"(
mo = f(10) mo = f(10)
c_iterable = mo c_iterable = mo
)"); )");
}()); REQUIRE(result2.valid());
{ {
my_object& mo = lua["mo"]; my_object& mo = lua["mo"];
@ -1311,12 +1295,11 @@ c_iterable = mo
REQUIRE(mo == mo_iterable); REQUIRE(mo == mo_iterable);
} }
REQUIRE_NOTHROW([&]() { auto result3 = lua.safe_script(R"(
lua.safe_script(R"(
s1_iterable = c_iterable:size() s1_iterable = c_iterable:size()
s1_iterable_len = #c_iterable s1_iterable_len = #c_iterable
)"); )");
}()); REQUIRE(result3.valid());
{ {
std::size_t s1_iterable = lua["s1_iterable"]; std::size_t s1_iterable = lua["s1_iterable"];
@ -1325,23 +1308,21 @@ s1_iterable_len = #c_iterable
REQUIRE(s1_iterable == s1_iterable_len); REQUIRE(s1_iterable == s1_iterable_len);
} }
REQUIRE_NOTHROW([&]() { auto result4 = lua.safe_script(R"(
lua.safe_script(R"(
for i=1,#c_iterable do for i=1,#c_iterable do
v_iterable = c_iterable[i] v_iterable = c_iterable[i]
assert(v_iterable == i) assert(v_iterable == i)
end end
)"); )");
}()); REQUIRE(result4.valid());
REQUIRE_NOTHROW([&]() { auto result5 = lua.safe_script(R"(
lua.safe_script(R"(
c_iterable:insert(1, 100) c_iterable:insert(1, 100)
v1 = c_iterable:get(1) v1 = c_iterable:get(1)
s2_iterable = c_iterable:size() s2_iterable = c_iterable:size()
s2_iterable_len = #c_iterable s2_iterable_len = #c_iterable
)"); )");
}()); REQUIRE(result5.valid());
{ {
int v1 = lua["v1"]; int v1 = lua["v1"];

View File

@ -21,10 +21,8 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
#include <iterator> #include <iterator>
@ -182,7 +180,8 @@ TEST_CASE("containers/returns", "make sure that even references to vectors are b
lua.set_function("f", [&]() -> std::vector<int>& { lua.set_function("f", [&]() -> std::vector<int>& {
return v; return v;
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::object x = lua["x"]; sol::object x = lua["x"];
sol::type xt = x.get_type(); sol::type xt = x.get_type();
REQUIRE(xt == sol::type::userdata); REQUIRE(xt == sol::type::userdata);
@ -288,8 +287,10 @@ TEST_CASE("containers/table conversion", "test table conversions with as_table a
return sol::as_nested(std::vector<std::string>{ "bark", "woof" }); return sol::as_nested(std::vector<std::string>{ "bark", "woof" });
}); });
lua.safe_script("v1 = bark()"); auto result1 = lua.safe_script("v1 = bark()", sol::script_pass_on_error);
lua.safe_script("v2 = woof()"); REQUIRE(result1.valid());
auto result2 = lua.safe_script("v2 = woof()", sol::script_pass_on_error);
REQUIRE(result2.valid());
sol::as_table_t<std::vector<std::string>> as_table_strings = lua["v1"]; sol::as_table_t<std::vector<std::string>> as_table_strings = lua["v1"];
sol::nested<std::vector<std::string>> nested_strings = lua["v2"]; sol::nested<std::vector<std::string>> nested_strings = lua["v2"];
@ -305,7 +306,8 @@ TEST_CASE("containers/vector roundtrip", "make sure vectors can be round-tripped
lua.set_function("f", [&]() -> std::vector<int>& { lua.set_function("f", [&]() -> std::vector<int>& {
return v; return v;
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
std::vector<int> x = lua["x"]; std::vector<int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -317,7 +319,8 @@ TEST_CASE("containers/deque roundtrip", "make sure deques can be round-tripped")
lua.set_function("f", [&]() -> std::deque<int>& { lua.set_function("f", [&]() -> std::deque<int>& {
return v; return v;
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
std::deque<int> x = lua["x"]; std::deque<int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -329,7 +332,8 @@ TEST_CASE("containers/array roundtrip", "make sure arrays can be round-tripped")
lua.set_function("f", [&]() -> std::array<int, 3>& { lua.set_function("f", [&]() -> std::array<int, 3>& {
return v; return v;
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
std::array<int, 3> x = lua["x"]; std::array<int, 3> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -341,7 +345,8 @@ TEST_CASE("containers/list roundtrip", "make sure lists can be round-tripped") {
lua.set_function("f", [&]() -> std::list<int>& { lua.set_function("f", [&]() -> std::list<int>& {
return v; return v;
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
std::list<int> x = lua["x"]; std::list<int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -353,7 +358,8 @@ TEST_CASE("containers/forward_list roundtrip", "make sure forward_lists can be r
lua.set_function("f", [&]() -> std::forward_list<int>& { lua.set_function("f", [&]() -> std::forward_list<int>& {
return v; return v;
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
std::forward_list<int> x = lua["x"]; std::forward_list<int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -365,7 +371,8 @@ TEST_CASE("containers/map roundtrip", "make sure maps can be round-tripped") {
lua.set_function("f", [&]() -> std::map<std::string, int>& { lua.set_function("f", [&]() -> std::map<std::string, int>& {
return v; return v;
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
std::map<std::string, int> x = lua["x"]; std::map<std::string, int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -377,7 +384,8 @@ TEST_CASE("containers/unordered_map roundtrip", "make sure unordered_maps can be
lua.set_function("f", [&]() -> std::unordered_map<std::string, int>& { lua.set_function("f", [&]() -> std::unordered_map<std::string, int>& {
return v; return v;
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
std::unordered_map<std::string, int> x = lua["x"]; std::unordered_map<std::string, int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -389,7 +397,8 @@ TEST_CASE("containers/unordered_set roundtrip", "make sure unordered_sets can be
lua.set_function("f", [&]() -> std::unordered_set<int>& { lua.set_function("f", [&]() -> std::unordered_set<int>& {
return v; return v;
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
std::unordered_set<int> x = lua["x"]; std::unordered_set<int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -401,7 +410,8 @@ TEST_CASE("containers/set roundtrip", "make sure sets can be round-tripped") {
lua.set_function("f", [&]() -> std::set<int>& { lua.set_function("f", [&]() -> std::set<int>& {
return v; return v;
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
std::set<int> x = lua["x"]; std::set<int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -413,7 +423,8 @@ TEST_CASE("containers/vector table roundtrip", "make sure vectors can be round-t
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::vector<int>> x = lua["x"]; sol::as_table_t<std::vector<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -425,7 +436,8 @@ TEST_CASE("containers/deque table roundtrip", "make sure deques can be round-tri
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::deque<int>> x = lua["x"]; sol::as_table_t<std::deque<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -437,7 +449,8 @@ TEST_CASE("containers/array table roundtrip", "make sure arrays can be round-tri
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::array<int, 3>> x = lua["x"]; sol::as_table_t<std::array<int, 3>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -449,7 +462,8 @@ TEST_CASE("containers/list table roundtrip", "make sure lists can be round-tripp
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::list<int>> x = lua["x"]; sol::as_table_t<std::list<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -461,7 +475,8 @@ TEST_CASE("containers/forward_list table roundtrip", "make sure forward_lists ca
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::forward_list<int>> x = lua["x"]; sol::as_table_t<std::forward_list<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -473,7 +488,8 @@ TEST_CASE("containers/map table roundtrip", "make sure maps can be round-tripped
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::map<std::string, int>> x = lua["x"]; sol::as_table_t<std::map<std::string, int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -485,7 +501,8 @@ TEST_CASE("containers/unordered_map table roundtrip", "make sure unordered_maps
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::unordered_map<std::string, int>> x = lua["x"]; sol::as_table_t<std::unordered_map<std::string, int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -497,7 +514,8 @@ TEST_CASE("containers/unordered_set table roundtrip", "make sure unordered_sets
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::unordered_set<int>> x = lua["x"]; sol::as_table_t<std::unordered_set<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -509,7 +527,8 @@ TEST_CASE("containers/set table roundtrip", "make sure sets can be round-tripped
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.safe_script("x = f()"); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::as_table_t<std::set<int>> x = lua["x"]; sol::as_table_t<std::set<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -530,7 +549,7 @@ TEST_CASE("containers/custom usertype", "make sure container usertype metatables
{ {
auto result0 = lua.safe_script("assert(a:at(24) == 50)", sol::script_pass_on_error); auto result0 = lua.safe_script("assert(a:at(24) == 50)", sol::script_pass_on_error);
REQUIRE(result0.valid()); REQUIRE(result0.valid());
auto result1 = lua.safe_script("a:something()"); auto result1 = lua.safe_script("a:something()", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
} }
lua.set("a", obj); lua.set("a", obj);
@ -554,8 +573,8 @@ TEST_CASE("containers/const serialization kvp", "make sure const keys / values a
lua.set("a", std::ref(obj)); lua.set("a", std::ref(obj));
auto result0 = lua.safe_script("assert(a[24] == 50)", sol::script_pass_on_error); auto result0 = lua.safe_script("assert(a[24] == 50)", sol::script_pass_on_error);
REQUIRE(result0.valid()); REQUIRE(result0.valid());
auto result = lua.safe_script("a[24] = 51", sol::script_pass_on_error); auto result1 = lua.safe_script("a[24] = 51", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid()); REQUIRE_FALSE(result1.valid());
auto result2 = lua.safe_script("assert(a[24] == 50)", sol::script_pass_on_error); auto result2 = lua.safe_script("assert(a[24] == 50)", sol::script_pass_on_error);
REQUIRE(result2.valid()); REQUIRE(result2.valid());
} }
@ -652,19 +671,21 @@ TEST_CASE("containers/const correctness", "usertype metatable names should reaso
std::vector<Vec const*> bar; std::vector<Vec const*> bar;
bar.push_back(&vec); bar.push_back(&vec);
lua.safe_script(R"( auto result0 = lua.safe_script(R"(
func = function(vecs) func = function(vecs)
for i = 1, #vecs do for i = 1, #vecs do
vec = vecs[i] vec = vecs[i]
print(i, ":", vec.x, vec.y, vec.z) print(i, ":", vec.x, vec.y, vec.z)
end end
end end
)"); )", sol::script_pass_on_error);
REQUIRE(result0.valid());
REQUIRE_NOTHROW([&] { sol::protected_function f(lua["func"]);
lua["func"](foo); auto pfr1 = f(foo);
lua["func"](bar); REQUIRE(pfr1.valid());
}()); auto pfr2 = f(bar);
REQUIRE(pfr2.valid());
} }
TEST_CASE("containers/arbitrary creation", "userdata and tables should be usable from standard containers") { TEST_CASE("containers/arbitrary creation", "userdata and tables should be usable from standard containers") {
@ -771,10 +792,11 @@ TEST_CASE("containers/usertype transparency", "Make sure containers pass their a
lua.new_usertype<B>("B", lua.new_usertype<B>("B",
"a_list", &B::a_list); "a_list", &B::a_list);
lua.safe_script(R"( auto result = lua.safe_script(R"(
b = B.new() b = B.new()
a_ref = b.a_list[2] a_ref = b.a_list[2]
)"); )", sol::script_pass_on_error);
REQUIRE(result.valid());
B& b = lua["b"]; B& b = lua["b"];
A& a_ref = lua["a_ref"]; A& a_ref = lua["a_ref"];
@ -836,9 +858,10 @@ TEST_CASE("containers/is container", "make sure the is_container trait behaves p
machine m; machine m;
lua["machine"] = &m; lua["machine"] = &m;
lua.safe_script(R"( auto result0 = lua.safe_script(R"(
machine:opt():output_help() machine:opt():output_help()
)"); )", sol::script_pass_on_error);
REQUIRE(result0.valid());
REQUIRE(options::last == &m.opt); REQUIRE(options::last == &m.opt);
REQUIRE(options::livingcount == 1); REQUIRE(options::livingcount == 1);
@ -865,12 +888,13 @@ TEST_CASE("containers/readonly", "make sure readonly members are stored appropri
); );
lua["value"] = std::list<bar>{ {}, {}, {} }; lua["value"] = std::list<bar>{ {}, {}, {} };
lua.safe_script(R"( auto result0 = lua.safe_script(R"(
a = foo.new() a = foo.new()
x = a.seq x = a.seq
a.seq = value a.seq = value
y = a.readonly_seq y = a.readonly_seq
)"); )", sol::script_pass_on_error);
REQUIRE(result0.valid());
std::list<bar>& seqrefx = lua["x"]; std::list<bar>& seqrefx = lua["x"];
std::list<bar>& seqrefy = lua["y"]; std::list<bar>& seqrefy = lua["y"];
REQUIRE(&seqrefx == &seqrefy); REQUIRE(&seqrefx == &seqrefy);
@ -883,7 +907,8 @@ TEST_CASE("containers/to_args", "Test that the to_args abstractions works") {
sol::state lua; sol::state lua;
lua.open_libraries(); lua.open_libraries();
lua.safe_script("function f (a, b, c, d) print(a, b, c, d) return a, b, c, d end"); auto result1 = lua.safe_script("function f (a, b, c, d) print(a, b, c, d) return a, b, c, d end", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::function f = lua["f"]; sol::function f = lua["f"];
int a, b, c, d; int a, b, c, d;
@ -922,18 +947,21 @@ TEST_CASE("containers/ipairs test", "ensure that abstractions roundtrip properly
return std::vector<thing*>(5, &t); return std::vector<thing*>(5, &t);
}); });
lua.safe_script(R"( auto result1 = lua.safe_script(R"(
c = f() c = f()
)"); )", sol::script_pass_on_error);
REQUIRE(result1.valid());
lua.safe_script(R"( auto result2 = lua.safe_script(R"(
check = {} check = {}
local i = 1 local i = 1
while c[i] do while c[i] do
check[i] = c[i] check[i] = c[i]
i = i + 1 i = i + 1
end end
)"); )", sol::script_pass_on_error);
REQUIRE(result2.valid());
sol::table c = lua["check"]; sol::table c = lua["check"];
for (std::size_t i = 1; i < 6; ++i) { for (std::size_t i = 1; i < 6; ++i) {
thing& ct = c[i]; thing& ct = c[i];
@ -945,7 +973,8 @@ end
TEST_CASE("containers/append idiom", "ensure the append-idiom works as intended") { TEST_CASE("containers/append idiom", "ensure the append-idiom works as intended") {
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.safe_script(
auto result1 = lua.safe_script(
R"( R"(
function f_fill(vec) function f_fill(vec)
print("#vec in lua: " .. #vec) print("#vec in lua: " .. #vec)
@ -961,6 +990,8 @@ function f_append(vec)
print("#vec in lua: " .. #vec) print("#vec in lua: " .. #vec)
end end
)"); )");
REQUIRE(result1.valid());
std::vector<int> fill_cmp{ 1, 2, 3 }; std::vector<int> fill_cmp{ 1, 2, 3 };
std::vector<int> append_cmp{ -1, -1, -10456407, -54 }; std::vector<int> append_cmp{ -1, -1, -10456407, -54 };
@ -1029,18 +1060,21 @@ TEST_CASE("containers/input iterators", "test shitty input iterators that are al
not_really_a_container c; not_really_a_container c;
lua["c"] = &c; lua["c"] = &c;
#if SOL_LUA_VERSION > 502 #if SOL_LUA_VERSION > 502
lua.safe_script(R"lua( auto result0 = lua.safe_script(R"lua(
for k, v in pairs(c) do for k, v in pairs(c) do
assert((k - 1) == v:val()) assert((k - 1) == v:val())
end end
)lua"); )lua", sol::script_pass_on_error);
REQUIRE(result0.valid());
#endif #endif
lua.safe_script(R"lua( auto result1 = lua.safe_script(R"lua(
for k=1,#c do for k=1,#c do
v = c[k] v = c[k]
assert((k - 1) == v:val()) assert((k - 1) == v:val())
end end
)lua"); )lua", sol::script_pass_on_error);
REQUIRE(result1.valid());
} }
TEST_CASE("containers/pairs", "test how well pairs work with the underlying system") { TEST_CASE("containers/pairs", "test how well pairs work with the underlying system") {
@ -1061,10 +1095,14 @@ TEST_CASE("containers/pairs", "test how well pairs work with the underlying syst
lua["c"] = std::ref(c); lua["c"] = std::ref(c);
lua["d"] = &d; lua["d"] = &d;
lua.safe_script("av1, av2 = a:get(1)"); auto result1 = lua.safe_script("av1, av2 = a:get(1)", sol::script_pass_on_error);
lua.safe_script("bv1, bv2 = b:get(1)"); REQUIRE(result1.valid());
lua.safe_script("cv1, cv2 = c:get(1)"); auto result2 = lua.safe_script("bv1, bv2 = b:get(1)", sol::script_pass_on_error);
lua.safe_script("dv1, dv2 = d:get(1)"); REQUIRE(result2.valid());
auto result3 = lua.safe_script("cv1, cv2 = c:get(1)", sol::script_pass_on_error);
REQUIRE(result3.valid());
auto result4 = lua.safe_script("dv1, dv2 = d:get(1)", sol::script_pass_on_error);
REQUIRE(result4.valid());
std::vector<std::pair<std::string, int>>& la = lua["a"]; std::vector<std::pair<std::string, int>>& la = lua["a"];
std::array<std::pair<std::string, int>, 5>& lb = lua["b"]; std::array<std::pair<std::string, int>, 5>& lb = lua["b"];
@ -1134,24 +1172,20 @@ TEST_CASE("containers/pointer types", "check that containers with unique usertyp
std::vector<base_t*> v2; std::vector<base_t*> v2;
v2.push_back(&d1); v2.push_back(&d1);
v2.push_back(&d2); v2.push_back(&d2);
REQUIRE_NOTHROW([&]() { lua["c1"] = std::move(v1);
lua["c1"] = std::move(v1); lua["c2"] = &v2;
lua["c2"] = &v2;
}()); auto result1 = lua.safe_script("b1 = c1[1]", sol::script_pass_on_error);
REQUIRE(result1.valid());
base_t* b1 = lua["b1"];
int val1 = b1->get();
REQUIRE(val1 == 250);
REQUIRE_NOTHROW([&]() { auto result2 = lua.safe_script("b2 = c2[2]", sol::script_pass_on_error);
lua.safe_script("b1 = c1[1]"); REQUIRE(result2.valid());
base_t* b1 = lua["b1"]; base_t* b2 = lua["b2"];
int val1 = b1->get(); int val2 = b2->get();
REQUIRE(val1 == 250); REQUIRE(val2 == 500);
}());
REQUIRE_NOTHROW([&]() {
lua.safe_script("b2 = c2[2]");
base_t* b2 = lua["b2"];
int val2 = b2->get();
REQUIRE(val2 == 500);
}());
} }
TEST_CASE("containers/initializer-list", "test initializer lists get pushed as tables directly rather than userdata") { TEST_CASE("containers/initializer-list", "test initializer lists get pushed as tables directly rather than userdata") {
@ -1160,11 +1194,11 @@ TEST_CASE("containers/initializer-list", "test initializer lists get pushed as t
lua.open_libraries(sol::lib::base, sol::lib::table); lua.open_libraries(sol::lib::base, sol::lib::table);
lua["c"] = { 1, 2, 3, 4, 5 }; lua["c"] = { 1, 2, 3, 4, 5 };
lua.safe_script(R"lua( auto result1 = lua.safe_script(R"lua(
for k, v in pairs(c) do for k, v in pairs(c) do
assert(k == v) assert(k == v)
end end
)lua"); )lua", sol::script_pass_on_error);
sol::as_table_t<std::vector<int>> t1vector = lua["c"]; sol::as_table_t<std::vector<int>> t1vector = lua["c"];
sol::as_table_t<std::deque<int>> t1deque = lua["c"]; sol::as_table_t<std::deque<int>> t1deque = lua["c"];
sol::as_table_t<std::list<int>> t1list = lua["c"]; sol::as_table_t<std::list<int>> t1list = lua["c"];

View File

@ -21,11 +21,9 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <catch.hpp> #include <catch.hpp>
#include <sol.hpp>
TEST_CASE("coroutines/yielding", "ensure calling a coroutine works") { TEST_CASE("coroutines/yielding", "ensure calling a coroutine works") {
const auto& script = R"(counter = 20 const auto& script = R"(counter = 20
@ -42,22 +40,21 @@ end
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine); lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.safe_script(script); auto result1 = lua.safe_script(script);
REQUIRE(result1.valid());
sol::coroutine cr = lua["loop"]; sol::coroutine cr = lua["loop"];
int counter; int counter;
for (counter = 20; counter < 31 && cr; ++counter) { for (counter = 20; counter < 31 && cr; ++counter) {
int value = cr(); int value = cr();
if (counter != value) { REQUIRE(counter == value);
throw std::logic_error("fuck");
}
} }
counter -= 1; counter -= 1;
REQUIRE(counter == 30); REQUIRE(counter == 30);
} }
TEST_CASE("coroutines/new thread coroutines", "ensure calling a coroutine works when the work is put on a different thread") { TEST_CASE("coroutines/new thread coroutines", "ensure calling a coroutine works when the work is put on a different thread") {
const auto& script = R"(counter = 20 const auto& code = R"(counter = 20
function loop() function loop()
while counter ~= 30 while counter ~= 30
@ -71,7 +68,8 @@ end
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine); lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.safe_script(script); auto result = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(result.valid());
sol::thread runner = sol::thread::create(lua.lua_state()); sol::thread runner = sol::thread::create(lua.lua_state());
sol::state_view runnerstate = runner.state(); sol::state_view runnerstate = runner.state();
sol::coroutine cr = runnerstate["loop"]; sol::coroutine cr = runnerstate["loop"];
@ -79,9 +77,7 @@ end
int counter; int counter;
for (counter = 20; counter < 31 && cr; ++counter) { for (counter = 20; counter < 31 && cr; ++counter) {
int value = cr(); int value = cr();
if (counter != value) { REQUIRE(counter == value);
throw std::logic_error("fuck");
}
} }
counter -= 1; counter -= 1;
REQUIRE(counter == 30); REQUIRE(counter == 30);
@ -96,8 +92,8 @@ TEST_CASE("coroutines/transfer", "test that things created inside of a coroutine
lua["f"] = [&lua, &f2](sol::object t) { lua["f"] = [&lua, &f2](sol::object t) {
f2 = sol::function(lua, t); f2 = sol::function(lua, t);
}; };
{
lua.script(R"( auto code = R"(
i = 0 i = 0
function INIT() function INIT()
co = coroutine.create( co = coroutine.create(
@ -112,13 +108,24 @@ function INIT()
co = nil co = nil
collectgarbage() collectgarbage()
end end
)"); )";
auto result = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(result.valid());
}
sol::function f3; sol::function f3;
sol::function f1; sol::function f1;
lua.safe_script("INIT()"); {
auto code = "INIT()";
auto result = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(result.valid());
}
f2(); f2();
sol::function update = lua.safe_script("return function() collectgarbage() end"); auto updatecode = "return function() collectgarbage() end";
auto pfr = lua.safe_script(updatecode);
REQUIRE(pfr.valid());
sol::function update = pfr;
update(); update();
f3 = f2; f3 = f2;
f3(); f3();
@ -199,7 +206,7 @@ co = nil
"copy_store", &co_test::copy_store, "copy_store", &co_test::copy_store,
"get", &co_test::get); "get", &co_test::get);
auto r = lua.safe_script(code); auto r = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
co_test& ct = lua["x"]; co_test& ct = lua["x"];
@ -283,7 +290,7 @@ co = nil
"copy_store", &co_test_implicit::copy_store, "copy_store", &co_test_implicit::copy_store,
"get", &co_test_implicit::get); "get", &co_test_implicit::get);
auto r = lua.safe_script(code); auto r = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
co_test_implicit& ct = lua["x"]; co_test_implicit& ct = lua["x"];
@ -370,7 +377,7 @@ collectgarbage()
"copy_store", &co_test_implicit::copy_store, "copy_store", &co_test_implicit::copy_store,
"get", &co_test_implicit::get); "get", &co_test_implicit::get);
auto r = lua.safe_script(code); auto r = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
co_test_implicit& ct = lua["x"]; co_test_implicit& ct = lua["x"];
@ -391,8 +398,7 @@ TEST_CASE("coroutines/coroutine.create protection", "ensure that a thread picked
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine); lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.script( auto code = R"(
R"(
function loop() function loop()
local i = 0 local i = 0
while true do while true do
@ -403,9 +409,10 @@ function loop()
end end
end end
loop_th = coroutine.create(loop) loop_th = coroutine.create(loop)
)" )";
);
auto r = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(r.valid());
sol::thread runner_thread = lua["loop_th"]; sol::thread runner_thread = lua["loop_th"];
auto test_resume = [&runner_thread]() { auto test_resume = [&runner_thread]() {
@ -419,8 +426,15 @@ loop_th = coroutine.create(loop)
int v0 = test_resume(); int v0 = test_resume();
int v1 = test_resume(); int v1 = test_resume();
int v2 = lua.script("return test_resume()"); int v2, v3;
int v3 = lua.script("return test_resume()"); {
auto r2 = lua.safe_script("return test_resume()", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r3 = lua.safe_script("return test_resume()", sol::script_pass_on_error);
REQUIRE(r3.valid());
v2 = r2;
v3 = r3;
}
REQUIRE(v0 == 0); REQUIRE(v0 == 0);
REQUIRE(v1 == 1); REQUIRE(v1 == 1);
REQUIRE(v2 == 2); REQUIRE(v2 == 2);
@ -430,9 +444,8 @@ loop_th = coroutine.create(loop)
TEST_CASE("coroutines/stack-check", "check that resumed functions consume the entire execution stack") { TEST_CASE("coroutines/stack-check", "check that resumed functions consume the entire execution stack") {
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::table, sol::lib::coroutine); lua.open_libraries(sol::lib::base, sol::lib::table, sol::lib::coroutine);
{
lua.script( auto code = R"(
R"(
unpack = unpack or table.unpack unpack = unpack or table.unpack
function loop() function loop()
@ -449,8 +462,10 @@ loop_res = function(...)
returns = { coroutine.resume(loop_th, ...) } returns = { coroutine.resume(loop_th, ...) }
return unpack(returns, 2) return unpack(returns, 2)
end end
)" )";
); auto result = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(result.valid());
}
// Resume from lua via thread and coroutine // Resume from lua via thread and coroutine
sol::thread runner_thread = lua["loop_th"]; sol::thread runner_thread = lua["loop_th"];
@ -478,13 +493,28 @@ end
int s0 = runner_thread_state.stack_top(); int s0 = runner_thread_state.stack_top();
int v1 = test_resume(); int v1 = test_resume();
int s1 = runner_thread_state.stack_top(); int s1 = runner_thread_state.stack_top();
int v2 = lua.script("return test_resume()"); int v2;
{
auto result = lua.safe_script("return test_resume()", sol::script_pass_on_error);
REQUIRE(result.valid());
v2 = result;
}
int s2 = runner_thread_state.stack_top(); int s2 = runner_thread_state.stack_top();
int v3 = lua.script("return test_resume()"); int v3;
{
auto result = lua.safe_script("return test_resume()", sol::script_pass_on_error);
REQUIRE(result.valid());
v3 = result;
}
int s3 = runner_thread_state.stack_top(); int s3 = runner_thread_state.stack_top();
int v4 = test_resume_lua(); int v4 = test_resume_lua();
int s4 = runner_thread_state.stack_top(); int s4 = runner_thread_state.stack_top();
int v5 = lua.script("return test_resume_func(loop_res)"); int v5;
{
auto result = lua.safe_script("return test_resume_func(loop_res)", sol::script_pass_on_error);
REQUIRE(result.valid());
v5 = result;
}
int s5 = runner_thread_state.stack_top(); int s5 = runner_thread_state.stack_top();
REQUIRE(v0 == 0); REQUIRE(v0 == 0);
REQUIRE(v1 == 1); REQUIRE(v1 == 1);

View File

@ -21,11 +21,9 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <catch.hpp> #include <catch.hpp>
#include <sol.hpp>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -127,7 +125,8 @@ TEST_CASE("customization/split struct", "using the newly documented customizatio
sol::state lua; sol::state lua;
// Create a pass-through style of function // Create a pass-through style of function
lua.safe_script("function f ( a, b, c ) return a + c, b end"); auto result1 = lua.safe_script("function f ( a, b, c ) return a + c, b end");
REQUIRE(result1.valid());
lua.set_function("g", [](int a, bool b, int c, double d) { lua.set_function("g", [](int a, bool b, int c, double d) {
return std::make_tuple(a + c, b, d + 2.5); return std::make_tuple(a + c, b, d + 2.5);
}); });
@ -152,15 +151,16 @@ TEST_CASE("customization/get_ check_usertype", "using the newly documented custo
sol::state lua; sol::state lua;
// Create a pass-through style of function // Create a pass-through style of function
lua.safe_script("function f ( a ) return a end"); auto result1 = lua.safe_script("function f ( a ) return a end");
REQUIRE(result1.valid());
lua.set_function("g", [](double a) { lua.set_function("g", [](double a) {
number_shim ns; number_shim ns;
ns.num = a; ns.num = a;
return ns; return ns;
}); });
auto result = lua.safe_script("vf = f(25) vg = g(35)", sol::script_pass_on_error); auto result2 = lua.safe_script("vf = f(25) vg = g(35)", sol::script_pass_on_error);
REQUIRE(result.valid()); REQUIRE(result2.valid());
number_shim thingsf = lua["vf"]; number_shim thingsf = lua["vf"];
number_shim thingsg = lua["vg"]; number_shim thingsg = lua["vg"];

View File

@ -21,21 +21,19 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
#include <iostream> #include <iostream>
#include "test_stack_guard.hpp"
TEST_CASE("environments/get", "Envronments can be taken out of things like Lua functions properly") { TEST_CASE("environments/get", "Envronments can be taken out of things like Lua functions properly") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua); sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.safe_script("f = function() return test end"); auto result1 = lua.safe_script("f = function() return test end", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::function f = lua["f"]; sol::function f = lua["f"];
sol::environment env_f(lua, sol::create); sol::environment env_f(lua, sol::create);
@ -45,7 +43,8 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
int result = f(); int result = f();
REQUIRE(result == 31); REQUIRE(result == 31);
lua.safe_script("g = function() test = 5 end"); auto result2 = lua.safe_script("g = function() test = 5 end", sol::script_pass_on_error);
REQUIRE(result2.valid());
sol::function g = lua["g"]; sol::function g = lua["g"];
sol::environment env_g(lua, sol::create); sol::environment env_g(lua, sol::create);
env_g.set_on(g); env_g.set_on(g);
@ -58,7 +57,8 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
sol::object global_test = lua["test"]; sol::object global_test = lua["test"];
REQUIRE(!global_test.valid()); REQUIRE(!global_test.valid());
lua.safe_script("h = function() end"); auto result3 = lua.safe_script("h = function() end", sol::script_pass_on_error);
REQUIRE(result3.valid());
lua.set_function("check_f_env", lua.set_function("check_f_env",
[&lua, &env_f](sol::object target) { [&lua, &env_f](sol::object target) {
@ -86,11 +86,12 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
sol::environment target_env = sol::get_environment(target); sol::environment target_env = sol::get_environment(target);
}); });
REQUIRE_NOTHROW([&lua]() { auto checkf = lua.safe_script("check_f_env(f)");
lua.safe_script("check_f_env(f)"); REQUIRE(checkf.valid());
lua.safe_script("check_g_env(g)"); auto checkg = lua.safe_script("check_g_env(g)");
lua.safe_script("check_h_env(h)"); REQUIRE(checkg.valid());
}()); auto checkh = lua.safe_script("check_h_env(h)");
REQUIRE(checkh.valid());
} }
TEST_CASE("environments/shadowing", "Environments can properly shadow and fallback on variables") { TEST_CASE("environments/shadowing", "Environments can properly shadow and fallback on variables") {
@ -100,7 +101,8 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
SECTION("no fallback") { SECTION("no fallback") {
sol::environment plain_env(lua, sol::create); sol::environment plain_env(lua, sol::create);
lua.safe_script("a = 24", plain_env); auto result1 = lua.safe_script("a = 24", plain_env, sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::optional<int> maybe_env_a = plain_env["a"]; sol::optional<int> maybe_env_a = plain_env["a"];
sol::optional<int> maybe_global_a = lua["a"]; sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = plain_env["b"]; sol::optional<int> maybe_env_b = plain_env["b"];
@ -116,7 +118,8 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
} }
SECTION("fallback") { SECTION("fallback") {
sol::environment env_with_fallback(lua, sol::create, lua.globals()); sol::environment env_with_fallback(lua, sol::create, lua.globals());
lua.safe_script("a = 56", env_with_fallback, sol::script_default_on_error); auto result1 = lua.safe_script("a = 56", env_with_fallback, sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::optional<int> maybe_env_a = env_with_fallback["a"]; sol::optional<int> maybe_env_a = env_with_fallback["a"];
sol::optional<int> maybe_global_a = lua["a"]; sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = env_with_fallback["b"]; sol::optional<int> maybe_env_b = env_with_fallback["b"];
@ -135,7 +138,8 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
sol::environment env_with_fallback(lua, sol::create, lua.globals()); sol::environment env_with_fallback(lua, sol::create, lua.globals());
lua["env"] = env_with_fallback; lua["env"] = env_with_fallback;
sol::environment env = lua["env"]; sol::environment env = lua["env"];
lua.safe_script("a = 56", env, sol::script_default_on_error); auto result1 = lua.safe_script("a = 56", env, sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::optional<int> maybe_env_a = env["a"]; sol::optional<int> maybe_env_a = env["a"];
sol::optional<int> maybe_global_a = lua["a"]; sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = env["b"]; sol::optional<int> maybe_env_b = env["b"];
@ -153,7 +157,9 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
SECTION("name with newtable") { SECTION("name with newtable") {
lua["blank_env"] = sol::new_table(0, 1); lua["blank_env"] = sol::new_table(0, 1);
sol::environment plain_env = lua["blank_env"]; sol::environment plain_env = lua["blank_env"];
lua.safe_script("a = 24", plain_env); auto result1 = lua.safe_script("a = 24", plain_env, sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::optional<int> maybe_env_a = plain_env["a"]; sol::optional<int> maybe_env_a = plain_env["a"];
sol::optional<int> maybe_global_a = lua["a"]; sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = plain_env["b"]; sol::optional<int> maybe_env_b = plain_env["b"];
@ -174,7 +180,8 @@ TEST_CASE("environments/functions", "see if environments on functions are workin
SECTION("basic") { SECTION("basic") {
sol::state lua; sol::state lua;
lua.safe_script("a = function() return 5 end"); auto result1 = lua.safe_script("a = function() return 5 end", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::function a = lua["a"]; sol::function a = lua["a"];
@ -184,13 +191,14 @@ TEST_CASE("environments/functions", "see if environments on functions are workin
sol::environment env(lua, sol::create); sol::environment env(lua, sol::create);
sol::set_environment(env, a); sol::set_environment(env, a);
int result1 = a(); int value = a();
REQUIRE(result1 == 5); REQUIRE(value == 5);
} }
SECTION("return environment value") { SECTION("return environment value") {
sol::state lua; sol::state lua;
lua.safe_script("a = function() return test end"); auto result1 = lua.safe_script("a = function() return test end", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::function a = lua["a"]; sol::function a = lua["a"];
sol::environment env(lua, sol::create); sol::environment env(lua, sol::create);
@ -204,7 +212,8 @@ TEST_CASE("environments/functions", "see if environments on functions are workin
SECTION("set environment value") { SECTION("set environment value") {
sol::state lua; sol::state lua;
lua.safe_script("a = function() test = 5 end"); auto result1 = lua.safe_script("a = function() test = 5 end", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::function a = lua["a"]; sol::function a = lua["a"];
sol::environment env(lua, sol::create); sol::environment env(lua, sol::create);
@ -240,7 +249,9 @@ TEST_CASE("environments/this_environment", "test various situations of pulling o
lua["x"] = 5; lua["x"] = 5;
e["x"] = 20; e["x"] = 20;
SECTION("from Lua script") { SECTION("from Lua script") {
int value = lua.safe_script(code, e); auto result1 = lua.safe_script(code, e, sol::script_pass_on_error);
REQUIRE(result1.valid());
int value = result1;
REQUIRE(value == 30); REQUIRE(value == 30);
} }
SECTION("from C++") { SECTION("from C++") {

View File

@ -21,10 +21,8 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
#include <iostream> #include <iostream>
@ -58,8 +56,8 @@ TEST_CASE("filters/self", "ensure we return a direct reference to the lua userda
"x", &vec2::x, "x", &vec2::x,
"y", &vec2::y, "y", &vec2::y,
"normalize", sol::filters(&vec2::normalize, sol::returns_self())); "normalize", sol::filters(&vec2::normalize, sol::returns_self()));
REQUIRE_NOTHROW([&]() {
lua.safe_script(R"( auto result1 = lua.safe_script(R"(
v1 = vec2.new() v1 = vec2.new()
print('v1:', v1.x, v1.y) print('v1:', v1.x, v1.y)
v2 = v1:normalize() v2 = v1:normalize()
@ -70,8 +68,8 @@ assert(rawequal(v1, v2))
v1 = nil v1 = nil
collectgarbage() collectgarbage()
print(v2) -- v2 points to same, is not destroyed print(v2) -- v2 points to same, is not destroyed
)"); )", sol::script_pass_on_error);
}()); REQUIRE(result1.valid());
} }
TEST_CASE("filters/self_dependency", "ensure we can keep a userdata instance alive by attaching it to the lifetime of another userdata") { TEST_CASE("filters/self_dependency", "ensure we can keep a userdata instance alive by attaching it to the lifetime of another userdata") {
@ -115,32 +113,36 @@ TEST_CASE("filters/self_dependency", "ensure we can keep a userdata instance ali
return "{ d: { " + std::to_string(g.d.value) + " } }"; return "{ d: { " + std::to_string(g.d.value) + " } }";
}); });
lua.safe_script(R"( auto result1 = lua.safe_script(R"(
g = gc_test.new() g = gc_test.new()
d = g.d d = g.d
print("new gc_test, d = g.d") print("new gc_test, d = g.d")
print("", g) print("", g)
)"); )", sol::script_pass_on_error);
REQUIRE(result1.valid());
REQUIRE(deps_destroyed.empty()); REQUIRE(deps_destroyed.empty());
REQUIRE(gc_tests_destroyed.empty()); REQUIRE(gc_tests_destroyed.empty());
gc_test* g = lua["g"]; gc_test* g = lua["g"];
dep* d = lua["d"]; dep* d = lua["d"];
lua.safe_script(R"( auto result2 = lua.safe_script(R"(
print("g = nil, collectgarbage") print("g = nil, collectgarbage")
g = nil g = nil
collectgarbage() collectgarbage()
print("", d) print("", d)
)"); )", sol::script_pass_on_error);
REQUIRE(result2.valid());
REQUIRE(deps_destroyed.empty()); REQUIRE(deps_destroyed.empty());
REQUIRE(gc_tests_destroyed.empty()); REQUIRE(gc_tests_destroyed.empty());
lua.safe_script(R"( auto result3 = lua.safe_script(R"(
print("d = nil, collectgarbage") print("d = nil, collectgarbage")
d = nil d = nil
collectgarbage() collectgarbage()
)"); )", sol::script_pass_on_error);
REQUIRE(result3.valid());
REQUIRE(deps_destroyed.size() == 1); REQUIRE(deps_destroyed.size() == 1);
REQUIRE(gc_tests_destroyed.size() == 1); REQUIRE(gc_tests_destroyed.size() == 1);
@ -199,11 +201,12 @@ TEST_CASE("filters/stack_dependencies", "ensure we can take dependencies even to
"new", sol::filters(sol::constructors<depends_on_reference(holder&)>(), sol::stack_dependencies(-1, 1)), "new", sol::filters(sol::constructors<depends_on_reference(holder&)>(), sol::stack_dependencies(-1, 1)),
"comp", &depends_on_reference::comp); "comp", &depends_on_reference::comp);
lua.safe_script(R"( auto result1 = lua.safe_script(R"(
h = holder.new() h = holder.new()
dor = depends_on_reference.new(h) dor = depends_on_reference.new(h)
c = dor.comp c = dor.comp
)"); )", sol::script_pass_on_error);
REQUIRE(result1.valid());
REQUIRE(composition_relateds_destroyed.empty()); REQUIRE(composition_relateds_destroyed.empty());
REQUIRE(holders_destroyed.empty()); REQUIRE(holders_destroyed.empty());
REQUIRE(depends_on_references_destroyed.empty()); REQUIRE(depends_on_references_destroyed.empty());
@ -215,27 +218,30 @@ c = dor.comp
REQUIRE(h == &dor->href.get()); REQUIRE(h == &dor->href.get());
REQUIRE(c == &dor->comp); REQUIRE(c == &dor->comp);
lua.safe_script(R"( auto result2 = lua.safe_script(R"(
h = nil h = nil
collectgarbage() collectgarbage()
)"); )");
REQUIRE(result2.valid());
REQUIRE(composition_relateds_destroyed.empty()); REQUIRE(composition_relateds_destroyed.empty());
REQUIRE(holders_destroyed.empty()); REQUIRE(holders_destroyed.empty());
REQUIRE(depends_on_references_destroyed.empty()); REQUIRE(depends_on_references_destroyed.empty());
lua.safe_script(R"( auto result3 = lua.safe_script(R"(
c = nil c = nil
collectgarbage() collectgarbage()
)"); )", sol::script_pass_on_error);
REQUIRE(result3.valid());
REQUIRE(composition_relateds_destroyed.empty()); REQUIRE(composition_relateds_destroyed.empty());
REQUIRE(holders_destroyed.empty()); REQUIRE(holders_destroyed.empty());
REQUIRE(depends_on_references_destroyed.empty()); REQUIRE(depends_on_references_destroyed.empty());
lua.safe_script(R"( auto result4 = lua.safe_script(R"(
dor = nil dor = nil
collectgarbage() collectgarbage()
)"); )", sol::script_pass_on_error);
REQUIRE(result4.valid());
REQUIRE(composition_relateds_destroyed.size() == 1); REQUIRE(composition_relateds_destroyed.size() == 1);
REQUIRE(holders_destroyed.size() == 1); REQUIRE(holders_destroyed.size() == 1);

View File

@ -21,15 +21,12 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp> #include "test_sol.hpp"
#include <catch.hpp> #include <catch.hpp>
#include <iostream> #include <iostream>
#include "test_stack_guard.hpp"
template <typename T> template <typename T>
T va_func(sol::variadic_args va, T first) { T va_func(sol::variadic_args va, T first) {
@ -73,8 +70,7 @@ void test_free_func(std::function<void()> f) {
void test_free_func2(std::function<int(int)> f, int arg1) { void test_free_func2(std::function<int(int)> f, int arg1) {
int val = f(arg1); int val = f(arg1);
if (val != arg1) REQUIRE(val == arg1);
throw sol::error("failed function call!");
} }
int overloaded(int x) { int overloaded(int x) {
@ -137,7 +133,8 @@ static int raw_noexcept_function(lua_State* L) noexcept {
TEST_CASE("functions/tuple returns", "Make sure tuple returns are ordered properly") { TEST_CASE("functions/tuple returns", "Make sure tuple returns are ordered properly") {
sol::state lua; sol::state lua;
lua.safe_script("function f() return '3', 4 end"); auto result1 = lua.safe_script("function f() return '3', 4 end", sol::script_pass_on_error);
REQUIRE(result1.valid());
std::tuple<std::string, int> result = lua["f"](); std::tuple<std::string, int> result = lua["f"]();
auto s = std::get<0>(result); auto s = std::get<0>(result);
@ -197,7 +194,9 @@ TEST_CASE("functions/return order and multi get", "Check if return order is in t
lua.set_function("h", []() { lua.set_function("h", []() {
return std::make_tuple(10, 10.0f); return std::make_tuple(10, 10.0f);
}); });
lua.safe_script("function g() return 10, 11, 12 end\nx,y,z = g()"); auto result1 = lua.safe_script("function g() return 10, 11, 12 end\nx,y,z = g()", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto tcpp = lua.get<sol::function>("f").call<int, int, int>(); auto tcpp = lua.get<sol::function>("f").call<int, int, int>();
auto tlua = lua.get<sol::function>("g").call<int, int, int>(); auto tlua = lua.get<sol::function>("g").call<int, int, int>();
auto tcpp2 = lua.get<sol::function>("h").call<int, float>(); auto tcpp2 = lua.get<sol::function>("h").call<int, float>();
@ -223,7 +222,9 @@ TEST_CASE("functions/deducing return order and multi get", "Check if return orde
lua.set_function("f", [] { lua.set_function("f", [] {
return std::make_tuple(10, 11, 12); return std::make_tuple(10, 11, 12);
}); });
lua.safe_script("function g() return 10, 11, 12 end\nx,y,z = g()"); auto result1 = lua.safe_script("function g() return 10, 11, 12 end\nx,y,z = g()", sol::script_pass_on_error);
REQUIRE(result1.valid());
std::tuple<int, int, int> tcpp = lua.get<sol::function>("f")(); std::tuple<int, int, int> tcpp = lua.get<sol::function>("f")();
std::tuple<int, int, int> tlua = lua.get<sol::function>("g")(); std::tuple<int, int, int> tlua = lua.get<sol::function>("g")();
std::tuple<int, int, int> tluaget = lua.get<int, int, int>("x", "y", "z"); std::tuple<int, int, int> tluaget = lua.get<int, int, int>("x", "y", "z");
@ -240,9 +241,10 @@ TEST_CASE("functions/optional values", "check if optionals can be passed in to b
int v; int v;
}; };
sol::state lua; sol::state lua;
lua.safe_script(R"( function f (a) auto result1 = lua.safe_script(R"( function f (a)
return a return a
end )"); end )", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::function lua_bark = lua["f"]; sol::function lua_bark = lua["f"];
@ -260,13 +262,15 @@ TEST_CASE("functions/pair and tuple and proxy tests", "Check if sol::reference a
sol::state lua; sol::state lua;
lua.new_usertype<A>("A", lua.new_usertype<A>("A",
"bark", &A::bark); "bark", &A::bark);
lua.safe_script(R"( function f (num_value, a) auto result1 = lua.safe_script(R"( function f (num_value, a)
return num_value * 2, a:bark() return num_value * 2, a:bark()
end end
function h (num_value, a, b) function h (num_value, a, b)
return num_value * 2, a:bark(), b * 3 return num_value * 2, a:bark(), b * 3
end end
nested = { variables = { no = { problem = 10 } } } )"); nested = { variables = { no = { problem = 10 } } } )", sol::script_pass_on_error);
REQUIRE(result1.valid());
lua.set_function("g", bark); lua.set_function("g", bark);
sol::function cpp_bark = lua["g"]; sol::function cpp_bark = lua["g"];
@ -302,8 +306,8 @@ TEST_CASE("functions/sol::function to std::function", "check if conversion to st
lua.set_function("testFunc", test_free_func); lua.set_function("testFunc", test_free_func);
lua.set_function("testFunc2", test_free_func2); lua.set_function("testFunc2", test_free_func2);
lua.safe_script( auto result1 = lua.safe_script("testFunc(function() print(\"hello std::function\") end)", sol::script_pass_on_error);
"testFunc(function() print(\"hello std::function\") end)"); REQUIRE(result1.valid());
{ {
auto result = lua.safe_script( auto result = lua.safe_script(
"function m(a)\n" "function m(a)\n"
@ -326,7 +330,7 @@ TEST_CASE("functions/returning functions from C++", "check to see if returning a
auto result = lua.safe_script( auto result = lua.safe_script(
"afx = makefn()\n" "afx = makefn()\n"
"print(afx())\n" "print(afx())\n"
"takefn(afx)\n"); "takefn(afx)\n", sol::script_pass_on_error);
REQUIRE(result.valid()); REQUIRE(result.valid());
} }
} }
@ -357,11 +361,12 @@ TEST_CASE("functions/function_result and protected_function_result", "Function r
return handlederrormessage; return handlederrormessage;
}; };
lua.set_function("cpphandler", cpphandlerfx); lua.set_function("cpphandler", cpphandlerfx);
lua.safe_script( auto result1 = lua.safe_script(
std::string("function luahandler ( message )") std::string("function luahandler ( message )")
+ " print('lua handler called with: ' .. message)" + " print('lua handler called with: ' .. message)"
+ " return '" + handlederrormessage + "'" + " return '" + handlederrormessage + "'"
+ "end"); + "end", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto nontrampolinefx = [](lua_State*) -> int { throw "x"; }; auto nontrampolinefx = [](lua_State*) -> int { throw "x"; };
lua_CFunction c_nontrampolinefx = nontrampolinefx; lua_CFunction c_nontrampolinefx = nontrampolinefx;
lua.set("nontrampoline", c_nontrampolinefx); lua.set("nontrampoline", c_nontrampolinefx);
@ -499,12 +504,13 @@ TEST_CASE("functions/all kinds", "Register all kinds of functions, make sure the
lua.set_function("m", &test_2::a, &t2); lua.set_function("m", &test_2::a, &t2);
lua.set_function("n", sol::c_call<decltype(&non_overloaded), &non_overloaded>); lua.set_function("n", sol::c_call<decltype(&non_overloaded), &non_overloaded>);
lua.safe_script(R"( auto result1 = lua.safe_script(R"(
o1 = test_1.new() o1 = test_1.new()
o2 = test_2.new() o2 = test_2.new()
)"); )", sol::script_pass_on_error);
REQUIRE(result1.valid());
lua.safe_script(R"( auto result2 = lua.safe_script(R"(
ob = o1:bark() ob = o1:bark()
A = a() A = a()
@ -516,35 +522,42 @@ G0, G1 = g(2, o1)
H = h(o1) H = h(o1)
I = i(o1) I = i(o1)
I = i(o1) I = i(o1)
)"); )", sol::script_pass_on_error);
REQUIRE(result2.valid());
lua.safe_script(R"( auto result3 = lua.safe_script(R"(
J0 = j() J0 = j()
j(24) j(24)
J1 = j() J1 = j()
)"); )", sol::script_pass_on_error);
REQUIRE(result3.valid());
lua.safe_script(R"( auto result4 = lua.safe_script(R"(
K0 = k(o2) K0 = k(o2)
k(o2, 1024) k(o2, 1024)
K1 = k(o2) K1 = k(o2)
)"); )", sol::script_pass_on_error);
REQUIRE(result4.valid());
lua.safe_script(R"( auto result5 = lua.safe_script(R"(
L0 = l(o1) L0 = l(o1)
l(o1, 678) l(o1, 678)
L1 = l(o1) L1 = l(o1)
)"); )", sol::script_pass_on_error);
REQUIRE(result5.valid());
lua.safe_script(R"( auto result6 = lua.safe_script(R"(
M0 = m() M0 = m()
m(256) m(256)
M1 = m() M1 = m()
)"); )", sol::script_pass_on_error);
REQUIRE(result6.valid());
lua.safe_script(R"( auto result7 = lua.safe_script(R"(
N = n(1, 2, 3) N = n(1, 2, 3)
)"); )", sol::script_pass_on_error);
REQUIRE(result7.valid());
int ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1, N; int ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1, N;
std::tie(ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1, N) std::tie(ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1, N)
= lua.get<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>( = lua.get<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>(
@ -668,7 +681,8 @@ TEST_CASE("simple/call c++ function", "C++ function is called from lua") {
sol::state lua; sol::state lua;
lua.set_function("plop_xyz", sep::plop_xyz); lua.set_function("plop_xyz", sep::plop_xyz);
lua.safe_script("x = plop_xyz(2, 6, 'hello')"); auto result1 = lua.safe_script("x = plop_xyz(2, 6, 'hello')", sol::script_pass_on_error);
REQUIRE(result1.valid());
REQUIRE(lua.get<int>("x") == 11); REQUIRE(lua.get<int>("x") == 11);
} }
@ -680,7 +694,8 @@ TEST_CASE("simple/call lambda", "A C++ lambda is exposed to lua and called") {
lua.set_function("foo", [&a] { a = 1; }); lua.set_function("foo", [&a] { a = 1; });
lua.safe_script("foo()"); auto result1 = lua.safe_script("foo()", sol::script_pass_on_error);
REQUIRE(result1.valid());
REQUIRE(a == 1); REQUIRE(a == 1);
} }
@ -764,7 +779,8 @@ TEST_CASE("advanced/call lambdas", "A C++ lambda is exposed to lua and called")
return 0; return 0;
}); });
lua.safe_script("set_x(9)"); auto result1 = lua.safe_script("set_x(9)", sol::script_pass_on_error);
REQUIRE(result1.valid());
REQUIRE(x == 9); REQUIRE(x == 9);
} }
@ -785,8 +801,11 @@ TEST_CASE("advanced/call referenced obj", "A C++ object is passed by pointer/ref
}; };
lua.set_function("set_y", &decltype(objy)::operator(), std::ref(objy)); lua.set_function("set_y", &decltype(objy)::operator(), std::ref(objy));
lua.safe_script("set_x(9)"); auto result1 = lua.safe_script("set_x(9)", sol::script_pass_on_error);
lua.safe_script("set_y(9)"); REQUIRE(result1.valid());
auto result2 = lua.safe_script("set_y(9)", sol::script_pass_on_error);
REQUIRE(result2.valid());
REQUIRE(x == 9); REQUIRE(x == 9);
REQUIRE(y == 9); REQUIRE(y == 9);
} }
@ -794,9 +813,10 @@ TEST_CASE("advanced/call referenced obj", "A C++ object is passed by pointer/ref
TEST_CASE("functions/tie", "make sure advanced syntax with 'tie' works") { TEST_CASE("functions/tie", "make sure advanced syntax with 'tie' works") {
sol::state lua; sol::state lua;
lua.safe_script(R"(function f () auto result1 = lua.safe_script(R"(function f ()
return 1, 2, 3 return 1, 2, 3
end)"); end)", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::function f = lua["f"]; sol::function f = lua["f"];
int a, b, c; int a, b, c;

View File

@ -21,10 +21,8 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
#include <iostream> #include <iostream>
@ -148,16 +146,16 @@ end
gc_entity e; gc_entity e;
target = &e; target = &e;
{ {
f(e); // same with std::ref(e)! f(e);
lua.collect_garbage(); // destroys e for some reason lua.collect_garbage();
} }
{ {
f(&e); // same with std::ref(e)! f(&e);
lua.collect_garbage(); // destroys e for some reason lua.collect_garbage();
} }
{ {
f(std::ref(e)); // same with std::ref(e)! f(std::ref(e));
lua.collect_garbage(); // destroys e for some reason lua.collect_garbage();
} }
} }
REQUIRE(entities.size() == 1); REQUIRE(entities.size() == 1);
@ -293,13 +291,15 @@ TEST_CASE("gc/function storage", "show that proper copies / destruction happens
sol::state lua; sol::state lua;
x x1; x x1;
lua.set_function("x1copy", &x::func, x1); lua.set_function("x1copy", &x::func, x1);
lua.safe_script("x1copy()"); auto result1 = lua.safe_script("x1copy()", sol::script_pass_on_error);
REQUIRE(result1.valid());
REQUIRE(created == 2); REQUIRE(created == 2);
REQUIRE(destroyed == 0); REQUIRE(destroyed == 0);
REQUIRE_FALSE(last_call == &x1); REQUIRE_FALSE(last_call == &x1);
lua.set_function("x1ref", &x::func, std::ref(x1)); lua.set_function("x1ref", &x::func, std::ref(x1));
lua.safe_script("x1ref()"); auto result2 = lua.safe_script("x1ref()", sol::script_pass_on_error);
REQUIRE(result2.valid());
REQUIRE(created == 2); REQUIRE(created == 2);
REQUIRE(destroyed == 0); REQUIRE(destroyed == 0);
REQUIRE(last_call == &x1); REQUIRE(last_call == &x1);
@ -318,14 +318,16 @@ TEST_CASE("gc/function storage", "show that proper copies / destruction happens
sol::state lua; sol::state lua;
y y1; y y1;
lua.set_function("y1copy", y1); lua.set_function("y1copy", y1);
lua.safe_script("y1copy()"); auto result1 = lua.safe_script("y1copy()", sol::script_pass_on_error);
REQUIRE(result1.valid());
REQUIRE(created == 1); REQUIRE(created == 1);
REQUIRE(destroyed == 0); REQUIRE(destroyed == 0);
REQUIRE(last_call == static_call); REQUIRE(last_call == static_call);
last_call = nullptr; last_call = nullptr;
lua.set_function("y1ref", std::ref(y1)); lua.set_function("y1ref", std::ref(y1));
lua.safe_script("y1ref()"); auto result2 = lua.safe_script("y1ref()", sol::script_pass_on_error);
REQUIRE(result2.valid());
REQUIRE(created == 1); REQUIRE(created == 1);
REQUIRE(destroyed == 0); REQUIRE(destroyed == 0);
REQUIRE(last_call == static_call); REQUIRE(last_call == static_call);
@ -483,11 +485,12 @@ TEST_CASE("gc/double-deletion tests", "make sure usertypes are properly destruct
lua.new_usertype<crash_class>("CrashClass", lua.new_usertype<crash_class>("CrashClass",
sol::call_constructor, sol::constructors<sol::types<>>()); sol::call_constructor, sol::constructors<sol::types<>>());
lua.safe_script(R"( auto result1 = lua.safe_script(R"(
function testCrash() function testCrash()
local x = CrashClass() local x = CrashClass()
end end
)"); )", sol::script_pass_on_error);
REQUIRE(result1.valid());
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
lua["testCrash"](); lua["testCrash"]();
@ -497,11 +500,12 @@ TEST_CASE("gc/double-deletion tests", "make sure usertypes are properly destruct
lua.new_simple_usertype<crash_class>("CrashClass", lua.new_simple_usertype<crash_class>("CrashClass",
sol::call_constructor, sol::constructors<sol::types<>>()); sol::call_constructor, sol::constructors<sol::types<>>());
lua.safe_script(R"( auto result1 = lua.safe_script(R"(
function testCrash() function testCrash()
local x = CrashClass() local x = CrashClass()
end end
)"); )", sol::script_pass_on_error);
REQUIRE(result1.valid());
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
lua["testCrash"](); lua["testCrash"]();
@ -537,7 +541,8 @@ TEST_CASE("gc/shared_ptr regression", "metatables should not screw over unique u
}); });
REQUIRE(created == 0); REQUIRE(created == 0);
REQUIRE(destroyed == 0); REQUIRE(destroyed == 0);
lua.safe_script("x = test.create()"); auto result1 = lua.safe_script("x = test.create()", sol::script_pass_on_error);
REQUIRE(result1.valid());
REQUIRE(created == 1); REQUIRE(created == 1);
REQUIRE(destroyed == 0); REQUIRE(destroyed == 0);
REQUIRE_FALSE(tests.empty()); REQUIRE_FALSE(tests.empty());
@ -564,7 +569,8 @@ TEST_CASE("gc/shared_ptr regression", "metatables should not screw over unique u
}); });
REQUIRE(created == 0); REQUIRE(created == 0);
REQUIRE(destroyed == 0); REQUIRE(destroyed == 0);
lua.safe_script("x = test.create()"); auto result1 = lua.safe_script("x = test.create()", sol::script_pass_on_error);
REQUIRE(result1.valid());
REQUIRE(created == 1); REQUIRE(created == 1);
REQUIRE(destroyed == 0); REQUIRE(destroyed == 0);
REQUIRE_FALSE(tests.empty()); REQUIRE_FALSE(tests.empty());
@ -635,7 +641,10 @@ TEST_CASE("gc/alignment", "test that allocation is always on aligned boundaries,
test obj{}; test obj{};
lua["obj"] = &obj; lua["obj"] = &obj;
INFO("obj"); INFO("obj");
lua.script("obj.callback()"); {
auto r = lua.safe_script("obj.callback()", sol::script_pass_on_error);
REQUIRE(r.valid());
}
{ {
// Do not check for stack-created object // Do not check for stack-created object
//test& lobj = lua["obj"]; //test& lobj = lua["obj"];
@ -644,7 +653,10 @@ TEST_CASE("gc/alignment", "test that allocation is always on aligned boundaries,
lua["obj0"] = std::ref(obj); lua["obj0"] = std::ref(obj);
INFO("obj0"); INFO("obj0");
lua.script("obj0.callback()"); {
auto r = lua.safe_script("obj0.callback()", sol::script_pass_on_error);
REQUIRE(r.valid());
}
{ {
// Do not check for stack-created object // Do not check for stack-created object
//test& lobj = lua["obj0"]; //test& lobj = lua["obj0"];
@ -653,7 +665,10 @@ TEST_CASE("gc/alignment", "test that allocation is always on aligned boundaries,
lua["obj1"] = obj; lua["obj1"] = obj;
INFO("obj1"); INFO("obj1");
lua.script("obj1.callback()"); {
auto r = lua.safe_script("obj1.callback()", sol::script_pass_on_error);
REQUIRE(r.valid());
}
{ {
test& lobj = lua["obj1"]; test& lobj = lua["obj1"];
lobj.check_alignment(); lobj.check_alignment();
@ -661,7 +676,10 @@ TEST_CASE("gc/alignment", "test that allocation is always on aligned boundaries,
lua["obj2"] = test{}; lua["obj2"] = test{};
INFO("obj2"); INFO("obj2");
lua.script("obj2.callback()"); {
auto r = lua.safe_script("obj2.callback()", sol::script_pass_on_error);
REQUIRE(r.valid());
}
{ {
test& lobj = lua["obj2"]; test& lobj = lua["obj2"];
lobj.check_alignment(); lobj.check_alignment();
@ -669,7 +687,10 @@ TEST_CASE("gc/alignment", "test that allocation is always on aligned boundaries,
lua["obj3"] = std::make_unique<test>(); lua["obj3"] = std::make_unique<test>();
INFO("obj3"); INFO("obj3");
lua.script("obj3.callback()"); {
auto r = lua.safe_script("obj3.callback()", sol::script_pass_on_error);
REQUIRE(r.valid());
}
{ {
test& lobj = lua["obj3"]; test& lobj = lua["obj3"];
lobj.check_alignment(); lobj.check_alignment();
@ -677,7 +698,10 @@ TEST_CASE("gc/alignment", "test that allocation is always on aligned boundaries,
lua["obj4"] = std::make_shared<test>(); lua["obj4"] = std::make_shared<test>();
INFO("obj4"); INFO("obj4");
lua.script("obj4.callback()"); {
auto r = lua.safe_script("obj4.callback()", sol::script_pass_on_error);
REQUIRE(r.valid());
}
{ {
test& lobj = lua["obj4"]; test& lobj = lua["obj4"];
lobj.check_alignment(); lobj.check_alignment();

View File

@ -21,10 +21,8 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
#include <iostream> #include <iostream>
@ -62,14 +60,19 @@ TEST_CASE("inheritance/basic", "test that metatables are properly inherited") {
"d", &D::d, "d", &D::d,
sol::base_classes, sol::bases<C, B, A>()); sol::base_classes, sol::bases<C, B, A>());
lua.safe_script("obj = D.new()"); auto result1 = lua.safe_script("obj = D.new()", sol::script_pass_on_error);
lua.safe_script("d = obj:d()"); REQUIRE(result1.valid());
auto result2 = lua.safe_script("d = obj:d()", sol::script_pass_on_error);
REQUIRE(result2.valid());
bool d = lua["d"]; bool d = lua["d"];
lua.safe_script("c = obj.c"); auto result3 = lua.safe_script("c = obj.c", sol::script_pass_on_error);
REQUIRE(result3.valid());
double c = lua["c"]; double c = lua["c"];
lua.safe_script("b = obj:b()"); auto result4 = lua.safe_script("b = obj:b()", sol::script_pass_on_error);
REQUIRE(result4.valid());
int b = lua["b"]; int b = lua["b"];
lua.safe_script("a = obj.a"); auto result5 = lua.safe_script("a = obj.a", sol::script_pass_on_error);
REQUIRE(result5.valid());
int a = lua["a"]; int a = lua["a"];
REQUIRE(d); REQUIRE(d);
@ -160,21 +163,13 @@ TEST_CASE("inheritance/multi base", "test that multiple bases all work and overl
lua.set_usertype("TestClass03", s_TestUsertype03); lua.set_usertype("TestClass03", s_TestUsertype03);
lua.safe_script(R"( auto result1 = lua.safe_script(R"(
tc0 = TestClass00() tc0 = TestClass00()
)");
lua.safe_script(R"(
tc2 = TestClass02(tc0) tc2 = TestClass02(tc0)
)");
lua.safe_script(R"(
tc1 = TestClass01() tc1 = TestClass01()
)");
lua.safe_script(R"(
tc3 = TestClass03(tc1) tc3 = TestClass03(tc1)
)"); )", sol::script_pass_on_error);
REQUIRE(result1.valid());
TestClass00& tc0 = lua["tc0"]; TestClass00& tc0 = lua["tc0"];
TestClass01& tc1 = lua["tc1"]; TestClass01& tc1 = lua["tc1"];
@ -271,22 +266,13 @@ TEST_CASE("inheritance/simple multi base", "test that multiple bases all work an
lua.set_usertype("TestClass03", s_TestUsertype03); lua.set_usertype("TestClass03", s_TestUsertype03);
lua.safe_script(R"( auto result1 = lua.safe_script(R"(
tc0 = TestClass00() tc0 = TestClass00()
)");
lua.safe_script(R"(
tc2 = TestClass02(tc0) tc2 = TestClass02(tc0)
)");
lua.safe_script(R"(
tc1 = TestClass01() tc1 = TestClass01()
)");
lua.safe_script(R"(
tc3 = TestClass03(tc1) tc3 = TestClass03(tc1)
)"); )", sol::script_pass_on_error);
REQUIRE(result1.valid());
TestClass00& tc0 = lua["tc0"]; TestClass00& tc0 = lua["tc0"];
TestClass01& tc1 = lua["tc1"]; TestClass01& tc1 = lua["tc1"];
TestClass02& tc2 = lua["tc2"]; TestClass02& tc2 = lua["tc2"];

View File

@ -21,10 +21,7 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
@ -38,8 +35,9 @@ TEST_CASE("large_integer/bool", "pass bool integral value to and from lua") {
REQUIRE(num == true); REQUIRE(num == true);
return num; return num;
}); });
lua.safe_script("x = f(true)"); auto result1 = lua.safe_script("x = f(true)\n"
lua.safe_script("assert(x == true)"); "assert(x == true)", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::object x = lua["x"]; sol::object x = lua["x"];
REQUIRE(x.is<bool>()); REQUIRE(x.is<bool>());
REQUIRE(x.as<bool>() == true); REQUIRE(x.as<bool>() == true);
@ -58,8 +56,9 @@ TEST_CASE("large_integers/unsigned32", "pass large unsigned 32bit values to and
REQUIRE(num == 0xFFFFFFFF); REQUIRE(num == 0xFFFFFFFF);
return num; return num;
}); });
lua.safe_script("x = f(0xFFFFFFFF)"); auto result1 = lua.safe_script("x = f(0xFFFFFFFF)\n"
lua.safe_script("assert(x == 0xFFFFFFFF)"); "assert(x == 0xFFFFFFFF)", sol::script_pass_on_error);
REQUIRE(result1.valid());
sol::object x = lua["x"]; sol::object x = lua["x"];
REQUIRE(x.is<T>()); REQUIRE(x.is<T>());
REQUIRE(x.as<T>() == 0xFFFFFFFF); REQUIRE(x.as<T>() == 0xFFFFFFFF);
@ -73,8 +72,9 @@ TEST_CASE("large_integer/unsigned53", "pass large unsigned 53bit value to and fr
REQUIRE(num == 0x1FFFFFFFFFFFFFull); REQUIRE(num == 0x1FFFFFFFFFFFFFull);
return num; return num;
}); });
lua.safe_script("x = f(0x1FFFFFFFFFFFFF)"); auto result1 = lua.safe_script("x = f(0x1FFFFFFFFFFFFF)\n"
lua.safe_script("assert(x == 0x1FFFFFFFFFFFFF)"); "assert(x == 0x1FFFFFFFFFFFFF)");
REQUIRE(result1.valid());
sol::object x = lua["x"]; sol::object x = lua["x"];
REQUIRE(x.is<T>()); REQUIRE(x.is<T>());
REQUIRE(x.as<T>() == 0x1FFFFFFFFFFFFFull); REQUIRE(x.as<T>() == 0x1FFFFFFFFFFFFFull);
@ -107,38 +107,50 @@ TEST_CASE("large_integer/double", "pass negative and large positive values as si
lua.set_function("u64", [&](std::uint64_t num) { lua.set_function("u64", [&](std::uint64_t num) {
return num; return num;
}); });
//signed 32bit {
REQUIRE_NOTHROW([&lua]() { //signed 32bit
lua.safe_script("x = s32(-1)"); auto result1 = lua.safe_script("x = s32(-1)", sol::script_pass_on_error);
lua.safe_script("assert(x == -1)"); REQUIRE(result1.valid());
lua.safe_script("x = s32(0xFFFFFFFF)"); auto result2 = lua.safe_script("assert(x == -1)", sol::script_pass_on_error);
lua.safe_script("assert(x == -1)"); REQUIRE(result2.valid());
auto result3 = lua.safe_script("x = s32(0xFFFFFFFF)", sol::script_pass_on_error);
REQUIRE(result3.valid());
auto result4 = lua.safe_script("assert(x == -1)", sol::script_pass_on_error);
REQUIRE(result4.valid());
sol::object x = lua["x"]; sol::object x = lua["x"];
REQUIRE(x.is<std::int32_t>()); REQUIRE(x.is<std::int32_t>());
REQUIRE(x.as<std::int32_t>() == -1); REQUIRE(x.as<std::int32_t>() == -1);
REQUIRE(x.is<std::uint32_t>()); REQUIRE(x.is<std::uint32_t>());
REQUIRE(x.as<std::uint32_t>() == 0xFFFFFFFF); REQUIRE(x.as<std::uint32_t>() == 0xFFFFFFFF);
}()); }
//unsigned 32bit //unsigned 32bit
REQUIRE_NOTHROW([&lua]() { {
lua.safe_script("x = u32(0xFFFFFFFF)"); auto result1 = lua.safe_script("x = u32(0xFFFFFFFF)", sol::script_pass_on_error);
lua.safe_script("assert(x == 0xFFFFFFFF)"); REQUIRE(result1.valid());
lua.safe_script("x = u32(-1)"); auto result2 = lua.safe_script("assert(x == 0xFFFFFFFF)", sol::script_pass_on_error);
lua.safe_script("assert(x == 0xFFFFFFFF)"); REQUIRE(result2.valid());
auto result3 = lua.safe_script("x = u32(-1)", sol::script_pass_on_error);
REQUIRE(result3.valid());
auto result4 = lua.safe_script("assert(x == 0xFFFFFFFF)", sol::script_pass_on_error);
REQUIRE(result4.valid());
sol::object x = lua["x"]; sol::object x = lua["x"];
REQUIRE(x.is<std::int32_t>()); REQUIRE(x.is<std::int32_t>());
REQUIRE(x.as<std::int32_t>() == -1); REQUIRE(x.as<std::int32_t>() == -1);
REQUIRE(x.is<std::uint32_t>()); REQUIRE(x.is<std::uint32_t>());
REQUIRE(x.as<std::uint32_t>() == 0xFFFFFFFF); REQUIRE(x.as<std::uint32_t>() == 0xFFFFFFFF);
}()); }
//signed 64bit //signed 64bit
REQUIRE_NOTHROW([&lua]() { {
lua.safe_script("x = s64(-1)"); auto result1 = lua.safe_script("x = s64(-1)", sol::script_pass_on_error);
lua.safe_script("assert(x == -1)"); REQUIRE(result1.valid());
auto result2 = lua.safe_script("assert(x == -1)", sol::script_pass_on_error);
REQUIRE(result2.valid());
sol::object x = lua["x"]; sol::object x = lua["x"];
REQUIRE(x.is<std::int64_t>()); REQUIRE(x.is<std::int64_t>());
REQUIRE(x.as<std::int64_t>() == -1); REQUIRE(x.as<std::int64_t>() == -1);
REQUIRE(x.is<std::uint64_t>()); REQUIRE(x.is<std::uint64_t>());
REQUIRE(x.as<std::uint64_t>() == 0xFFFFFFFFFFFFFFFFull); REQUIRE(x.as<std::uint64_t>() == 0xFFFFFFFFFFFFFFFFull);
}()); }
} }

View File

@ -21,10 +21,7 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
@ -77,40 +74,46 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
SECTION("plain") { SECTION("plain") {
// Can only compare identity here // Can only compare identity here
REQUIRE_NOTHROW([&] { {
lua.safe_script("assert(t1 == t1)"); auto result1 = lua.safe_script("assert(t1 == t1)"
lua.safe_script("assert(t2 == t2)"); "assert(t2 == t2)"
lua.safe_script("assert(t3 == t3)"); "assert(t3 == t3)", sol::script_pass_on_error);
}()); REQUIRE(result1.valid());
REQUIRE_NOTHROW([&] { }
lua.safe_script("assert(t1 == t2)"); {
lua.safe_script("assert(not (t1 == t3))"); auto result1 = lua.safe_script("assert(t1 == t2)"
lua.safe_script("assert(not (t2 == t3))"); "assert(not (t1 == t3))"
}()); "assert(not (t2 == t3))", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
// Object should compare equal to themselves // Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient) // (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] { {
lua.safe_script("assert(u1 == u1)"); auto result1 = lua.safe_script("assert(u1 == u1)"
lua.safe_script("assert(u2 == u2)"); "assert(u2 == u2)"
lua.safe_script("assert(u3 == u3)"); "assert(u3 == u3)", sol::script_pass_on_error);
}()); REQUIRE(result1.valid());
REQUIRE_NOTHROW([&] { }
lua.safe_script("assert(not (u1 == u2))"); {
lua.safe_script("assert(u1 == u3)"); auto result1 = lua.safe_script("assert(not (u1 == u2))"
lua.safe_script("assert(not (u2 == u3))"); "assert(u1 == u3)"
}()); "assert(not (u2 == u3))", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
// Object should compare equal to themselves // Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient) // (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] { {
lua.safe_script("assert(v1 == v1)"); auto result1 = lua.safe_script("assert(v1 == v1)"
lua.safe_script("assert(v2 == v2)"); "assert(v2 == v2)"
lua.safe_script("assert(v3 == v3)"); "assert(v3 == v3)", sol::script_pass_on_error);
}()); REQUIRE(result1.valid());
REQUIRE_NOTHROW([&] { }
lua.safe_script("assert(not (v1 == v2))"); {
lua.safe_script("assert(v1 == v3)"); auto result1 = lua.safe_script("assert(not (v1 == v2))"
lua.safe_script("assert(not (v2 == v3))"); "assert(v1 == v3)"
}()); "assert(not (v2 == v3))", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
} }
SECTION("regular") { SECTION("regular") {
lua.new_usertype<T>("T"); lua.new_usertype<T>("T");
@ -118,40 +121,46 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
lua.new_usertype<V>("V"); lua.new_usertype<V>("V");
// Can only compare identity here // Can only compare identity here
REQUIRE_NOTHROW([&] { {
lua.safe_script("assert(t1 == t1)"); auto result1 = lua.safe_script("assert(t1 == t1)"
lua.safe_script("assert(t2 == t2)"); "assert(t2 == t2)"
lua.safe_script("assert(t3 == t3)"); "assert(t3 == t3)", sol::script_pass_on_error);
}()); REQUIRE(result1.valid());
REQUIRE_NOTHROW([&] { }
lua.safe_script("assert(t1 == t2)"); {
lua.safe_script("assert(not (t1 == t3))"); auto result1 = lua.safe_script("assert(t1 == t2)"
lua.safe_script("assert(not (t2 == t3))"); "assert(not (t1 == t3))"
}()); "assert(not (t2 == t3))", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
// Object should compare equal to themselves // Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient) // (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] { {
lua.safe_script("assert(u1 == u1)"); auto result1 = lua.safe_script("assert(u1 == u1)"
lua.safe_script("assert(u2 == u2)"); "assert(u2 == u2)"
lua.safe_script("assert(u3 == u3)"); "assert(u3 == u3)", sol::script_pass_on_error);
}()); REQUIRE(result1.valid());
REQUIRE_NOTHROW([&] { }
lua.safe_script("assert(not (u1 == u2))"); {
lua.safe_script("assert(u1 == u3)"); auto result1 = lua.safe_script("assert(not (u1 == u2))"
lua.safe_script("assert(not (u2 == u3))"); "assert(u1 == u3)"
}()); "assert(not (u2 == u3))", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
// Object should compare equal to themselves // Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient) // (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] { {
lua.safe_script("assert(v1 == v1)"); auto result1 = lua.safe_script("assert(v1 == v1)"
lua.safe_script("assert(v2 == v2)"); "assert(v2 == v2)"
lua.safe_script("assert(v3 == v3)"); "assert(v3 == v3)", sol::script_pass_on_error);
}()); REQUIRE(result1.valid());
REQUIRE_NOTHROW([&] { }
lua.safe_script("assert(not (v1 == v2))"); {
lua.safe_script("assert(v1 == v3)"); auto result1 = lua.safe_script("assert(not (v1 == v2))"
lua.safe_script("assert(not (v2 == v3))"); "assert(v1 == v3)"
}()); "assert(not (v2 == v3))", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
} }
SECTION("simple") { SECTION("simple") {
lua.new_simple_usertype<T>("T"); lua.new_simple_usertype<T>("T");
@ -159,40 +168,46 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
lua.new_simple_usertype<V>("V"); lua.new_simple_usertype<V>("V");
// Can only compare identity here // Can only compare identity here
REQUIRE_NOTHROW([&] { {
lua.safe_script("assert(t1 == t1)"); auto result1 = lua.safe_script("assert(t1 == t1)"
lua.safe_script("assert(t2 == t2)"); "assert(t2 == t2)"
lua.safe_script("assert(t3 == t3)"); "assert(t3 == t3)", sol::script_pass_on_error);
}()); REQUIRE(result1.valid());
REQUIRE_NOTHROW([&] { }
lua.safe_script("assert(t1 == t2)"); {
lua.safe_script("assert(not (t1 == t3))"); auto result1 = lua.safe_script("assert(t1 == t2)"
lua.safe_script("assert(not (t2 == t3))"); "assert(not (t1 == t3))"
}()); "assert(not (t2 == t3))", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
// Object should compare equal to themselves // Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient) // (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] { {
lua.safe_script("assert(u1 == u1)"); auto result1 = lua.safe_script("assert(u1 == u1)"
lua.safe_script("assert(u2 == u2)"); "assert(u2 == u2)"
lua.safe_script("assert(u3 == u3)"); "assert(u3 == u3)", sol::script_pass_on_error);
}()); REQUIRE(result1.valid());
REQUIRE_NOTHROW([&] { }
lua.safe_script("assert(not (u1 == u2))"); {
lua.safe_script("assert(u1 == u3)"); auto result1 = lua.safe_script("assert(not (u1 == u2))"
lua.safe_script("assert(not (u2 == u3))"); "assert(u1 == u3)"
}()); "assert(not (u2 == u3))", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
// Object should compare equal to themselves // Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient) // (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] { {
lua.safe_script("assert(v1 == v1)"); auto result1 = lua.safe_script("assert(v1 == v1)"
lua.safe_script("assert(v2 == v2)"); "assert(v2 == v2)"
lua.safe_script("assert(v3 == v3)"); "assert(v3 == v3)", sol::script_pass_on_error);
}()); REQUIRE(result1.valid());
REQUIRE_NOTHROW([&] { }
lua.safe_script("assert(not (v1 == v2))"); {
lua.safe_script("assert(v1 == v3)"); auto result1 = lua.safe_script("assert(not (v1 == v2))"
lua.safe_script("assert(not (v2 == v3))"); "assert(v1 == v3)"
}()); "assert(not (v2 == v3))", sol::script_pass_on_error);
REQUIRE(result1.valid());
}
} }
} }
@ -209,7 +224,8 @@ TEST_CASE("operators/call", "test call operator generation") {
SECTION("plain") { SECTION("plain") {
{ {
lua.set("obj", callable()); lua.set("obj", callable());
lua.safe_script("v = obj(2, 'bark woof')"); auto result1 = lua.safe_script("v = obj(2, 'bark woof')", sol::script_pass_on_error);
REQUIRE(result1.valid());
int v = lua["v"]; int v = lua["v"];
REQUIRE(v == 11); REQUIRE(v == 11);
} }
@ -217,8 +233,9 @@ TEST_CASE("operators/call", "test call operator generation") {
SECTION("regular") { SECTION("regular") {
lua.new_usertype<callable>("callable"); lua.new_usertype<callable>("callable");
{ {
lua.safe_script("obj = callable.new()"); auto result1 = lua.safe_script("obj = callable.new()\n"
lua.safe_script("v = obj(2, 'bark woof')"); "v = obj(2, 'bark woof')", sol::script_pass_on_error);
REQUIRE(result1.valid());
int v = lua["v"]; int v = lua["v"];
REQUIRE(v == 11); REQUIRE(v == 11);
} }
@ -283,7 +300,8 @@ TEST_CASE("operators/stringable", "test std::ostream stringability") {
SECTION("plain") { SECTION("plain") {
{ {
lua["obj"] = stringable(); lua["obj"] = stringable();
lua.safe_script("print(obj)"); auto result1 = lua.safe_script("print(obj)", sol::script_pass_on_error);
REQUIRE(result1.valid());
stringable& obj = lua["obj"]; stringable& obj = lua["obj"];
REQUIRE(stringable::last_print_ptr == &obj); REQUIRE(stringable::last_print_ptr == &obj);
} }
@ -291,8 +309,9 @@ TEST_CASE("operators/stringable", "test std::ostream stringability") {
SECTION("regular") { SECTION("regular") {
lua.new_usertype<stringable>("stringable"); lua.new_usertype<stringable>("stringable");
{ {
lua.safe_script("obj = stringable.new()"); auto result1 = lua.safe_script(R"(obj = stringable.new()
lua.safe_script("print(obj)"); print(obj) )", sol::script_pass_on_error);
REQUIRE(result1.valid());
stringable& obj = lua["obj"]; stringable& obj = lua["obj"];
REQUIRE(stringable::last_print_ptr == &obj); REQUIRE(stringable::last_print_ptr == &obj);
} }
@ -300,8 +319,9 @@ TEST_CASE("operators/stringable", "test std::ostream stringability") {
SECTION("simple") { SECTION("simple") {
lua.new_simple_usertype<stringable>("stringable"); lua.new_simple_usertype<stringable>("stringable");
{ {
lua.safe_script("obj = stringable.new()"); auto result1 = lua.safe_script(R"(obj = stringable.new()
lua.safe_script("print(obj)"); print(obj))", sol::script_pass_on_error);
REQUIRE(result1.valid());
stringable& obj = lua["obj"]; stringable& obj = lua["obj"];
REQUIRE(stringable::last_print_ptr == &obj); REQUIRE(stringable::last_print_ptr == &obj);
} }

View File

@ -21,10 +21,7 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>

View File

@ -21,15 +21,11 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
#include <iostream> #include <iostream>
#include "test_stack_guard.hpp"
TEST_CASE("proxy/function results", "make sure that function results return proper proxies and can be indexed nicely") { TEST_CASE("proxy/function results", "make sure that function results return proper proxies and can be indexed nicely") {
sol::state lua; sol::state lua;

View File

@ -21,10 +21,7 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>

View File

@ -23,14 +23,39 @@
#pragma once #pragma once
#ifndef SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#endif // SOL_CHECK_ARGUMENTS
#ifndef SOL_ENABLE_INTEROP
#define SOL_ENABLE_INTEROP 1
#endif // SOL_ENABLE_INTEROP
// Can't activate until all script/safe_script calls are vetted...
/*#ifndef SOL_DEFAULT_PASS_ON_ERROR
#define SOL_DEFAULT_PASS_ON_ERROR 1
#endif // SOL_DEFAULT_PASS_ON_ERROR
*/
#ifdef TEST_SINGLE
#include <sol_forward.hpp>
#endif // Single
#include <sol.hpp>
#include <catch.hpp>
#define CHECK_VALID ( x ) { auto r = x; REQUIRE(r.valid()); }
struct test_stack_guard { struct test_stack_guard {
lua_State* L; lua_State* L;
int& begintop; int& begintop;
int& endtop; int& endtop;
test_stack_guard(lua_State* L, int& begintop, int& endtop) test_stack_guard(lua_State* L, int& begintop, int& endtop)
: L(L), begintop(begintop), endtop(endtop) { : L(L), begintop(begintop), endtop(endtop) {
begintop = lua_gettop(L); begintop = lua_gettop(L);
} }
void check() {
REQUIRE(begintop == endtop);
}
~test_stack_guard() { ~test_stack_guard() {
endtop = lua_gettop(L); endtop = lua_gettop(L);
} }

View File

@ -21,10 +21,7 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
@ -35,8 +32,6 @@
#include <mutex> #include <mutex>
#include <atomic> #include <atomic>
#include "test_stack_guard.hpp"
template <typename Name, typename Data> template <typename Name, typename Data>
void write_file_attempt(Name&& filename, Data&& data) { void write_file_attempt(Name&& filename, Data&& data) {
bool success = false; bool success = false;

View File

@ -36,7 +36,10 @@ end
)"; )";
sol::state lua; sol::state lua;
lua.script(code); {
auto r = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(r.valid());
}
sol::function f = lua["f"]; sol::function f = lua["f"];
sol::reference r = lua["f"]; sol::reference r = lua["f"];
sol::function regf(lua, f); sol::function regf(lua, f);

View File

@ -21,10 +21,7 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
@ -43,6 +40,7 @@ namespace muh_namespace {
} // namespace muh_namespace } // namespace muh_namespace
// There isn't a single library roundtripping which codecvt works on. We'll do the nitty-gritty of it later... // There isn't a single library roundtripping which codecvt works on. We'll do the nitty-gritty of it later...
#if (defined(_MSC_VER) || defined(__clang__) || defined(__MINGW64__))
TEST_CASE("stack/strings", "test that strings can be roundtripped") { TEST_CASE("stack/strings", "test that strings can be roundtripped") {
sol::state lua; sol::state lua;
@ -124,6 +122,7 @@ TEST_CASE("stack/strings", "test that strings can be roundtripped") {
REQUIRE(wide_to_char32 == utf32str[0]); REQUIRE(wide_to_char32 == utf32str[0]);
#endif // codecvt support #endif // codecvt support
} }
#endif // MinGW fails with codecvt
TEST_CASE("detail/demangling", "test some basic demangling cases") { TEST_CASE("detail/demangling", "test some basic demangling cases") {
std::string teststr = sol::detail::short_demangle<test>(); std::string teststr = sol::detail::short_demangle<test>();

View File

@ -21,10 +21,7 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
@ -33,8 +30,6 @@
#include <numeric> #include <numeric>
#include <vector> #include <vector>
#include "test_stack_guard.hpp"
std::string free_function() { std::string free_function() {
INFO("free_function()"); INFO("free_function()");
return "test"; return "test";

View File

@ -21,10 +21,7 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
@ -441,10 +438,11 @@ TEST_CASE("usertype/self-referential usertype", "usertype classes must play nice
lua.new_usertype<self_test>("test", "g", &self_test::g, "f", &self_test::f); lua.new_usertype<self_test>("test", "g", &self_test::g, "f", &self_test::f);
lua.safe_script( auto result = lua.safe_script(
"local a = test.new()\n" "local a = test.new()\n"
"a:g(\"woof\")\n" "a:g(\"woof\")\n"
"a:f(a)\n"); "a:f(a)\n", sol::script_pass_on_error);
REQUIRE(result.valid());
} }
TEST_CASE("usertype/issue-number-twenty-five", "Using pointers and references from C++ classes in Lua") { TEST_CASE("usertype/issue-number-twenty-five", "Using pointers and references from C++ classes in Lua") {
@ -525,12 +523,18 @@ TEST_CASE("usertype/issue-number-thirty-five", "using value types created from l
sol::usertype<Vec> udata(ctor, "normalized", &Vec::normalized, "length", &Vec::length); sol::usertype<Vec> udata(ctor, "normalized", &Vec::normalized, "length", &Vec::length);
lua.set_usertype(udata); lua.set_usertype(udata);
REQUIRE_NOTHROW(lua.safe_script( {
auto result = lua.safe_script(
"v = Vec.new(1, 2, 3)\n" "v = Vec.new(1, 2, 3)\n"
"print(v:length())")); "print(v:length())");
REQUIRE_NOTHROW(lua.safe_script( REQUIRE(result.valid());
}
{
auto result = lua.safe_script(
"v = Vec.new(1, 2, 3)\n" "v = Vec.new(1, 2, 3)\n"
"print(v:normalized():length())")); "print(v:normalized():length())");
REQUIRE(result.valid());
}
} }
TEST_CASE("usertype/lua-stored-usertype", "ensure usertype values can be stored without keeping usertype object alive") { TEST_CASE("usertype/lua-stored-usertype", "ensure usertype values can be stored without keeping usertype object alive") {
@ -547,14 +551,20 @@ TEST_CASE("usertype/lua-stored-usertype", "ensure usertype values can be stored
// usertype dies, but still usable in lua! // usertype dies, but still usable in lua!
} }
REQUIRE_NOTHROW(lua.safe_script( {
"collectgarbage()\n" auto result = lua.safe_script(
"v = Vec.new(1, 2, 3)\n" "collectgarbage()\n"
"print(v:length())")); "v = Vec.new(1, 2, 3)\n"
"print(v:length())");
REQUIRE(result.valid());
}
REQUIRE_NOTHROW(lua.safe_script( {
"v = Vec.new(1, 2, 3)\n" auto result = lua.safe_script(
"print(v:normalized():length())")); "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") { TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as member variables for usertype") {
@ -669,14 +679,18 @@ TEST_CASE("regressions/one", "issue number 48") {
sol::state lua; sol::state lua;
lua.new_usertype<vars>("vars", lua.new_usertype<vars>("vars",
"boop", &vars::boop); "boop", &vars::boop);
REQUIRE_NOTHROW(lua.safe_script( auto code = "beep = vars.new()\n"
"beep = vars.new()\n" "beep.boop = 1";
"beep.boop = 1")); auto result1 = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(result1.valid());
// test for segfault // test for segfault
auto my_var = lua.get<vars>("beep"); auto my_var = lua.get<vars>("beep");
auto& my_var_ref = lua.get<vars>("beep");
auto* my_var_ptr = lua.get<vars*>("beep");
REQUIRE(my_var.boop == 1); REQUIRE(my_var.boop == 1);
auto* ptr = &my_var; REQUIRE(my_var_ref.boop == 1);
REQUIRE(ptr->boop == 1); REQUIRE(my_var_ptr->boop == 1);
REQUIRE(std::addressof(my_var_ref) == my_var_ptr);
} }
TEST_CASE("usertype/get-set-references", "properly get and set with std::ref semantics. Note that to get, we must not use Unqualified<T> on the type...") { TEST_CASE("usertype/get-set-references", "properly get and set with std::ref semantics. Note that to get, we must not use Unqualified<T> on the type...") {
@ -726,9 +740,10 @@ TEST_CASE("usertype/private-constructible", "Check to make sure special snowflak
REQUIRE(result.valid()); REQUIRE(result.valid());
} }
REQUIRE_NOTHROW(lua.safe_script( auto code1 = "local fresh_f = factory_test:new()\n"
"local fresh_f = factory_test:new()\n" "assert(fresh_f.a == true_a)\n";
"assert(fresh_f.a == true_a)\n")); auto result1 = lua.safe_script(code1, sol::script_pass_on_error);
REQUIRE(result1.valid());
} }
int expectednumsaved = numsaved + 1; int expectednumsaved = numsaved + 1;
int expectednumkilled = numkilled + 1; int expectednumkilled = numkilled + 1;

View File

@ -21,10 +21,7 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>

View File

@ -21,10 +21,7 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1 #include "test_sol.hpp"
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>

View File

@ -21,11 +21,9 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#define CATCH_CONFIG_MAIN 1 #define CATCH_CONFIG_MAIN 1
#include <sol.hpp> #include "test_sol.hpp"
#include <catch.hpp> #include <catch.hpp>
@ -35,8 +33,6 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "test_stack_guard.hpp"
bool func_opt_ret_bool(sol::optional<int> i) { bool func_opt_ret_bool(sol::optional<int> i) {
if (i) { if (i) {
INFO(i.value()); INFO(i.value());