mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
e8467334f6
Add unregister funcationality Make sure clearing is stack-size-safe.
402 lines
16 KiB
C++
402 lines
16 KiB
C++
// sol3
|
|
|
|
// The MIT License (MIT)
|
|
|
|
// Copyright (c) 2013-2019 Rapptz, ThePhD and contributors
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
// this software and associated documentation files (the "Software"), to deal in
|
|
// the Software without restriction, including without limitation the rights to
|
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
// the Software, and to permit persons to whom the Software is furnished to do so,
|
|
// subject to the following conditions:
|
|
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
// copies or substantial portions of the Software.
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
#include "sol_test.hpp"
|
|
|
|
#include <catch.hpp>
|
|
|
|
#include <vector>
|
|
#include <map>
|
|
#include <thread>
|
|
#include <mutex>
|
|
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
|
|
#include <string_view>
|
|
#include <variant>
|
|
#endif // C++17
|
|
|
|
struct int_entry {
|
|
int value;
|
|
|
|
int_entry() : value(0) {
|
|
}
|
|
|
|
int_entry(int v) : value(v) {
|
|
}
|
|
|
|
bool operator==(const int_entry& e) const {
|
|
return value == e.value;
|
|
}
|
|
};
|
|
|
|
std::mutex lua_value_construct_require_mutex;
|
|
|
|
void lua_value_construct_race() {
|
|
sol::state lua;
|
|
try {
|
|
lua.open_libraries();
|
|
lua["a"] = sol::lua_value(lua, 24);
|
|
int a = lua["a"];
|
|
{
|
|
std::lock_guard<std::mutex> lg(lua_value_construct_require_mutex);
|
|
REQUIRE(a == 24);
|
|
}
|
|
}
|
|
catch (const sol::error& e) {
|
|
std::lock_guard<std::mutex> lg(lua_value_construct_require_mutex);
|
|
INFO(e.what());
|
|
REQUIRE(false);
|
|
}
|
|
catch (...) {
|
|
std::lock_guard<std::mutex> lg(lua_value_construct_require_mutex);
|
|
REQUIRE(false);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("lua_value/nested", "make nested values can be put in lua_value properly") {
|
|
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
|
|
using mixed_table_entry = std::variant<int, int_entry, std::string>;
|
|
using nested_entry = std::variant<int, int_entry, std::string, std::vector<mixed_table_entry>>;
|
|
|
|
const std::vector<std::variant<int, int_entry>> mixed_table_truth = { 1, int_entry(2), 3, int_entry(4), 5 };
|
|
const std::vector<nested_entry> mixed_nested_table_truth = { 1, int_entry(2), 3, int_entry(4), std::vector<mixed_table_entry>{ 5, 6, int_entry(7), "8" } };
|
|
|
|
sol::state lua;
|
|
|
|
sol::lua_value lv_mixed_table(lua, sol::array_value{ 1, int_entry(2), 3, int_entry(4), 5 });
|
|
sol::lua_value lv_mixed_nested_table(lua, sol::array_value{ 1, int_entry(2), 3, int_entry(4), sol::array_value{ 5, 6, int_entry(7), "8" } });
|
|
|
|
REQUIRE(lv_mixed_table.is<sol::table>());
|
|
REQUIRE(lv_mixed_nested_table.is<sol::table>());
|
|
|
|
std::vector<std::variant<int, int_entry>> mixed_table_value_lv = lv_mixed_table.as<std::vector<std::variant<int, int_entry>>>();
|
|
std::vector<nested_entry> mixed_nested_table_value_lv = lv_mixed_nested_table.as<std::vector<nested_entry>>();
|
|
|
|
REQUIRE(mixed_table_truth == mixed_table_value_lv);
|
|
REQUIRE(mixed_nested_table_truth == mixed_nested_table_value_lv);
|
|
|
|
SECTION("type check (object)") {
|
|
sol::object obj_mixed_table(lv_mixed_table.value());
|
|
sol::object obj_mixed_nested_table(lv_mixed_nested_table.value());
|
|
|
|
REQUIRE(obj_mixed_table.is<sol::table>());
|
|
REQUIRE(obj_mixed_nested_table.is<sol::table>());
|
|
|
|
std::vector<std::variant<int, int_entry>> mixed_table_value = obj_mixed_table.as<std::vector<std::variant<int, int_entry>>>();
|
|
std::vector<nested_entry> mixed_nested_table_value = obj_mixed_nested_table.as<std::vector<nested_entry>>();
|
|
|
|
REQUIRE(mixed_table_truth == mixed_table_value);
|
|
REQUIRE(mixed_nested_table_truth == mixed_nested_table_value);
|
|
}
|
|
SECTION("pushing/popping") {
|
|
lua["obj_mixed_table"] = lv_mixed_table;
|
|
lua["obj_mixed_nested_table"] = lv_mixed_nested_table;
|
|
|
|
sol::lua_value obj_mixed_table = lua["obj_mixed_table"];
|
|
sol::lua_value obj_mixed_nested_table = lua["obj_mixed_nested_table"];
|
|
|
|
REQUIRE(obj_mixed_table.is<sol::table>());
|
|
REQUIRE(obj_mixed_nested_table.is<sol::table>());
|
|
|
|
std::vector<std::variant<int, int_entry>> mixed_table_value = obj_mixed_table.as<std::vector<std::variant<int, int_entry>>>();
|
|
std::vector<nested_entry> mixed_nested_table_value = obj_mixed_nested_table.as<std::vector<nested_entry>>();
|
|
|
|
REQUIRE(mixed_table_truth == mixed_table_value);
|
|
REQUIRE(mixed_nested_table_truth == mixed_nested_table_value);
|
|
}
|
|
SECTION("pushing/popping (object)") {
|
|
lua["obj_mixed_table"] = lv_mixed_table;
|
|
lua["obj_mixed_nested_table"] = lv_mixed_nested_table;
|
|
|
|
sol::object obj_mixed_table = lua["obj_mixed_table"];
|
|
sol::object obj_mixed_nested_table = lua["obj_mixed_nested_table"];
|
|
|
|
REQUIRE(obj_mixed_table.is<sol::table>());
|
|
REQUIRE(obj_mixed_nested_table.is<sol::table>());
|
|
|
|
std::vector<std::variant<int, int_entry>> mixed_table_value = obj_mixed_table.as<std::vector<std::variant<int, int_entry>>>();
|
|
std::vector<nested_entry> mixed_nested_table_value = obj_mixed_nested_table.as<std::vector<nested_entry>>();
|
|
|
|
REQUIRE(mixed_table_truth == mixed_table_value);
|
|
REQUIRE(mixed_nested_table_truth == mixed_nested_table_value);
|
|
}
|
|
#else
|
|
REQUIRE(true);
|
|
#endif // C++17
|
|
}
|
|
|
|
TEST_CASE("lua_value/nested key value", "make nested values (key value) can be put in lua_value properly") {
|
|
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
|
|
using mixed_table_entry = std::variant<int, int_entry, std::string>;
|
|
using nested_entry = std::variant<int, int_entry, std::string, std::vector<mixed_table_entry>>;
|
|
|
|
const std::vector<std::variant<int, int_entry>> mixed_table_truth = { 1, int_entry(2), 3, int_entry(4), 5 };
|
|
const std::vector<nested_entry> mixed_nested_table_truth = { 1, int_entry(2), 3, int_entry(4), std::vector<mixed_table_entry>{ 5, 6, int_entry(7), "8" } };
|
|
|
|
sol::state lua;
|
|
|
|
sol::lua_value lv_mixed_table(lua, sol::array_value{ 1, int_entry(2), 3, int_entry(4), 5 });
|
|
sol::lua_value lv_mixed_nested_table(lua, sol::array_value{ 1, int_entry(2), 3, int_entry(4), sol::array_value{ 5, 6, int_entry(7), "8" } });
|
|
|
|
REQUIRE(lv_mixed_table.is<sol::table>());
|
|
REQUIRE(lv_mixed_nested_table.is<sol::table>());
|
|
|
|
std::vector<std::variant<int, int_entry>> mixed_table_value_lv = lv_mixed_table.as<std::vector<std::variant<int, int_entry>>>();
|
|
std::vector<nested_entry> mixed_nested_table_value_lv = lv_mixed_nested_table.as<std::vector<nested_entry>>();
|
|
|
|
REQUIRE(mixed_table_truth == mixed_table_value_lv);
|
|
REQUIRE(mixed_nested_table_truth == mixed_nested_table_value_lv);
|
|
|
|
SECTION("type check (object)") {
|
|
sol::object obj_mixed_table(lv_mixed_table.value());
|
|
sol::object obj_mixed_nested_table(lv_mixed_nested_table.value());
|
|
|
|
REQUIRE(obj_mixed_table.is<sol::table>());
|
|
REQUIRE(obj_mixed_nested_table.is<sol::table>());
|
|
|
|
std::vector<std::variant<int, int_entry>> mixed_table_value = obj_mixed_table.as<std::vector<std::variant<int, int_entry>>>();
|
|
std::vector<nested_entry> mixed_nested_table_value = obj_mixed_nested_table.as<std::vector<nested_entry>>();
|
|
|
|
REQUIRE(mixed_table_truth == mixed_table_value);
|
|
REQUIRE(mixed_nested_table_truth == mixed_nested_table_value);
|
|
}
|
|
SECTION("pushing/popping") {
|
|
lua["obj_mixed_table"] = lv_mixed_table;
|
|
lua["obj_mixed_nested_table"] = lv_mixed_nested_table;
|
|
|
|
sol::lua_value obj_mixed_table = lua["obj_mixed_table"];
|
|
sol::lua_value obj_mixed_nested_table = lua["obj_mixed_nested_table"];
|
|
|
|
REQUIRE(obj_mixed_table.is<sol::table>());
|
|
REQUIRE(obj_mixed_nested_table.is<sol::table>());
|
|
|
|
std::vector<std::variant<int, int_entry>> mixed_table_value = obj_mixed_table.as<std::vector<std::variant<int, int_entry>>>();
|
|
std::vector<nested_entry> mixed_nested_table_value = obj_mixed_nested_table.as<std::vector<nested_entry>>();
|
|
|
|
REQUIRE(mixed_table_truth == mixed_table_value);
|
|
REQUIRE(mixed_nested_table_truth == mixed_nested_table_value);
|
|
}
|
|
SECTION("pushing/popping (object)") {
|
|
lua["obj_mixed_table"] = lv_mixed_table;
|
|
lua["obj_mixed_nested_table"] = lv_mixed_nested_table;
|
|
|
|
sol::object obj_mixed_table = lua["obj_mixed_table"];
|
|
sol::object obj_mixed_nested_table = lua["obj_mixed_nested_table"];
|
|
|
|
REQUIRE(obj_mixed_table.is<sol::table>());
|
|
REQUIRE(obj_mixed_nested_table.is<sol::table>());
|
|
|
|
std::vector<std::variant<int, int_entry>> mixed_table_value = obj_mixed_table.as<std::vector<std::variant<int, int_entry>>>();
|
|
std::vector<nested_entry> mixed_nested_table_value = obj_mixed_nested_table.as<std::vector<nested_entry>>();
|
|
|
|
REQUIRE(mixed_table_truth == mixed_table_value);
|
|
REQUIRE(mixed_nested_table_truth == mixed_nested_table_value);
|
|
}
|
|
#else
|
|
REQUIRE(true);
|
|
#endif // C++17
|
|
}
|
|
|
|
TEST_CASE("lua_value/basic types", "make sure we can stick values and nested values in a lua_value and retrieve them") {
|
|
sol::state lua;
|
|
|
|
const int_entry userdata_truth = int_entry(3);
|
|
const std::vector<int> int_table_truth = { 1, 2, 3, 4, 5 };
|
|
const std::map<int, int> int_map_truth = { {1, 2}, {3, 4}, {5, 6} };
|
|
|
|
sol::lua_value lv_int(lua, 1);
|
|
sol::lua_value lv_double(lua, 2.0);
|
|
sol::lua_value lv_string(lua, "heyo");
|
|
sol::lua_value lv_lstring(lua, L"hiyo");
|
|
sol::lua_value lv_bool(lua, true);
|
|
sol::lua_value lv_nil(lua, sol::lua_nil);
|
|
sol::lua_value lv_userdata(lua, int_entry(3));
|
|
sol::lua_value lv_int_table(lua, { 1, 2, 3, 4, 5 });
|
|
sol::lua_value lv_int_map(lua, { {1, 2}, {3, 4}, {5, 6} });
|
|
REQUIRE(lv_int.is<int>());
|
|
REQUIRE(lv_double.is<double>());
|
|
REQUIRE(lv_string.is<std::string>());
|
|
REQUIRE(lv_lstring.is<std::string>());
|
|
REQUIRE(lv_bool.is<bool>());
|
|
REQUIRE(lv_nil.is<sol::lua_nil_t>());
|
|
REQUIRE(lv_userdata.is<sol::userdata>());
|
|
REQUIRE(lv_userdata.is<int_entry>());
|
|
REQUIRE(lv_int_table.is<sol::table>());
|
|
REQUIRE(lv_int_map.is<sol::table>());
|
|
|
|
REQUIRE(lv_int.as<int>() == 1);
|
|
REQUIRE(lv_double.as<double>() == 2.0);
|
|
REQUIRE(lv_string.as<std::string>() == "heyo");
|
|
REQUIRE(lv_lstring.as<std::string>() == "hiyo");
|
|
REQUIRE(lv_lstring.as<std::wstring>() == L"hiyo");
|
|
REQUIRE(lv_bool.as<bool>());
|
|
REQUIRE(lv_nil.as<sol::lua_nil_t>() == sol::lua_nil);
|
|
REQUIRE(lv_userdata.as<int_entry>() == userdata_truth);
|
|
|
|
std::vector<int> int_table_value_lv = lv_int_table.as<std::vector<int>>();
|
|
REQUIRE(int_table_truth == int_table_value_lv);
|
|
std::map<int, int> int_map_value_lv = lv_int_map.as<std::map<int, int>>();
|
|
REQUIRE(int_map_truth == int_map_value_lv);
|
|
|
|
SECTION("type check (object)") {
|
|
sol::object obj_int(lv_int.value());
|
|
sol::object obj_double(lv_double.value());
|
|
sol::object obj_string(lv_string.value());
|
|
sol::object obj_lstring(lv_lstring.value());
|
|
sol::object obj_bool(lv_bool.value());
|
|
sol::object obj_nil(lv_nil.value());
|
|
sol::object obj_userdata(lv_userdata.value());
|
|
sol::object obj_int_table(lv_int_table.value());
|
|
sol::object obj_int_map(lv_int_map.value());
|
|
|
|
REQUIRE(obj_int.is<int>());
|
|
REQUIRE(obj_double.is<double>());
|
|
REQUIRE(obj_string.is<std::string>());
|
|
REQUIRE(obj_lstring.is<std::string>());
|
|
REQUIRE(obj_bool.is<bool>());
|
|
REQUIRE(obj_nil.is<sol::lua_nil_t>());
|
|
REQUIRE(obj_userdata.is<sol::userdata>());
|
|
REQUIRE(obj_userdata.is<int_entry>());
|
|
REQUIRE(obj_int_table.is<sol::table>());
|
|
REQUIRE(obj_int_map.is<sol::table>());
|
|
|
|
REQUIRE(obj_int.as<int>() == 1);
|
|
REQUIRE(obj_double.as<double>() == 2.0);
|
|
REQUIRE(obj_string.as<std::string>() == "heyo");
|
|
REQUIRE(obj_lstring.as<std::string>() == "hiyo");
|
|
REQUIRE(obj_lstring.as<std::wstring>() == L"hiyo");
|
|
REQUIRE(obj_bool.as<bool>());
|
|
REQUIRE(obj_userdata.as<int_entry>() == userdata_truth);
|
|
REQUIRE(obj_nil.as<sol::lua_nil_t>() == sol::lua_nil);
|
|
|
|
std::vector<int> int_table_value = obj_int_table.as<std::vector<int>>();
|
|
REQUIRE(int_table_truth == int_table_value);
|
|
std::map<int, int> int_map_value = obj_int_map.as<std::map<int, int>>();
|
|
REQUIRE(int_map_truth == int_map_value);
|
|
}
|
|
SECTION("push/popping") {
|
|
lua["obj_int"] = lv_int;
|
|
lua["obj_double"] = lv_double;
|
|
lua["obj_string"] = lv_string;
|
|
lua["obj_lstring"] = lv_lstring;
|
|
lua["obj_bool"] = lv_bool;
|
|
lua["obj_nil"] = lv_nil;
|
|
lua["obj_userdata"] = lv_userdata;
|
|
lua["obj_int_table"] = lv_int_table;
|
|
lua["obj_int_map"] = lv_int_map;
|
|
|
|
// these all actually invoke the constructor
|
|
// so do one .get<> explicitly to ensure it's
|
|
// working correctl for a few cases...
|
|
// but it's nice to make sure it's all there now
|
|
sol::lua_value obj_int = lua["obj_int"].get<sol::lua_value>();
|
|
sol::lua_value obj_double = lua["obj_double"].get<sol::lua_value>();
|
|
sol::lua_value obj_string = lua["obj_string"].get<sol::lua_value>();
|
|
sol::lua_value obj_lstring = lua["obj_lstring"].get<sol::lua_value>();
|
|
sol::lua_value obj_bool = lua["obj_bool"].get<sol::lua_value>();
|
|
sol::lua_value obj_nil = lua["obj_nil"];
|
|
sol::lua_value obj_userdata = lua["obj_userdata"];
|
|
sol::lua_value obj_int_table = lua["obj_int_table"];
|
|
sol::lua_value obj_int_map = lua["obj_int_map"];
|
|
|
|
REQUIRE(obj_int.is<int>());
|
|
REQUIRE(obj_double.is<double>());
|
|
REQUIRE(obj_string.is<std::string>());
|
|
REQUIRE(obj_lstring.is<std::string>());
|
|
REQUIRE(obj_bool.is<bool>());
|
|
REQUIRE(obj_nil.is<sol::lua_nil_t>());
|
|
REQUIRE(obj_int_table.is<sol::table>());
|
|
REQUIRE(obj_int_map.is<sol::table>());
|
|
|
|
REQUIRE(obj_int.as<int>() == 1);
|
|
REQUIRE(obj_double.as<double>() == 2.0);
|
|
REQUIRE(obj_string.as<std::string>() == "heyo");
|
|
REQUIRE(obj_lstring.as<std::string>() == "hiyo");
|
|
REQUIRE(obj_lstring.as<std::wstring>() == L"hiyo");
|
|
REQUIRE(obj_bool.as<bool>());
|
|
REQUIRE(obj_nil.as<sol::lua_nil_t>() == sol::lua_nil);
|
|
|
|
std::vector<int> int_table_value = obj_int_table.as<std::vector<int>>();
|
|
REQUIRE(int_table_truth == int_table_value);
|
|
std::map<int, int> int_map_value = obj_int_map.as<std::map<int, int>>();
|
|
REQUIRE(int_map_truth == int_map_value);
|
|
}
|
|
SECTION("push/popping (object)") {
|
|
lua["obj_int"] = lv_int;
|
|
lua["obj_double"] = lv_double;
|
|
lua["obj_string"] = lv_string;
|
|
lua["obj_lstring"] = lv_lstring;
|
|
lua["obj_bool"] = lv_bool;
|
|
lua["obj_nil"] = lv_nil;
|
|
lua["obj_userdata"] = lv_userdata;
|
|
lua["obj_int_table"] = lv_int_table;
|
|
lua["obj_int_map"] = lv_int_map;
|
|
|
|
sol::object obj_int = lua["obj_int"];
|
|
sol::object obj_double = lua["obj_double"];
|
|
sol::object obj_string = lua["obj_string"];
|
|
sol::object obj_lstring = lua["obj_lstring"];
|
|
sol::object obj_bool = lua["obj_bool"];
|
|
sol::object obj_nil = lua["obj_nil"];
|
|
sol::object obj_userdata = lua["obj_userdata"];
|
|
sol::object obj_int_table = lua["obj_int_table"];
|
|
sol::object obj_int_map = lua["obj_int_map"];
|
|
|
|
REQUIRE(obj_int.is<int>());
|
|
REQUIRE(obj_double.is<double>());
|
|
REQUIRE(obj_string.is<std::string>());
|
|
REQUIRE(obj_lstring.is<std::string>());
|
|
REQUIRE(obj_bool.is<bool>());
|
|
REQUIRE(obj_nil.is<sol::lua_nil_t>());
|
|
REQUIRE(obj_userdata.is<sol::userdata>());
|
|
REQUIRE(obj_userdata.is<int_entry>());
|
|
REQUIRE(obj_int_table.is<sol::table>());
|
|
|
|
REQUIRE(obj_int.as<int>() == 1);
|
|
REQUIRE(obj_double.as<double>() == 2.0);
|
|
REQUIRE(obj_string.as<std::string>() == "heyo");
|
|
REQUIRE(obj_lstring.as<std::string>() == "hiyo");
|
|
REQUIRE(obj_lstring.as<std::wstring>() == L"hiyo");
|
|
REQUIRE(obj_bool.as<bool>());
|
|
REQUIRE(obj_nil.as<sol::lua_nil_t>() == sol::lua_nil);
|
|
REQUIRE(obj_userdata.as<int_entry>() == userdata_truth);
|
|
|
|
std::vector<int> int_table_value = obj_int_table.as<std::vector<int>>();
|
|
REQUIRE(int_table_truth == int_table_value);
|
|
std::map<int, int> int_map_value = obj_int_map.as<std::map<int, int>>();
|
|
REQUIRE(int_map_truth == int_map_value);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("lua_value/threading", "test that thread_local in lua_value constructors do not race or clobber") {
|
|
REQUIRE_NOTHROW([]() {
|
|
std::thread thrds[24];
|
|
for (int i = 0; i < 24; i++) {
|
|
thrds[i] = std::thread(&lua_value_construct_race);
|
|
}
|
|
|
|
for (int i = 0; i < 24; i++) {
|
|
thrds[i].join();
|
|
}
|
|
}());
|
|
}
|