Update to sol2 v2.20.6
This commit is contained in:
+88
@@ -0,0 +1,88 @@
|
||||
# # # # sol2
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2013-2018 Rapptz, ThePhD, and contributors
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
# # # # sol2 tests
|
||||
|
||||
if (CMAKE_GENERATOR MATCHES "Visual Studio 14 2015")
|
||||
find_package(Catch 1.12.1 REQUIRED)
|
||||
else()
|
||||
find_package(Catch 2.1.2 REQUIRED)
|
||||
endif()
|
||||
|
||||
file(GLOB SOL2_TEST_SOURCES test*.cpp)
|
||||
source_group(test_sources FILES ${SOL2_TEST_SOURCES})
|
||||
|
||||
function(CREATE_TEST test_target_name test_name is_single)
|
||||
if (is_single)
|
||||
set(header_files ${SOL2_SINGLE_HEADER_SOURCES})
|
||||
else()
|
||||
set(header_files ${SOL2_HEADER_SOURCES})
|
||||
endif()
|
||||
|
||||
add_executable(${test_target_name} ${SOL2_TEST_SOURCES} ${header_files})
|
||||
set_target_properties(${test_target_name}
|
||||
PROPERTIES
|
||||
OUTPUT_NAME ${test_name})
|
||||
if (is_single)
|
||||
target_link_libraries(${test_target_name} sol2_single)
|
||||
target_compile_definitions(${test_target_name}
|
||||
PRIVATE TEST_SINGLE)
|
||||
else()
|
||||
target_link_libraries(${test_target_name} sol2)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (NOT CMAKE_COMPILER_ID MATCHES "Clang")
|
||||
target_compile_options(${test_target_name}
|
||||
PRIVATE /bigobj)
|
||||
endif()
|
||||
else()
|
||||
target_compile_options(${test_target_name}
|
||||
PRIVATE -Wno-noexcept-type -ftemplate-depth=1024 -pthread)
|
||||
|
||||
if (IS_X86)
|
||||
if(MINGW)
|
||||
set_target_properties(${test_target_name}
|
||||
PROPERTIES
|
||||
LINK_FLAGS -static-libstdc++)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
if (CI)
|
||||
target_compile_definitions(${test_target_name}
|
||||
PRIVATE SOL2_CI)
|
||||
endif()
|
||||
if (CMAKE_DL_LIBS)
|
||||
target_link_libraries(${test_target_name}
|
||||
${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
target_link_libraries(${test_target_name}
|
||||
Threads::Threads ${LUA_LIBRARIES} ${CATCH_LIBRARIES})
|
||||
|
||||
add_test(NAME ${test_name} COMMAND ${test_target_name})
|
||||
install(TARGETS ${test_target_name} RUNTIME DESTINATION bin)
|
||||
endfunction(CREATE_TEST)
|
||||
|
||||
CREATE_TEST(tests "tests" FALSE)
|
||||
if (TESTS_SINGLE AND SOL2_SINGLE_FOUND)
|
||||
CREATE_TEST(tests_single "tests.single" TRUE)
|
||||
endif()
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
#include <cstdlib>
|
||||
|
||||
struct pre_main {
|
||||
pre_main() {
|
||||
#ifdef SOL2_CI
|
||||
#ifdef _MSC_VER
|
||||
_set_abort_behavior(0, _WRITE_ABORT_MSG);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
} pm;
|
||||
+1335
File diff suppressed because it is too large
Load Diff
+1388
File diff suppressed because it is too large
Load Diff
+584
@@ -0,0 +1,584 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("coroutines/coroutine.yield", "ensure calling a coroutine works") {
|
||||
const auto& script = R"(counter = 20
|
||||
|
||||
function loop()
|
||||
while counter ~= 30
|
||||
do
|
||||
coroutine.yield(counter);
|
||||
counter = counter + 1;
|
||||
end
|
||||
return counter
|
||||
end
|
||||
)";
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
|
||||
auto result1 = lua.safe_script(script);
|
||||
REQUIRE(result1.valid());
|
||||
sol::coroutine cr = lua["loop"];
|
||||
|
||||
int counter;
|
||||
for (counter = 20; counter < 31 && cr; ++counter) {
|
||||
int value = cr();
|
||||
REQUIRE(counter == value);
|
||||
}
|
||||
counter -= 1;
|
||||
REQUIRE(counter == 30);
|
||||
}
|
||||
|
||||
TEST_CASE("coroutines/new thread coroutines", "ensure calling a coroutine works when the work is put on a different thread") {
|
||||
const auto& code = R"(counter = 20
|
||||
|
||||
function loop()
|
||||
while counter ~= 30
|
||||
do
|
||||
coroutine.yield(counter);
|
||||
counter = counter + 1;
|
||||
end
|
||||
return counter
|
||||
end
|
||||
)";
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
|
||||
auto result = lua.safe_script(code, sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
sol::thread runner = sol::thread::create(lua.lua_state());
|
||||
sol::state_view runnerstate = runner.state();
|
||||
sol::coroutine cr = runnerstate["loop"];
|
||||
|
||||
int counter;
|
||||
for (counter = 20; counter < 31 && cr; ++counter) {
|
||||
int value = cr();
|
||||
REQUIRE(counter == value);
|
||||
}
|
||||
counter -= 1;
|
||||
REQUIRE(counter == 30);
|
||||
}
|
||||
|
||||
TEST_CASE("coroutines/transfer", "test that things created inside of a coroutine can have their state transferred using lua_xmove constructors") {
|
||||
for (std::size_t tries = 0; tries < 200; ++tries) {
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
{
|
||||
sol::function f2;
|
||||
lua["f"] = [&lua, &f2](sol::object t) {
|
||||
f2 = sol::function(lua, t);
|
||||
};
|
||||
{
|
||||
auto code = R"(
|
||||
i = 0
|
||||
function INIT()
|
||||
co = coroutine.create(
|
||||
function()
|
||||
local g = function() i = i + 1 end
|
||||
f(g)
|
||||
g = nil
|
||||
collectgarbage()
|
||||
end
|
||||
)
|
||||
coroutine.resume(co)
|
||||
co = nil
|
||||
collectgarbage()
|
||||
end
|
||||
)";
|
||||
auto result = lua.safe_script(code, sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
sol::function f3;
|
||||
sol::function f1;
|
||||
|
||||
{
|
||||
auto code = "INIT()";
|
||||
auto result = lua.safe_script(code, sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
f2();
|
||||
auto updatecode = "return function() collectgarbage() end";
|
||||
auto pfr = lua.safe_script(updatecode);
|
||||
REQUIRE(pfr.valid());
|
||||
|
||||
sol::function update = pfr;
|
||||
update();
|
||||
f3 = f2;
|
||||
f3();
|
||||
update();
|
||||
f1 = f2;
|
||||
f1();
|
||||
update();
|
||||
int i = lua["i"];
|
||||
REQUIRE(i == 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("coroutines/explicit transfer", "check that the xmove constructors shift things around appropriately") {
|
||||
const std::string code = R"(
|
||||
-- main thread - L1
|
||||
-- co - L2
|
||||
-- co2 - L3
|
||||
|
||||
x = co_test.new("x")
|
||||
local co = coroutine.wrap(
|
||||
function()
|
||||
local t = co_test.new("t")
|
||||
local co2 = coroutine.wrap(
|
||||
function()
|
||||
local t2 = { "SOME_TABLE" }
|
||||
t:copy_store(t2) -- t2 = [L3], t.obj = [L2]
|
||||
end
|
||||
)
|
||||
|
||||
co2()
|
||||
co2 = nil
|
||||
|
||||
collectgarbage() -- t2 ref in t remains valid!
|
||||
|
||||
x:store(t:get()) -- t.obj = [L2], x.obj = [L1]
|
||||
end
|
||||
)
|
||||
|
||||
co()
|
||||
collectgarbage()
|
||||
collectgarbage()
|
||||
co = nil
|
||||
)";
|
||||
|
||||
struct co_test {
|
||||
std::string identifier;
|
||||
sol::reference obj;
|
||||
|
||||
co_test(sol::this_state L, std::string id)
|
||||
: identifier(id), obj(L, sol::lua_nil) {
|
||||
}
|
||||
|
||||
void store(sol::table ref) {
|
||||
// must be explicit
|
||||
obj = sol::reference(obj.lua_state(), ref);
|
||||
}
|
||||
|
||||
void copy_store(sol::table ref) {
|
||||
// must be explicit
|
||||
obj = sol::reference(obj.lua_state(), ref);
|
||||
}
|
||||
|
||||
sol::reference get() {
|
||||
return obj;
|
||||
}
|
||||
|
||||
~co_test() {
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::coroutine, sol::lib::base);
|
||||
|
||||
lua.new_usertype<co_test>("co_test",
|
||||
sol::constructors<co_test(sol::this_state, std::string)>(),
|
||||
"store", &co_test::store,
|
||||
"copy_store", &co_test::copy_store,
|
||||
"get", &co_test::get);
|
||||
|
||||
auto r = lua.safe_script(code, sol::script_pass_on_error);
|
||||
REQUIRE(r.valid());
|
||||
|
||||
co_test& ct = lua["x"];
|
||||
|
||||
lua_State* Lmain1 = lua.lua_state();
|
||||
lua_State* Lmain2 = sol::main_thread(lua);
|
||||
lua_State* Lmain3 = ct.get().lua_state();
|
||||
REQUIRE(Lmain1 == Lmain2);
|
||||
REQUIRE(Lmain1 == Lmain3);
|
||||
|
||||
sol::table t = ct.get();
|
||||
REQUIRE(t.size() == 1);
|
||||
std::string s = t[1];
|
||||
REQUIRE(s == "SOME_TABLE");
|
||||
}
|
||||
|
||||
TEST_CASE("coroutines/implicit transfer", "check that copy and move assignment constructors implicitly shift things around") {
|
||||
const std::string code = R"(
|
||||
-- main thread - L1
|
||||
-- co - L2
|
||||
-- co2 - L3
|
||||
|
||||
x = co_test.new("x")
|
||||
local co = coroutine.wrap(
|
||||
function()
|
||||
local t = co_test.new("t")
|
||||
local co2 = coroutine.wrap(
|
||||
function()
|
||||
local t2 = { "SOME_TABLE" }
|
||||
t:copy_store(t2) -- t2 = [L3], t.obj = [L2]
|
||||
end
|
||||
)
|
||||
|
||||
co2()
|
||||
co2 = nil
|
||||
|
||||
collectgarbage() -- t2 ref in t remains valid!
|
||||
|
||||
x:store(t:get()) -- t.obj = [L2], x.obj = [L1]
|
||||
end
|
||||
)
|
||||
|
||||
co()
|
||||
collectgarbage()
|
||||
collectgarbage()
|
||||
co = nil
|
||||
)";
|
||||
|
||||
struct co_test_implicit {
|
||||
std::string identifier;
|
||||
sol::reference obj;
|
||||
|
||||
co_test_implicit(sol::this_state L, std::string id)
|
||||
: identifier(id), obj(L, sol::lua_nil) {
|
||||
}
|
||||
|
||||
void store(sol::table ref) {
|
||||
// must be explicit
|
||||
obj = std::move(ref);
|
||||
}
|
||||
|
||||
void copy_store(sol::table ref) {
|
||||
// must be explicit
|
||||
obj = ref;
|
||||
}
|
||||
|
||||
sol::reference get() {
|
||||
return obj;
|
||||
}
|
||||
|
||||
~co_test_implicit() {
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::coroutine, sol::lib::base);
|
||||
|
||||
lua.new_usertype<co_test_implicit>("co_test",
|
||||
sol::constructors<co_test_implicit(sol::this_state, std::string)>(),
|
||||
"store", &co_test_implicit::store,
|
||||
"copy_store", &co_test_implicit::copy_store,
|
||||
"get", &co_test_implicit::get);
|
||||
|
||||
auto r = lua.safe_script(code, sol::script_pass_on_error);
|
||||
REQUIRE(r.valid());
|
||||
|
||||
co_test_implicit& ct = lua["x"];
|
||||
|
||||
lua_State* Lmain1 = lua.lua_state();
|
||||
lua_State* Lmain2 = sol::main_thread(lua);
|
||||
lua_State* Lmain3 = ct.get().lua_state();
|
||||
REQUIRE(Lmain1 == Lmain2);
|
||||
REQUIRE(Lmain1 == Lmain3);
|
||||
|
||||
sol::table t = ct.get();
|
||||
REQUIRE(t.size() == 1);
|
||||
std::string s = t[1];
|
||||
REQUIRE(s == "SOME_TABLE");
|
||||
}
|
||||
|
||||
TEST_CASE("coroutines/main transfer", "check that copy and move assignment constructors using main-forced types work") {
|
||||
const std::string code = R"(
|
||||
-- main thread - L1
|
||||
-- co - L2
|
||||
-- co2 - L3
|
||||
|
||||
x = co_test.new("x")
|
||||
local co = coroutine.wrap(
|
||||
function()
|
||||
local t = co_test.new("t")
|
||||
local co2 = coroutine.wrap(
|
||||
function()
|
||||
local t2 = { "SOME_TABLE" }
|
||||
t:copy_store(t2) -- t2 = [L3], t.obj = [L2]
|
||||
end
|
||||
)
|
||||
|
||||
co2()
|
||||
co2 = nil
|
||||
|
||||
collectgarbage() -- t2 ref in t remains valid!
|
||||
|
||||
x:store(t:get()) -- t.obj = [L2], x.obj = [L1]
|
||||
end
|
||||
)
|
||||
|
||||
co()
|
||||
co = nil
|
||||
collectgarbage()
|
||||
)";
|
||||
|
||||
struct co_test_implicit {
|
||||
std::string identifier;
|
||||
sol::main_reference obj;
|
||||
|
||||
co_test_implicit(sol::this_state L, std::string id)
|
||||
: identifier(id), obj(L, sol::lua_nil) {
|
||||
}
|
||||
|
||||
void store(sol::table ref) {
|
||||
// main_reference does the state shift implicitly
|
||||
obj = std::move(ref);
|
||||
lua_State* Lmain = sol::main_thread(ref.lua_state());
|
||||
REQUIRE(obj.lua_state() == Lmain);
|
||||
}
|
||||
|
||||
void copy_store(sol::table ref) {
|
||||
// main_reference does the state shift implicitly
|
||||
obj = ref;
|
||||
lua_State* Lmain = sol::main_thread(ref.lua_state());
|
||||
REQUIRE(obj.lua_state() == Lmain);
|
||||
}
|
||||
|
||||
sol::reference get() {
|
||||
return obj;
|
||||
}
|
||||
|
||||
~co_test_implicit() {
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::coroutine, sol::lib::base);
|
||||
|
||||
lua.new_usertype<co_test_implicit>("co_test",
|
||||
sol::constructors<co_test_implicit(sol::this_state, std::string)>(),
|
||||
"store", &co_test_implicit::store,
|
||||
"copy_store", &co_test_implicit::copy_store,
|
||||
"get", &co_test_implicit::get);
|
||||
|
||||
auto r = lua.safe_script(code, sol::script_pass_on_error);
|
||||
REQUIRE(r.valid());
|
||||
|
||||
co_test_implicit& ct = lua["x"];
|
||||
|
||||
lua_State* Lmain1 = lua.lua_state();
|
||||
lua_State* Lmain2 = sol::main_thread(lua);
|
||||
lua_State* Lmain3 = ct.get().lua_state();
|
||||
REQUIRE(Lmain1 == Lmain2);
|
||||
REQUIRE(Lmain1 == Lmain3);
|
||||
|
||||
sol::table t = ct.get();
|
||||
REQUIRE(t.size() == 1);
|
||||
std::string s = t[1];
|
||||
REQUIRE(s == "SOME_TABLE");
|
||||
}
|
||||
|
||||
TEST_CASE("coroutines/coroutine.create protection", "ensure that a thread picked up from coroutine.create does not throw off the lua stack entirely when called from C++") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
|
||||
|
||||
auto code = R"(
|
||||
function loop()
|
||||
local i = 0
|
||||
while true do
|
||||
print("pre-yield in loop")
|
||||
coroutine.yield(i)
|
||||
print("post-yield in loop")
|
||||
i = i+1
|
||||
end
|
||||
end
|
||||
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"];
|
||||
|
||||
auto test_resume = [&runner_thread]() {
|
||||
sol::state_view th_state = runner_thread.state();
|
||||
sol::coroutine cr = th_state["loop"];
|
||||
int r = cr();
|
||||
return r;
|
||||
};
|
||||
|
||||
lua.set_function("test_resume", std::ref(test_resume));
|
||||
|
||||
int v0 = test_resume();
|
||||
int v1 = test_resume();
|
||||
int v2, v3;
|
||||
{
|
||||
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(v1 == 1);
|
||||
REQUIRE(v2 == 2);
|
||||
REQUIRE(v3 == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("coroutines/stack-check", "check that resumed functions consume the entire execution stack") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::table, sol::lib::coroutine);
|
||||
{
|
||||
auto code = R"(
|
||||
unpack = unpack or table.unpack
|
||||
|
||||
function loop()
|
||||
local i = 0
|
||||
while true do
|
||||
print("pre-yield in loop")
|
||||
coroutine.yield(i)
|
||||
print("post-yield in loop")
|
||||
i = i+1
|
||||
end
|
||||
end
|
||||
loop_th = coroutine.create(loop)
|
||||
loop_res = function(...)
|
||||
returns = { coroutine.resume(loop_th, ...) }
|
||||
return unpack(returns, 2)
|
||||
end
|
||||
)";
|
||||
auto result = lua.safe_script(code, sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
|
||||
// Resume from lua via thread and coroutine
|
||||
sol::thread runner_thread = lua["loop_th"];
|
||||
sol::state_view runner_thread_state = runner_thread.state();
|
||||
auto test_resume = [&runner_thread, &runner_thread_state]() {
|
||||
sol::coroutine cr = runner_thread_state["loop"];
|
||||
sol::stack::push(runner_thread_state, 50);
|
||||
sol::stack::push(runner_thread_state, 25);
|
||||
int r = cr();
|
||||
return r;
|
||||
};
|
||||
lua.set_function("test_resume", std::ref(test_resume));
|
||||
|
||||
// Resume via getting a sol::function from the state
|
||||
sol::function test_resume_lua = lua["loop_res"];
|
||||
|
||||
// Resume via passing a sol::function object
|
||||
auto test_resume_func = [](sol::function f) {
|
||||
int r = f();
|
||||
return r;
|
||||
};
|
||||
lua.set_function("test_resume_func", std::ref(test_resume_func));
|
||||
|
||||
int v0 = test_resume();
|
||||
int s0 = runner_thread_state.stack_top();
|
||||
int v1 = test_resume();
|
||||
int s1 = runner_thread_state.stack_top();
|
||||
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 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 v4 = test_resume_lua();
|
||||
int s4 = runner_thread_state.stack_top();
|
||||
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();
|
||||
REQUIRE(v0 == 0);
|
||||
REQUIRE(v1 == 1);
|
||||
REQUIRE(v2 == 2);
|
||||
REQUIRE(v3 == 3);
|
||||
REQUIRE(v4 == 4);
|
||||
REQUIRE(v5 == 5);
|
||||
|
||||
REQUIRE(s0 == 0);
|
||||
REQUIRE(s1 == 0);
|
||||
REQUIRE(s2 == 0);
|
||||
REQUIRE(s3 == 0);
|
||||
REQUIRE(s4 == 0);
|
||||
REQUIRE(s5 == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("coroutines/yielding", "test that a sol2 bound function can yield when marked yieldable") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
|
||||
|
||||
int i = 0;
|
||||
auto func = [&i]() {
|
||||
++i;
|
||||
return i;
|
||||
};
|
||||
|
||||
struct h {
|
||||
int x = 500;
|
||||
int func() const {
|
||||
return x;
|
||||
}
|
||||
} hobj{};
|
||||
|
||||
lua["f"] = sol::yielding(func);
|
||||
lua["g"] = sol::yielding([]() { return 300; });
|
||||
lua["h"] = sol::yielding(&h::func);
|
||||
lua["hobj"] = &hobj;
|
||||
|
||||
sol::string_view code = R"(
|
||||
co1 = coroutine.create(function () return f() end)
|
||||
success1, value1 = coroutine.resume(co1)
|
||||
co2 = coroutine.create(function () return g() end)
|
||||
success2, value2 = coroutine.resume(co2)
|
||||
co3 = coroutine.create(function()
|
||||
h(hobj)
|
||||
end)
|
||||
success3, value3 = coroutine.resume(co3)
|
||||
)";
|
||||
|
||||
auto result = lua.safe_script(code);
|
||||
REQUIRE(result.valid());
|
||||
|
||||
bool success1 = lua["success1"];
|
||||
int value1 = lua["value1"];
|
||||
REQUIRE(success1);
|
||||
REQUIRE(value1 == 1);
|
||||
|
||||
bool success2 = lua["success2"];
|
||||
int value2 = lua["value2"];
|
||||
REQUIRE(success2);
|
||||
REQUIRE(value2 == 300);
|
||||
|
||||
bool success3 = lua["success3"];
|
||||
int value3 = lua["value3"];
|
||||
REQUIRE(success3);
|
||||
REQUIRE(value3 == 500);
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
struct two_things {
|
||||
int a;
|
||||
bool b;
|
||||
};
|
||||
|
||||
struct number_shim {
|
||||
double num = 0;
|
||||
};
|
||||
|
||||
namespace sol {
|
||||
|
||||
// First, the expected size
|
||||
// Specialization of a struct
|
||||
template <>
|
||||
struct lua_size<two_things> : std::integral_constant<int, 2> {};
|
||||
|
||||
// Then, the expected type
|
||||
template <>
|
||||
struct lua_type_of<two_things> : std::integral_constant<sol::type, sol::type::poly> {};
|
||||
|
||||
// do note specialize size for this because it is our type
|
||||
template <>
|
||||
struct lua_type_of<number_shim> : std::integral_constant<sol::type, sol::type::poly> {};
|
||||
|
||||
// Now, specialize various stack structures
|
||||
namespace stack {
|
||||
|
||||
template <>
|
||||
struct checker<two_things> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
// Check first and second second index for being the proper types
|
||||
bool success = stack::check<int>(L, index, handler)
|
||||
&& stack::check<bool>(L, index + 1, handler);
|
||||
tracking.use(2);
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct getter<two_things> {
|
||||
static two_things get(lua_State* L, int index, record& tracking) {
|
||||
// Get the first element
|
||||
int a = stack::get<int>(L, index);
|
||||
// Get the second element,
|
||||
// in the +1 position from the first
|
||||
bool b = stack::get<bool>(L, index + 1);
|
||||
// we use 2 slots, each of the previous takes 1
|
||||
tracking.use(2);
|
||||
return two_things{ a, b };
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pusher<two_things> {
|
||||
static int push(lua_State* L, const two_things& things) {
|
||||
int amount = stack::push(L, things.a);
|
||||
amount += stack::push(L, things.b);
|
||||
// Return 2 things
|
||||
return amount;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct checker<number_shim> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
// check_usertype is a backdoor for directly checking sol2 usertypes
|
||||
if (!check_usertype<number_shim>(L, index) && !stack::check<double>(L, index)) {
|
||||
handler(L, index, type_of(L, index), type::userdata, "expected a number_shim or a number");
|
||||
return false;
|
||||
}
|
||||
tracking.use(1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct getter<number_shim> {
|
||||
static number_shim get(lua_State* L, int index, record& tracking) {
|
||||
if (check_usertype<number_shim>(L, index)) {
|
||||
number_shim& ns = get_usertype<number_shim>(L, index, tracking);
|
||||
return ns;
|
||||
}
|
||||
number_shim ns{};
|
||||
ns.num = stack::get<double>(L, index, tracking);
|
||||
return ns;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace stack
|
||||
} // namespace sol
|
||||
|
||||
TEST_CASE("customization/split struct", "using the newly documented customization points to handle different kinds of classes") {
|
||||
sol::state lua;
|
||||
|
||||
// Create a pass-through style of function
|
||||
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) {
|
||||
return std::make_tuple(a + c, b, d + 2.5);
|
||||
});
|
||||
|
||||
// get the function out of Lua
|
||||
sol::function f = lua["f"];
|
||||
sol::function g = lua["g"];
|
||||
|
||||
two_things thingsf = f(two_things{ 24, true }, 1);
|
||||
two_things thingsg;
|
||||
double d;
|
||||
sol::tie(thingsg, d) = g(two_things{ 25, false }, 2, 34.0);
|
||||
REQUIRE(thingsf.a == 25);
|
||||
REQUIRE(thingsf.b);
|
||||
|
||||
REQUIRE(thingsg.a == 27);
|
||||
REQUIRE_FALSE(thingsg.b);
|
||||
REQUIRE(d == 36.5);
|
||||
}
|
||||
|
||||
TEST_CASE("customization/get_ check_usertype", "using the newly documented customization points to handle different kinds of classes") {
|
||||
sol::state lua;
|
||||
|
||||
// Create a pass-through style of function
|
||||
auto result1 = lua.safe_script("function f ( a ) return a end");
|
||||
REQUIRE(result1.valid());
|
||||
lua.set_function("g", [](double a) {
|
||||
number_shim ns;
|
||||
ns.num = a;
|
||||
return ns;
|
||||
});
|
||||
|
||||
auto result2 = lua.safe_script("vf = f(25) vg = g(35)", sol::script_pass_on_error);
|
||||
REQUIRE(result2.valid());
|
||||
|
||||
number_shim thingsf = lua["vf"];
|
||||
number_shim thingsg = lua["vg"];
|
||||
|
||||
REQUIRE(thingsf.num == 25);
|
||||
REQUIRE(thingsg.num == 35);
|
||||
}
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE("environments/get", "Envronments can be taken out of things like Lua functions properly") {
|
||||
sol::state lua;
|
||||
sol::stack_guard luasg(lua);
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
auto result1 = lua.safe_script("f = function() return test end", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
sol::function f = lua["f"];
|
||||
|
||||
sol::environment env_f(lua, sol::create);
|
||||
env_f["test"] = 31;
|
||||
sol::set_environment(env_f, f);
|
||||
|
||||
int result = f();
|
||||
REQUIRE(result == 31);
|
||||
|
||||
auto result2 = lua.safe_script("g = function() test = 5 end", sol::script_pass_on_error);
|
||||
REQUIRE(result2.valid());
|
||||
sol::function g = lua["g"];
|
||||
sol::environment env_g(lua, sol::create);
|
||||
env_g.set_on(g);
|
||||
|
||||
g();
|
||||
|
||||
int test = env_g["test"];
|
||||
REQUIRE(test == 5);
|
||||
|
||||
sol::object global_test = lua["test"];
|
||||
REQUIRE(!global_test.valid());
|
||||
|
||||
auto result3 = lua.safe_script("h = function() end", sol::script_pass_on_error);
|
||||
REQUIRE(result3.valid());
|
||||
|
||||
lua.set_function("check_f_env",
|
||||
[&lua, &env_f](sol::object target) {
|
||||
sol::stack_guard sg(lua);
|
||||
sol::environment target_env(sol::env_key, target);
|
||||
int test_env_f = env_f["test"];
|
||||
int test_target_env = target_env["test"];
|
||||
REQUIRE(test_env_f == test_target_env);
|
||||
REQUIRE(test_env_f == 31);
|
||||
REQUIRE(env_f == target_env);
|
||||
});
|
||||
lua.set_function("check_g_env",
|
||||
[&lua, &env_g](sol::function target) {
|
||||
sol::stack_guard sg(lua);
|
||||
sol::environment target_env = sol::get_environment(target);
|
||||
int test_env_g = env_g["test"];
|
||||
int test_target_env = target_env["test"];
|
||||
REQUIRE(test_env_g == test_target_env);
|
||||
REQUIRE(test_env_g == 5);
|
||||
REQUIRE(env_g == target_env);
|
||||
});
|
||||
lua.set_function("check_h_env",
|
||||
[&lua](sol::function target) {
|
||||
sol::stack_guard sg(lua);
|
||||
sol::environment target_env = sol::get_environment(target);
|
||||
});
|
||||
|
||||
auto checkf = lua.safe_script("check_f_env(f)");
|
||||
REQUIRE(checkf.valid());
|
||||
auto checkg = lua.safe_script("check_g_env(g)");
|
||||
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") {
|
||||
|
||||
sol::state lua;
|
||||
lua["b"] = 2142;
|
||||
|
||||
SECTION("no fallback") {
|
||||
sol::environment plain_env(lua, sol::create);
|
||||
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_global_a = lua["a"];
|
||||
sol::optional<int> maybe_env_b = plain_env["b"];
|
||||
sol::optional<int> maybe_global_b = lua["b"];
|
||||
|
||||
REQUIRE(maybe_env_a != sol::nullopt);
|
||||
REQUIRE(maybe_env_a.value() == 24);
|
||||
REQUIRE(maybe_env_b == sol::nullopt);
|
||||
|
||||
REQUIRE(maybe_global_a == sol::nullopt);
|
||||
REQUIRE(maybe_global_b != sol::nullopt);
|
||||
REQUIRE(maybe_global_b.value() == 2142);
|
||||
}
|
||||
SECTION("fallback") {
|
||||
sol::environment env_with_fallback(lua, sol::create, lua.globals());
|
||||
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_global_a = lua["a"];
|
||||
sol::optional<int> maybe_env_b = env_with_fallback["b"];
|
||||
sol::optional<int> maybe_global_b = lua["b"];
|
||||
|
||||
REQUIRE(maybe_env_a != sol::nullopt);
|
||||
REQUIRE(maybe_env_a.value() == 56);
|
||||
REQUIRE(maybe_env_b != sol::nullopt);
|
||||
REQUIRE(maybe_env_b.value() == 2142);
|
||||
|
||||
REQUIRE(maybe_global_a == sol::nullopt);
|
||||
REQUIRE(maybe_global_b != sol::nullopt);
|
||||
REQUIRE(maybe_global_b.value() == 2142);
|
||||
}
|
||||
SECTION("from name") {
|
||||
sol::environment env_with_fallback(lua, sol::create, lua.globals());
|
||||
lua["env"] = env_with_fallback;
|
||||
sol::environment env = lua["env"];
|
||||
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_global_a = lua["a"];
|
||||
sol::optional<int> maybe_env_b = env["b"];
|
||||
sol::optional<int> maybe_global_b = lua["b"];
|
||||
|
||||
REQUIRE(maybe_env_a != sol::nullopt);
|
||||
REQUIRE(maybe_env_a.value() == 56);
|
||||
REQUIRE(maybe_env_b != sol::nullopt);
|
||||
REQUIRE(maybe_env_b.value() == 2142);
|
||||
|
||||
REQUIRE(maybe_global_a == sol::nullopt);
|
||||
REQUIRE(maybe_global_b != sol::nullopt);
|
||||
REQUIRE(maybe_global_b.value() == 2142);
|
||||
}
|
||||
SECTION("name with newtable") {
|
||||
lua["blank_env"] = sol::new_table(0, 1);
|
||||
sol::environment plain_env = lua["blank_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_global_a = lua["a"];
|
||||
sol::optional<int> maybe_env_b = plain_env["b"];
|
||||
sol::optional<int> maybe_global_b = lua["b"];
|
||||
|
||||
REQUIRE(maybe_env_a != sol::nullopt);
|
||||
REQUIRE(maybe_env_a.value() == 24);
|
||||
REQUIRE(maybe_env_b == sol::nullopt);
|
||||
|
||||
REQUIRE(maybe_global_a == sol::nullopt);
|
||||
REQUIRE(maybe_global_b != sol::nullopt);
|
||||
REQUIRE(maybe_global_b.value() == 2142);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("environments/functions", "see if environments on functions are working properly") {
|
||||
|
||||
SECTION("basic") {
|
||||
sol::state lua;
|
||||
|
||||
auto result1 = lua.safe_script("a = function() return 5 end", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
|
||||
sol::function a = lua["a"];
|
||||
|
||||
int result0 = a();
|
||||
REQUIRE(result0 == 5);
|
||||
|
||||
sol::environment env(lua, sol::create);
|
||||
sol::set_environment(env, a);
|
||||
|
||||
int value = a();
|
||||
REQUIRE(value == 5);
|
||||
}
|
||||
SECTION("return environment value") {
|
||||
sol::state lua;
|
||||
|
||||
auto result1 = lua.safe_script("a = function() return test end", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
|
||||
sol::function a = lua["a"];
|
||||
sol::environment env(lua, sol::create);
|
||||
env["test"] = 5;
|
||||
env.set_on(a);
|
||||
|
||||
// the function returns the value from the environment table
|
||||
int result = a();
|
||||
REQUIRE(result == 5);
|
||||
}
|
||||
|
||||
SECTION("set environment value") {
|
||||
sol::state lua;
|
||||
auto result1 = lua.safe_script("a = function() test = 5 end", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
|
||||
sol::function a = lua["a"];
|
||||
sol::environment env(lua, sol::create);
|
||||
sol::set_environment(env, a);
|
||||
|
||||
a();
|
||||
|
||||
// the value can be retrieved from the env table
|
||||
int result = env["test"];
|
||||
REQUIRE(result == 5);
|
||||
|
||||
// the global environment is not polluted
|
||||
auto gtest = lua["test"];
|
||||
REQUIRE(!gtest.valid());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("environments/this_environment", "test various situations of pulling out an environment") {
|
||||
static std::string code = "return (f(10))";
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua["f"] = [](sol::this_environment te, int x, sol::this_state ts) {
|
||||
if (te) {
|
||||
sol::environment& env = te;
|
||||
return x + static_cast<int>(env["x"]);
|
||||
}
|
||||
sol::state_view lua = ts;
|
||||
return x + static_cast<int>(lua["x"]);
|
||||
};
|
||||
|
||||
sol::environment e(lua, sol::create, lua.globals());
|
||||
lua["x"] = 5;
|
||||
e["x"] = 20;
|
||||
SECTION("from Lua script") {
|
||||
auto result1 = lua.safe_script(code, e, sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
int value = result1;
|
||||
REQUIRE(value == 30);
|
||||
}
|
||||
SECTION("from C++") {
|
||||
sol::function f = lua["f"];
|
||||
e.set_on(f);
|
||||
int value = f(10);
|
||||
REQUIRE(value == 30);
|
||||
}
|
||||
SECTION("from C++, with no env") {
|
||||
sol::function f = lua["f"];
|
||||
int value = f(10);
|
||||
REQUIRE(value == 15);
|
||||
}
|
||||
}
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
TEST_CASE("filters/self", "ensure we return a direct reference to the lua userdata rather than creating a new one") {
|
||||
struct vec2 {
|
||||
float x = 20.f;
|
||||
float y = 20.f;
|
||||
|
||||
vec2& normalize() {
|
||||
float len2 = x * x + y * y;
|
||||
if (len2 != 0) {
|
||||
float len = sqrtf(len2);
|
||||
x /= len;
|
||||
y /= len;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~vec2() {
|
||||
x = std::numeric_limits<float>::lowest();
|
||||
y = std::numeric_limits<float>::lowest();
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<vec2>("vec2",
|
||||
"x", &vec2::x,
|
||||
"y", &vec2::y,
|
||||
"normalize", sol::filters(&vec2::normalize, sol::returns_self()));
|
||||
|
||||
auto result1 = lua.safe_script(R"(
|
||||
v1 = vec2.new()
|
||||
print('v1:', v1.x, v1.y)
|
||||
v2 = v1:normalize()
|
||||
print('v1:', v1.x, v1.y)
|
||||
print('v2:', v2.x, v2.y)
|
||||
print(v1, v2)
|
||||
assert(rawequal(v1, v2))
|
||||
v1 = nil
|
||||
collectgarbage()
|
||||
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") {
|
||||
struct dep;
|
||||
struct gc_test;
|
||||
static std::vector<dep*> deps_destroyed;
|
||||
static std::vector<gc_test*> gc_tests_destroyed;
|
||||
|
||||
struct dep {
|
||||
int value = 20;
|
||||
~dep() {
|
||||
std::cout << "\t"
|
||||
<< "[C++] ~dep" << std::endl;
|
||||
value = std::numeric_limits<int>::max();
|
||||
deps_destroyed.push_back(this);
|
||||
}
|
||||
};
|
||||
|
||||
struct gc_test {
|
||||
|
||||
dep d;
|
||||
|
||||
~gc_test() {
|
||||
std::cout << "\t"
|
||||
<< "[C++] ~gc_test" << std::endl;
|
||||
gc_tests_destroyed.push_back(this);
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<dep>("dep",
|
||||
"value", &dep::value,
|
||||
sol::meta_function::to_string, [](dep& d) {
|
||||
return "{ " + std::to_string(d.value) + " }";
|
||||
});
|
||||
lua.new_usertype<gc_test>("gc_test",
|
||||
"d", sol::filters(&gc_test::d, sol::self_dependency()),
|
||||
sol::meta_function::to_string, [](gc_test& g) {
|
||||
return "{ d: { " + std::to_string(g.d.value) + " } }";
|
||||
});
|
||||
|
||||
auto result1 = lua.safe_script(R"(
|
||||
g = gc_test.new()
|
||||
d = g.d
|
||||
print("new gc_test, d = g.d")
|
||||
print("", g)
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
REQUIRE(deps_destroyed.empty());
|
||||
REQUIRE(gc_tests_destroyed.empty());
|
||||
|
||||
gc_test* g = lua["g"];
|
||||
dep* d = lua["d"];
|
||||
|
||||
auto result2 = lua.safe_script(R"(
|
||||
print("g = nil, collectgarbage")
|
||||
g = nil
|
||||
collectgarbage()
|
||||
print("", d)
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE(result2.valid());
|
||||
|
||||
REQUIRE(deps_destroyed.empty());
|
||||
REQUIRE(gc_tests_destroyed.empty());
|
||||
|
||||
auto result3 = lua.safe_script(R"(
|
||||
print("d = nil, collectgarbage")
|
||||
d = nil
|
||||
collectgarbage()
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE(result3.valid());
|
||||
|
||||
REQUIRE(deps_destroyed.size() == 1);
|
||||
REQUIRE(gc_tests_destroyed.size() == 1);
|
||||
REQUIRE(deps_destroyed[0] == d);
|
||||
REQUIRE(gc_tests_destroyed[0] == g);
|
||||
}
|
||||
|
||||
TEST_CASE("filters/stack_dependencies", "ensure we can take dependencies even to arguments pushed on the stack") {
|
||||
struct holder;
|
||||
struct depends_on_reference;
|
||||
struct composition_related;
|
||||
static std::vector<composition_related*> composition_relateds_destroyed;
|
||||
static std::vector<holder*> holders_destroyed;
|
||||
static std::vector<depends_on_reference*> depends_on_references_destroyed;
|
||||
|
||||
struct composition_related {
|
||||
std::string text = "bark";
|
||||
|
||||
~composition_related() {
|
||||
std::cout << "[C++] ~composition_related" << std::endl;
|
||||
text = "";
|
||||
composition_relateds_destroyed.push_back(this);
|
||||
}
|
||||
};
|
||||
|
||||
struct holder {
|
||||
int value = 20;
|
||||
~holder() {
|
||||
std::cout << "[C++] ~holder" << std::endl;
|
||||
value = std::numeric_limits<int>::max();
|
||||
holders_destroyed.push_back(this);
|
||||
}
|
||||
};
|
||||
|
||||
struct depends_on_reference {
|
||||
|
||||
std::reference_wrapper<holder> href;
|
||||
composition_related comp;
|
||||
|
||||
depends_on_reference(holder& h)
|
||||
: href(h) {
|
||||
}
|
||||
|
||||
~depends_on_reference() {
|
||||
std::cout << "[C++] ~depends_on_reference" << std::endl;
|
||||
depends_on_references_destroyed.push_back(this);
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<holder>("holder",
|
||||
"value", &holder::value);
|
||||
lua.new_usertype<depends_on_reference>("depends_on_reference",
|
||||
"new", sol::filters(sol::constructors<depends_on_reference(holder&)>(), sol::stack_dependencies(-1, 1)),
|
||||
"comp", &depends_on_reference::comp);
|
||||
|
||||
auto result1 = lua.safe_script(R"(
|
||||
h = holder.new()
|
||||
dor = depends_on_reference.new(h)
|
||||
c = dor.comp
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
REQUIRE(composition_relateds_destroyed.empty());
|
||||
REQUIRE(holders_destroyed.empty());
|
||||
REQUIRE(depends_on_references_destroyed.empty());
|
||||
|
||||
holder* h = lua["h"];
|
||||
composition_related* c = lua["c"];
|
||||
depends_on_reference* dor = lua["dor"];
|
||||
|
||||
REQUIRE(h == &dor->href.get());
|
||||
REQUIRE(c == &dor->comp);
|
||||
|
||||
auto result2 = lua.safe_script(R"(
|
||||
h = nil
|
||||
collectgarbage()
|
||||
)");
|
||||
REQUIRE(result2.valid());
|
||||
REQUIRE(composition_relateds_destroyed.empty());
|
||||
REQUIRE(holders_destroyed.empty());
|
||||
REQUIRE(depends_on_references_destroyed.empty());
|
||||
|
||||
auto result3 = lua.safe_script(R"(
|
||||
c = nil
|
||||
collectgarbage()
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE(result3.valid());
|
||||
|
||||
REQUIRE(composition_relateds_destroyed.empty());
|
||||
REQUIRE(holders_destroyed.empty());
|
||||
REQUIRE(depends_on_references_destroyed.empty());
|
||||
|
||||
auto result4 = lua.safe_script(R"(
|
||||
dor = nil
|
||||
collectgarbage()
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE(result4.valid());
|
||||
|
||||
REQUIRE(composition_relateds_destroyed.size() == 1);
|
||||
REQUIRE(holders_destroyed.size() == 1);
|
||||
REQUIRE(depends_on_references_destroyed.size() == 1);
|
||||
REQUIRE(composition_relateds_destroyed[0] == c);
|
||||
REQUIRE(holders_destroyed[0] == h);
|
||||
REQUIRE(depends_on_references_destroyed[0] == dor);
|
||||
}
|
||||
|
||||
int always_return_24(lua_State* L, int) {
|
||||
return sol::stack::push(L, 24);
|
||||
}
|
||||
|
||||
TEST_CASE("filters/custom", "ensure we can return dependencies on multiple things in the stack") {
|
||||
|
||||
sol::state lua;
|
||||
lua.set_function("f", sol::filters([]() { return std::string("hi there"); }, always_return_24));
|
||||
|
||||
int value = lua["f"]();
|
||||
REQUIRE(value == 24);
|
||||
}
|
||||
+1642
File diff suppressed because it is too large
Load Diff
Vendored
+709
@@ -0,0 +1,709 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
TEST_CASE("gc/destructors", "test if destructors are fired properly through gc of unbound usertypes") {
|
||||
struct test;
|
||||
static std::vector<test*> tests_destroyed;
|
||||
struct test {
|
||||
int v = 10;
|
||||
~test() {
|
||||
tests_destroyed.push_back(this);
|
||||
}
|
||||
};
|
||||
test t;
|
||||
test* pt = nullptr;
|
||||
{
|
||||
sol::state lua;
|
||||
|
||||
lua["t"] = test{};
|
||||
pt = lua["t"];
|
||||
}
|
||||
|
||||
REQUIRE(tests_destroyed.size() == 2);
|
||||
REQUIRE(tests_destroyed.back() == pt);
|
||||
|
||||
{
|
||||
sol::state lua;
|
||||
|
||||
lua["t"] = &t;
|
||||
pt = lua["t"];
|
||||
}
|
||||
|
||||
REQUIRE(tests_destroyed.size() == 2);
|
||||
REQUIRE(&t == pt);
|
||||
|
||||
{
|
||||
sol::state lua;
|
||||
|
||||
lua["t"] = std::ref(t);
|
||||
pt = lua["t"];
|
||||
}
|
||||
|
||||
REQUIRE(tests_destroyed.size() == 2);
|
||||
REQUIRE(&t == pt);
|
||||
|
||||
{
|
||||
sol::state lua;
|
||||
|
||||
lua["t"] = t;
|
||||
pt = lua["t"];
|
||||
}
|
||||
|
||||
REQUIRE(tests_destroyed.size() == 3);
|
||||
REQUIRE(&t != pt);
|
||||
REQUIRE(nullptr != pt);
|
||||
}
|
||||
|
||||
TEST_CASE("gc/virtual destructors", "ensure types with virtual destructions behave just fine") {
|
||||
class B;
|
||||
class A;
|
||||
static std::vector<B*> bs;
|
||||
static std::vector<A*> as;
|
||||
|
||||
class A {
|
||||
public:
|
||||
virtual ~A() {
|
||||
as.push_back(this);
|
||||
std::cout << "~A" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
class B : public A {
|
||||
public:
|
||||
virtual ~B() {
|
||||
bs.push_back(this);
|
||||
std::cout << "~B" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<A>("A");
|
||||
lua.new_usertype<B>("B", sol::base_classes, sol::bases<A>());
|
||||
|
||||
B b1;
|
||||
lua["b1"] = b1; // breaks here
|
||||
}
|
||||
|
||||
REQUIRE(as.size() == 2);
|
||||
REQUIRE(bs.size() == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("gc/function argument storage", "ensure functions take references on their types, not ownership, when specified") {
|
||||
class gc_entity;
|
||||
static std::vector<gc_entity*> entities;
|
||||
|
||||
class gc_entity {
|
||||
public:
|
||||
~gc_entity() {
|
||||
entities.push_back(this);
|
||||
}
|
||||
};
|
||||
SECTION("plain") {
|
||||
entities.clear();
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
sol::function f = lua.safe_script(R"(
|
||||
return function(e)
|
||||
end
|
||||
)");
|
||||
gc_entity* target = nullptr;
|
||||
{
|
||||
gc_entity e;
|
||||
target = &e;
|
||||
{
|
||||
f(e);
|
||||
lua.collect_garbage();
|
||||
}
|
||||
{
|
||||
f(&e);
|
||||
lua.collect_garbage();
|
||||
}
|
||||
{
|
||||
f(std::ref(e));
|
||||
lua.collect_garbage();
|
||||
}
|
||||
}
|
||||
REQUIRE(entities.size() == 1);
|
||||
REQUIRE(entities.back() == target);
|
||||
}
|
||||
SECTION("regular") {
|
||||
entities.clear();
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
lua.new_usertype<gc_entity>("entity");
|
||||
sol::function f = lua.safe_script(R"(
|
||||
return function(e)
|
||||
end
|
||||
)");
|
||||
gc_entity* target = nullptr;
|
||||
{
|
||||
gc_entity e;
|
||||
target = &e;
|
||||
{
|
||||
f(e); // same with std::ref(e)!
|
||||
lua.collect_garbage(); // destroys e for some reason
|
||||
}
|
||||
{
|
||||
f(&e); // same with std::ref(e)!
|
||||
lua.collect_garbage(); // destroys e for some reason
|
||||
}
|
||||
{
|
||||
f(std::ref(e)); // same with std::ref(e)!
|
||||
lua.collect_garbage(); // destroys e for some reason
|
||||
}
|
||||
}
|
||||
REQUIRE(entities.size() == 1);
|
||||
REQUIRE(entities.back() == target);
|
||||
}
|
||||
SECTION("simple") {
|
||||
entities.clear();
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
lua.new_simple_usertype<gc_entity>("entity");
|
||||
sol::function f = lua.safe_script(R"(
|
||||
return function(e)
|
||||
end
|
||||
)");
|
||||
gc_entity* target = nullptr;
|
||||
{
|
||||
gc_entity e;
|
||||
target = &e;
|
||||
{
|
||||
f(e); // same with std::ref(e)!
|
||||
lua.collect_garbage(); // destroys e for some reason
|
||||
}
|
||||
{
|
||||
f(&e); // same with std::ref(e)!
|
||||
lua.collect_garbage(); // destroys e for some reason
|
||||
}
|
||||
{
|
||||
f(std::ref(e)); // same with std::ref(e)!
|
||||
lua.collect_garbage(); // destroys e for some reason
|
||||
}
|
||||
}
|
||||
REQUIRE(entities.size() == 1);
|
||||
REQUIRE(entities.back() == target);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("gc/function storage", "show that proper copies / destruction happens for function storage (or not)") {
|
||||
static int created = 0;
|
||||
static int destroyed = 0;
|
||||
static void* last_call = nullptr;
|
||||
static void* static_call = reinterpret_cast<void*>(0x01);
|
||||
typedef void (*fptr)();
|
||||
struct x {
|
||||
x() {
|
||||
++created;
|
||||
}
|
||||
x(const x&) {
|
||||
++created;
|
||||
}
|
||||
x(x&&) {
|
||||
++created;
|
||||
}
|
||||
x& operator=(const x&) {
|
||||
return *this;
|
||||
}
|
||||
x& operator=(x&&) {
|
||||
return *this;
|
||||
}
|
||||
void func() {
|
||||
last_call = static_cast<void*>(this);
|
||||
};
|
||||
~x() {
|
||||
++destroyed;
|
||||
}
|
||||
};
|
||||
struct y {
|
||||
y() {
|
||||
++created;
|
||||
}
|
||||
y(const x&) {
|
||||
++created;
|
||||
}
|
||||
y(x&&) {
|
||||
++created;
|
||||
}
|
||||
y& operator=(const x&) {
|
||||
return *this;
|
||||
}
|
||||
y& operator=(x&&) {
|
||||
return *this;
|
||||
}
|
||||
static void func() {
|
||||
last_call = static_call;
|
||||
};
|
||||
void operator()() {
|
||||
func();
|
||||
}
|
||||
operator fptr() {
|
||||
return func;
|
||||
}
|
||||
~y() {
|
||||
++destroyed;
|
||||
}
|
||||
};
|
||||
|
||||
// stateful functors/member functions should always copy unless specified
|
||||
{
|
||||
created = 0;
|
||||
destroyed = 0;
|
||||
last_call = nullptr;
|
||||
{
|
||||
sol::state lua;
|
||||
x x1;
|
||||
lua.set_function("x1copy", &x::func, x1);
|
||||
auto result1 = lua.safe_script("x1copy()", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
REQUIRE(created == 2);
|
||||
REQUIRE(destroyed == 0);
|
||||
REQUIRE_FALSE(last_call == &x1);
|
||||
|
||||
lua.set_function("x1ref", &x::func, std::ref(x1));
|
||||
auto result2 = lua.safe_script("x1ref()", sol::script_pass_on_error);
|
||||
REQUIRE(result2.valid());
|
||||
REQUIRE(created == 2);
|
||||
REQUIRE(destroyed == 0);
|
||||
REQUIRE(last_call == &x1);
|
||||
}
|
||||
REQUIRE(created == 2);
|
||||
REQUIRE(destroyed == 2);
|
||||
}
|
||||
|
||||
// things convertible to a static function should _never_ be forced to make copies
|
||||
// therefore, pass through untouched
|
||||
{
|
||||
created = 0;
|
||||
destroyed = 0;
|
||||
last_call = nullptr;
|
||||
{
|
||||
sol::state lua;
|
||||
y y1;
|
||||
lua.set_function("y1copy", y1);
|
||||
auto result1 = lua.safe_script("y1copy()", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
REQUIRE(created == 1);
|
||||
REQUIRE(destroyed == 0);
|
||||
REQUIRE(last_call == static_call);
|
||||
|
||||
last_call = nullptr;
|
||||
lua.set_function("y1ref", std::ref(y1));
|
||||
auto result2 = lua.safe_script("y1ref()", sol::script_pass_on_error);
|
||||
REQUIRE(result2.valid());
|
||||
REQUIRE(created == 1);
|
||||
REQUIRE(destroyed == 0);
|
||||
REQUIRE(last_call == static_call);
|
||||
}
|
||||
REQUIRE(created == 1);
|
||||
REQUIRE(destroyed == 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("gc/same type closures", "make sure destructions are per-object, not per-type, by destroying one type multiple times") {
|
||||
static std::set<void*> last_my_closures;
|
||||
static bool checking_closures = false;
|
||||
static bool check_failed = false;
|
||||
|
||||
struct my_closure {
|
||||
int& n;
|
||||
|
||||
my_closure(int& n)
|
||||
: n(n) {
|
||||
}
|
||||
~my_closure() noexcept(false) {
|
||||
if (!checking_closures)
|
||||
return;
|
||||
void* addr = static_cast<void*>(this);
|
||||
auto f = last_my_closures.find(addr);
|
||||
if (f != last_my_closures.cend()) {
|
||||
check_failed = true;
|
||||
}
|
||||
last_my_closures.insert(f, addr);
|
||||
}
|
||||
|
||||
int operator()() {
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
int n = 250;
|
||||
my_closure a(n);
|
||||
my_closure b(n);
|
||||
{
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function("f", a);
|
||||
lua.set_function("g", b);
|
||||
checking_closures = true;
|
||||
}
|
||||
REQUIRE_FALSE(check_failed);
|
||||
REQUIRE(last_my_closures.size() == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("gc/usertypes", "show that proper copies / destruction happens for usertypes") {
|
||||
static int created = 0;
|
||||
static int destroyed = 0;
|
||||
struct x {
|
||||
x() {
|
||||
++created;
|
||||
}
|
||||
x(const x&) {
|
||||
++created;
|
||||
}
|
||||
x(x&&) {
|
||||
++created;
|
||||
}
|
||||
x& operator=(const x&) {
|
||||
return *this;
|
||||
}
|
||||
x& operator=(x&&) {
|
||||
return *this;
|
||||
}
|
||||
~x() {
|
||||
++destroyed;
|
||||
}
|
||||
};
|
||||
SECTION("plain") {
|
||||
created = 0;
|
||||
destroyed = 0;
|
||||
{
|
||||
sol::state lua;
|
||||
x x1;
|
||||
x x2;
|
||||
lua.set("x1copy", x1, "x2copy", x2, "x1ref", std::ref(x1));
|
||||
x& x1copyref = lua["x1copy"];
|
||||
x& x2copyref = lua["x2copy"];
|
||||
x& x1ref = lua["x1ref"];
|
||||
REQUIRE(created == 4);
|
||||
REQUIRE(destroyed == 0);
|
||||
REQUIRE(std::addressof(x1) == std::addressof(x1ref));
|
||||
REQUIRE(std::addressof(x1copyref) != std::addressof(x1));
|
||||
REQUIRE(std::addressof(x2copyref) != std::addressof(x2));
|
||||
}
|
||||
REQUIRE(created == 4);
|
||||
REQUIRE(destroyed == 4);
|
||||
}
|
||||
SECTION("regular") {
|
||||
created = 0;
|
||||
destroyed = 0;
|
||||
{
|
||||
sol::state lua;
|
||||
lua.new_usertype<x>("x");
|
||||
x x1;
|
||||
x x2;
|
||||
lua.set("x1copy", x1, "x2copy", x2, "x1ref", std::ref(x1));
|
||||
x& x1copyref = lua["x1copy"];
|
||||
x& x2copyref = lua["x2copy"];
|
||||
x& x1ref = lua["x1ref"];
|
||||
REQUIRE(created == 4);
|
||||
REQUIRE(destroyed == 0);
|
||||
REQUIRE(std::addressof(x1) == std::addressof(x1ref));
|
||||
REQUIRE(std::addressof(x1copyref) != std::addressof(x1));
|
||||
REQUIRE(std::addressof(x2copyref) != std::addressof(x2));
|
||||
}
|
||||
REQUIRE(created == 4);
|
||||
REQUIRE(destroyed == 4);
|
||||
}
|
||||
SECTION("simple") {
|
||||
created = 0;
|
||||
destroyed = 0;
|
||||
{
|
||||
sol::state lua;
|
||||
lua.new_simple_usertype<x>("x");
|
||||
x x1;
|
||||
x x2;
|
||||
lua.set("x1copy", x1, "x2copy", x2, "x1ref", std::ref(x1));
|
||||
x& x1copyref = lua["x1copy"];
|
||||
x& x2copyref = lua["x2copy"];
|
||||
x& x1ref = lua["x1ref"];
|
||||
REQUIRE(created == 4);
|
||||
REQUIRE(destroyed == 0);
|
||||
REQUIRE(std::addressof(x1) == std::addressof(x1ref));
|
||||
REQUIRE(std::addressof(x1copyref) != std::addressof(x1));
|
||||
REQUIRE(std::addressof(x2copyref) != std::addressof(x2));
|
||||
}
|
||||
REQUIRE(created == 4);
|
||||
REQUIRE(destroyed == 4);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("gc/double-deletion tests", "make sure usertypes are properly destructed and don't double-delete memory or segfault") {
|
||||
class crash_class {
|
||||
public:
|
||||
crash_class() {
|
||||
}
|
||||
~crash_class() {
|
||||
a = 10;
|
||||
}
|
||||
|
||||
private:
|
||||
int a;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<crash_class>("CrashClass",
|
||||
sol::call_constructor, sol::constructors<sol::types<>>());
|
||||
|
||||
auto result1 = lua.safe_script(R"(
|
||||
function testCrash()
|
||||
local x = CrashClass()
|
||||
end
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
lua["testCrash"]();
|
||||
}
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<crash_class>("CrashClass",
|
||||
sol::call_constructor, sol::constructors<sol::types<>>());
|
||||
|
||||
auto result1 = lua.safe_script(R"(
|
||||
function testCrash()
|
||||
local x = CrashClass()
|
||||
end
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
lua["testCrash"]();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("gc/shared_ptr regression", "metatables should not screw over unique usertype metatables") {
|
||||
static int created = 0;
|
||||
static int destroyed = 0;
|
||||
struct test {
|
||||
test() {
|
||||
++created;
|
||||
}
|
||||
|
||||
~test() {
|
||||
++destroyed;
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("regular") {
|
||||
created = 0;
|
||||
destroyed = 0;
|
||||
{
|
||||
std::list<std::shared_ptr<test>> tests;
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
lua.new_usertype<test>("test",
|
||||
"create", [&]() -> std::shared_ptr<test> {
|
||||
tests.push_back(std::make_shared<test>());
|
||||
return tests.back();
|
||||
});
|
||||
REQUIRE(created == 0);
|
||||
REQUIRE(destroyed == 0);
|
||||
auto result1 = lua.safe_script("x = test.create()", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
REQUIRE(created == 1);
|
||||
REQUIRE(destroyed == 0);
|
||||
REQUIRE_FALSE(tests.empty());
|
||||
std::shared_ptr<test>& x = lua["x"];
|
||||
std::size_t xuse = x.use_count();
|
||||
std::size_t tuse = tests.back().use_count();
|
||||
REQUIRE(xuse == tuse);
|
||||
}
|
||||
REQUIRE(created == 1);
|
||||
REQUIRE(destroyed == 1);
|
||||
}
|
||||
SECTION("simple") {
|
||||
created = 0;
|
||||
destroyed = 0;
|
||||
{
|
||||
std::list<std::shared_ptr<test>> tests;
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
lua.new_simple_usertype<test>("test",
|
||||
"create", [&]() -> std::shared_ptr<test> {
|
||||
tests.push_back(std::make_shared<test>());
|
||||
return tests.back();
|
||||
});
|
||||
REQUIRE(created == 0);
|
||||
REQUIRE(destroyed == 0);
|
||||
auto result1 = lua.safe_script("x = test.create()", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
REQUIRE(created == 1);
|
||||
REQUIRE(destroyed == 0);
|
||||
REQUIRE_FALSE(tests.empty());
|
||||
std::shared_ptr<test>& x = lua["x"];
|
||||
std::size_t xuse = x.use_count();
|
||||
std::size_t tuse = tests.back().use_count();
|
||||
REQUIRE(xuse == tuse);
|
||||
}
|
||||
REQUIRE(created == 1);
|
||||
REQUIRE(destroyed == 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("gc/double deleter guards", "usertype metatables internally must not rely on C++ state") {
|
||||
SECTION("regular") {
|
||||
struct c_a {
|
||||
int xv;
|
||||
};
|
||||
struct c_b {
|
||||
int yv;
|
||||
};
|
||||
auto routine = []() {
|
||||
sol::state lua;
|
||||
lua.new_usertype<c_a>("c_a", "x", &c_a::xv);
|
||||
lua.new_usertype<c_b>("c_b", "y", &c_b::yv);
|
||||
lua = sol::state();
|
||||
lua.new_usertype<c_a>("c_a", "x", &c_a::xv);
|
||||
lua.new_usertype<c_b>("c_b", "y", &c_b::yv);
|
||||
lua = sol::state();
|
||||
};
|
||||
REQUIRE_NOTHROW(routine());
|
||||
}
|
||||
SECTION("simple") {
|
||||
struct sc_a {
|
||||
int xv;
|
||||
};
|
||||
struct sc_b {
|
||||
int yv;
|
||||
};
|
||||
auto routine = []() {
|
||||
sol::state lua;
|
||||
lua.new_simple_usertype<sc_a>("c_a", "x", &sc_a::xv);
|
||||
lua.new_simple_usertype<sc_b>("c_b", "y", &sc_b::yv);
|
||||
lua = sol::state();
|
||||
lua.new_simple_usertype<sc_a>("c_a", "x", &sc_a::xv);
|
||||
lua.new_simple_usertype<sc_b>("c_b", "y", &sc_b::yv);
|
||||
lua = sol::state();
|
||||
};
|
||||
REQUIRE_NOTHROW(routine());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("gc/alignment", "test that allocation is always on aligned boundaries, no matter the wrapper / type") {
|
||||
struct test {
|
||||
std::function<void()> callback = []() { std::cout << "Hello world!" << std::endl; };
|
||||
|
||||
void check_alignment() {
|
||||
std::uintptr_t p = reinterpret_cast<std::uintptr_t>(this);
|
||||
std::uintptr_t offset = p % std::alignment_of<test>::value;
|
||||
REQUIRE(offset == 0);
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.new_usertype<test>("test",
|
||||
"callback", &test::callback);
|
||||
|
||||
test obj{};
|
||||
lua["obj"] = &obj;
|
||||
INFO("obj");
|
||||
{
|
||||
auto r = lua.safe_script("obj.callback()", sol::script_pass_on_error);
|
||||
REQUIRE(r.valid());
|
||||
}
|
||||
{
|
||||
// Do not check for stack-created object
|
||||
//test& lobj = lua["obj"];
|
||||
//lobj.check_alignment();
|
||||
}
|
||||
|
||||
lua["obj0"] = std::ref(obj);
|
||||
INFO("obj0");
|
||||
{
|
||||
auto r = lua.safe_script("obj0.callback()", sol::script_pass_on_error);
|
||||
REQUIRE(r.valid());
|
||||
}
|
||||
{
|
||||
// Do not check for stack-created object
|
||||
//test& lobj = lua["obj0"];
|
||||
//lobj.check_alignment();
|
||||
}
|
||||
|
||||
lua["obj1"] = obj;
|
||||
INFO("obj1");
|
||||
{
|
||||
auto r = lua.safe_script("obj1.callback()", sol::script_pass_on_error);
|
||||
REQUIRE(r.valid());
|
||||
}
|
||||
{
|
||||
test& lobj = lua["obj1"];
|
||||
lobj.check_alignment();
|
||||
}
|
||||
|
||||
lua["obj2"] = test{};
|
||||
INFO("obj2");
|
||||
{
|
||||
auto r = lua.safe_script("obj2.callback()", sol::script_pass_on_error);
|
||||
REQUIRE(r.valid());
|
||||
}
|
||||
{
|
||||
test& lobj = lua["obj2"];
|
||||
lobj.check_alignment();
|
||||
}
|
||||
|
||||
lua["obj3"] = std::make_unique<test>();
|
||||
INFO("obj3");
|
||||
{
|
||||
auto r = lua.safe_script("obj3.callback()", sol::script_pass_on_error);
|
||||
REQUIRE(r.valid());
|
||||
}
|
||||
{
|
||||
test& lobj = lua["obj3"];
|
||||
lobj.check_alignment();
|
||||
}
|
||||
|
||||
lua["obj4"] = std::make_shared<test>();
|
||||
INFO("obj4");
|
||||
{
|
||||
auto r = lua.safe_script("obj4.callback()", sol::script_pass_on_error);
|
||||
REQUIRE(r.valid());
|
||||
}
|
||||
{
|
||||
test& lobj = lua["obj4"];
|
||||
lobj.check_alignment();
|
||||
}
|
||||
}
|
||||
+287
@@ -0,0 +1,287 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE("inheritance/basic", "test that metatables are properly inherited") {
|
||||
struct A {
|
||||
int a = 5;
|
||||
};
|
||||
|
||||
struct B {
|
||||
int b() {
|
||||
return 10;
|
||||
}
|
||||
};
|
||||
|
||||
struct C : B, A {
|
||||
double c = 2.4;
|
||||
};
|
||||
|
||||
struct D : C {
|
||||
bool d() const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.new_usertype<A>("A",
|
||||
"a", &A::a);
|
||||
lua.new_usertype<B>("B",
|
||||
"b", &B::b);
|
||||
lua.new_usertype<C>("C",
|
||||
"c", &C::c,
|
||||
sol::base_classes, sol::bases<B, A>());
|
||||
lua.new_usertype<D>("D",
|
||||
"d", &D::d,
|
||||
sol::base_classes, sol::bases<C, B, A>());
|
||||
|
||||
auto result1 = lua.safe_script("obj = D.new()", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
auto result2 = lua.safe_script("d = obj:d()", sol::script_pass_on_error);
|
||||
REQUIRE(result2.valid());
|
||||
bool d = lua["d"];
|
||||
auto result3 = lua.safe_script("c = obj.c", sol::script_pass_on_error);
|
||||
REQUIRE(result3.valid());
|
||||
double c = lua["c"];
|
||||
auto result4 = lua.safe_script("b = obj:b()", sol::script_pass_on_error);
|
||||
REQUIRE(result4.valid());
|
||||
int b = lua["b"];
|
||||
auto result5 = lua.safe_script("a = obj.a", sol::script_pass_on_error);
|
||||
REQUIRE(result5.valid());
|
||||
int a = lua["a"];
|
||||
|
||||
REQUIRE(d);
|
||||
REQUIRE(c == 2.4);
|
||||
REQUIRE(b == 10);
|
||||
REQUIRE(a == 5);
|
||||
}
|
||||
|
||||
TEST_CASE("inheritance/multi base", "test that multiple bases all work and overloading for constructors works with them") {
|
||||
class TestClass00 {
|
||||
public:
|
||||
int Thing() const {
|
||||
return 123;
|
||||
}
|
||||
};
|
||||
|
||||
class TestClass01 : public TestClass00 {
|
||||
public:
|
||||
TestClass01()
|
||||
: a(1) {
|
||||
}
|
||||
TestClass01(const TestClass00& other)
|
||||
: a(other.Thing()) {
|
||||
}
|
||||
|
||||
int a;
|
||||
};
|
||||
|
||||
class TestClass02 : public TestClass01 {
|
||||
public:
|
||||
TestClass02()
|
||||
: b(2) {
|
||||
}
|
||||
TestClass02(const TestClass01& other)
|
||||
: b(other.a) {
|
||||
}
|
||||
TestClass02(const TestClass00& other)
|
||||
: b(other.Thing()) {
|
||||
}
|
||||
|
||||
int b;
|
||||
};
|
||||
|
||||
class TestClass03 : public TestClass02 {
|
||||
public:
|
||||
TestClass03()
|
||||
: c(2) {
|
||||
}
|
||||
TestClass03(const TestClass02& other)
|
||||
: c(other.b) {
|
||||
}
|
||||
TestClass03(const TestClass01& other)
|
||||
: c(other.a) {
|
||||
}
|
||||
TestClass03(const TestClass00& other)
|
||||
: c(other.Thing()) {
|
||||
}
|
||||
|
||||
int c;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
|
||||
sol::usertype<TestClass00> s_TestUsertype00(
|
||||
sol::call_constructor, sol::constructors<sol::types<>>(),
|
||||
"Thing", &TestClass00::Thing);
|
||||
|
||||
lua.set_usertype("TestClass00", s_TestUsertype00);
|
||||
|
||||
sol::usertype<TestClass01> s_TestUsertype01(
|
||||
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass00&>>(),
|
||||
sol::base_classes, sol::bases<TestClass00>(),
|
||||
"a", &TestClass01::a);
|
||||
|
||||
lua.set_usertype("TestClass01", s_TestUsertype01);
|
||||
|
||||
sol::usertype<TestClass02> s_TestUsertype02(
|
||||
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
|
||||
sol::base_classes, sol::bases<TestClass01, TestClass00>(),
|
||||
"b", &TestClass02::b);
|
||||
|
||||
lua.set_usertype("TestClass02", s_TestUsertype02);
|
||||
|
||||
sol::usertype<TestClass03> s_TestUsertype03(
|
||||
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass02&>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
|
||||
sol::base_classes, sol::bases<TestClass02, TestClass01, TestClass00>(),
|
||||
"c", &TestClass03::c);
|
||||
|
||||
lua.set_usertype("TestClass03", s_TestUsertype03);
|
||||
|
||||
auto result1 = lua.safe_script(R"(
|
||||
tc0 = TestClass00()
|
||||
tc2 = TestClass02(tc0)
|
||||
tc1 = TestClass01()
|
||||
tc3 = TestClass03(tc1)
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
|
||||
TestClass00& tc0 = lua["tc0"];
|
||||
TestClass01& tc1 = lua["tc1"];
|
||||
TestClass02& tc2 = lua["tc2"];
|
||||
TestClass03& tc3 = lua["tc3"];
|
||||
REQUIRE(tc0.Thing() == 123);
|
||||
REQUIRE(tc1.a == 1);
|
||||
REQUIRE(tc2.a == 1);
|
||||
REQUIRE(tc2.b == 123);
|
||||
REQUIRE(tc3.a == 1);
|
||||
REQUIRE(tc3.b == 2);
|
||||
REQUIRE(tc3.c == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("inheritance/simple multi base", "test that multiple bases all work and overloading for constructors works with them") {
|
||||
class TestClass00 {
|
||||
public:
|
||||
int Thing() const {
|
||||
return 123;
|
||||
}
|
||||
};
|
||||
|
||||
class TestClass01 : public TestClass00 {
|
||||
public:
|
||||
TestClass01()
|
||||
: a(1) {
|
||||
}
|
||||
TestClass01(const TestClass00& other)
|
||||
: a(other.Thing()) {
|
||||
}
|
||||
|
||||
int a;
|
||||
};
|
||||
|
||||
class TestClass02 : public TestClass01 {
|
||||
public:
|
||||
TestClass02()
|
||||
: b(2) {
|
||||
}
|
||||
TestClass02(const TestClass01& other)
|
||||
: b(other.a) {
|
||||
}
|
||||
TestClass02(const TestClass00& other)
|
||||
: b(other.Thing()) {
|
||||
}
|
||||
|
||||
int b;
|
||||
};
|
||||
|
||||
class TestClass03 : public TestClass02 {
|
||||
public:
|
||||
TestClass03()
|
||||
: c(2) {
|
||||
}
|
||||
TestClass03(const TestClass02& other)
|
||||
: c(other.b) {
|
||||
}
|
||||
TestClass03(const TestClass01& other)
|
||||
: c(other.a) {
|
||||
}
|
||||
TestClass03(const TestClass00& other)
|
||||
: c(other.Thing()) {
|
||||
}
|
||||
|
||||
int c;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
|
||||
sol::simple_usertype<TestClass00> s_TestUsertype00(lua,
|
||||
sol::call_constructor, sol::constructors<sol::types<>>(),
|
||||
"Thing", &TestClass00::Thing);
|
||||
|
||||
lua.set_usertype("TestClass00", s_TestUsertype00);
|
||||
|
||||
sol::simple_usertype<TestClass01> s_TestUsertype01(lua,
|
||||
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass00&>>(),
|
||||
sol::base_classes, sol::bases<TestClass00>(),
|
||||
"a", &TestClass01::a);
|
||||
|
||||
lua.set_usertype("TestClass01", s_TestUsertype01);
|
||||
|
||||
sol::simple_usertype<TestClass02> s_TestUsertype02(lua,
|
||||
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
|
||||
sol::base_classes, sol::bases<TestClass01, TestClass00>(),
|
||||
"b", &TestClass02::b);
|
||||
|
||||
lua.set_usertype("TestClass02", s_TestUsertype02);
|
||||
|
||||
sol::simple_usertype<TestClass03> s_TestUsertype03(lua,
|
||||
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const TestClass02&>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
|
||||
sol::base_classes, sol::bases<TestClass02, TestClass01, TestClass00>(),
|
||||
"c", &TestClass03::c);
|
||||
|
||||
lua.set_usertype("TestClass03", s_TestUsertype03);
|
||||
|
||||
auto result1 = lua.safe_script(R"(
|
||||
tc0 = TestClass00()
|
||||
tc2 = TestClass02(tc0)
|
||||
tc1 = TestClass01()
|
||||
tc3 = TestClass03(tc1)
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
TestClass00& tc0 = lua["tc0"];
|
||||
TestClass01& tc1 = lua["tc1"];
|
||||
TestClass02& tc2 = lua["tc2"];
|
||||
TestClass03& tc3 = lua["tc3"];
|
||||
REQUIRE(tc0.Thing() == 123);
|
||||
REQUIRE(tc1.a == 1);
|
||||
REQUIRE(tc2.a == 1);
|
||||
REQUIRE(tc2.b == 123);
|
||||
REQUIRE(tc3.a == 1);
|
||||
REQUIRE(tc3.b == 2);
|
||||
REQUIRE(tc3.c == 1);
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
TEST_CASE("large_integer/bool", "pass bool integral value to and from lua") {
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
lua.set_function("f", [&](bool num) {
|
||||
REQUIRE(num == true);
|
||||
return num;
|
||||
});
|
||||
auto result1 = lua.safe_script("x = f(true)\n"
|
||||
"assert(x == true)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
sol::object x = lua["x"];
|
||||
REQUIRE(x.is<bool>());
|
||||
REQUIRE(x.as<bool>() == true);
|
||||
REQUIRE_FALSE(x.is<std::int32_t>());
|
||||
{
|
||||
auto result = lua.safe_script("f(1)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("large_integers/unsigned32", "pass large unsigned 32bit values to and from lua") {
|
||||
using T = std::uint32_t;
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
lua.set_function("f", [&](T num) -> T {
|
||||
REQUIRE(num == 0xFFFFFFFF);
|
||||
return num;
|
||||
});
|
||||
auto result1 = lua.safe_script("x = f(0xFFFFFFFF)\n"
|
||||
"assert(x == 0xFFFFFFFF)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
sol::object x = lua["x"];
|
||||
REQUIRE(x.is<T>());
|
||||
REQUIRE(x.as<T>() == 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
TEST_CASE("large_integer/unsigned53", "pass large unsigned 53bit value to and from lua") {
|
||||
using T = std::uint64_t;
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
lua.set_function("f", [&](T num) -> T {
|
||||
REQUIRE(num == 0x1FFFFFFFFFFFFFull);
|
||||
return num;
|
||||
});
|
||||
auto result1 = lua.safe_script("x = f(0x1FFFFFFFFFFFFF)\n"
|
||||
"assert(x == 0x1FFFFFFFFFFFFF)");
|
||||
REQUIRE(result1.valid());
|
||||
sol::object x = lua["x"];
|
||||
REQUIRE(x.is<T>());
|
||||
REQUIRE(x.as<T>() == 0x1FFFFFFFFFFFFFull);
|
||||
}
|
||||
|
||||
TEST_CASE("large_integer/unsigned64", "pass too large unsigned 64bit value to lua") {
|
||||
using T = std::int64_t;
|
||||
sol::state lua;
|
||||
lua.set_function("f", [&](T num) -> T {
|
||||
return num;
|
||||
});
|
||||
REQUIRE_THROWS([&lua]() {
|
||||
sol::protected_function pf = lua["f"];
|
||||
auto result = pf(0xFFFFFFFFFFFFFFFFull);
|
||||
}());
|
||||
}
|
||||
|
||||
TEST_CASE("large_integer/double", "pass negative and large positive values as signed and unsigned from and to lua") {
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
lua.set_function("s32", [&](std::int32_t num) {
|
||||
return num;
|
||||
});
|
||||
lua.set_function("s64", [&](std::int64_t num) {
|
||||
return num;
|
||||
});
|
||||
lua.set_function("u32", [&](std::uint32_t num) {
|
||||
return num;
|
||||
});
|
||||
lua.set_function("u64", [&](std::uint64_t num) {
|
||||
return num;
|
||||
});
|
||||
{
|
||||
//signed 32bit
|
||||
auto result1 = lua.safe_script("x = s32(-1)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
auto result2 = lua.safe_script("assert(x == -1)", sol::script_pass_on_error);
|
||||
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"];
|
||||
REQUIRE(x.is<std::int32_t>());
|
||||
REQUIRE(x.as<std::int32_t>() == -1);
|
||||
REQUIRE(x.is<std::uint32_t>());
|
||||
REQUIRE(x.as<std::uint32_t>() == 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
//unsigned 32bit
|
||||
{
|
||||
auto result1 = lua.safe_script("x = u32(0xFFFFFFFF)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
auto result2 = lua.safe_script("assert(x == 0xFFFFFFFF)", sol::script_pass_on_error);
|
||||
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"];
|
||||
REQUIRE(x.is<std::int32_t>());
|
||||
REQUIRE(x.as<std::int32_t>() == -1);
|
||||
REQUIRE(x.is<std::uint32_t>());
|
||||
REQUIRE(x.as<std::uint32_t>() == 0xFFFFFFFF);
|
||||
}
|
||||
//signed 64bit
|
||||
{
|
||||
auto result1 = lua.safe_script("x = s64(-1)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
auto result2 = lua.safe_script("assert(x == -1)", sol::script_pass_on_error);
|
||||
REQUIRE(result2.valid());
|
||||
sol::object x = lua["x"];
|
||||
REQUIRE(x.is<std::int64_t>());
|
||||
REQUIRE(x.as<std::int64_t>() == -1);
|
||||
REQUIRE(x.is<std::uint64_t>());
|
||||
REQUIRE(x.as<std::uint64_t>() == 0xFFFFFFFFFFFFFFFFull);
|
||||
}
|
||||
}
|
||||
+518
@@ -0,0 +1,518 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE("operators/default", "test that generic equality operators and all sorts of equality tests can be used") {
|
||||
struct T {};
|
||||
struct U {
|
||||
int a;
|
||||
U(int x = 20)
|
||||
: a(x) {
|
||||
}
|
||||
bool operator==(const U& r) {
|
||||
return a == r.a;
|
||||
}
|
||||
};
|
||||
struct V {
|
||||
int a;
|
||||
V(int x = 20)
|
||||
: a(x) {
|
||||
}
|
||||
bool operator==(const V& r) const {
|
||||
return a == r.a;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
T t1;
|
||||
T& t2 = t1;
|
||||
T t3;
|
||||
U u1;
|
||||
U u2{ 30 };
|
||||
U u3;
|
||||
U v1;
|
||||
U v2{ 30 };
|
||||
U v3;
|
||||
lua["t1"] = &t1;
|
||||
lua["t2"] = &t2;
|
||||
lua["t3"] = &t3;
|
||||
lua["u1"] = &u1;
|
||||
lua["u2"] = &u2;
|
||||
lua["u3"] = &u3;
|
||||
lua["v1"] = &v1;
|
||||
lua["v2"] = &v2;
|
||||
lua["v3"] = &v3;
|
||||
|
||||
SECTION("plain") {
|
||||
// Can only compare identity here
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(t1 == t1)"
|
||||
"assert(t2 == t2)"
|
||||
"assert(t3 == t3)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(t1 == t2)"
|
||||
"assert(not (t1 == t3))"
|
||||
"assert(not (t2 == t3))", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
// Object should compare equal to themselves
|
||||
// (and not invoke operator==; pointer test should be sufficient)
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(u1 == u1)"
|
||||
"assert(u2 == u2)"
|
||||
"assert(u3 == u3)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(not (u1 == u2))"
|
||||
"assert(u1 == u3)"
|
||||
"assert(not (u2 == u3))", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
// Object should compare equal to themselves
|
||||
// (and not invoke operator==; pointer test should be sufficient)
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(v1 == v1)"
|
||||
"assert(v2 == v2)"
|
||||
"assert(v3 == v3)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(not (v1 == v2))"
|
||||
"assert(v1 == v3)"
|
||||
"assert(not (v2 == v3))", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
}
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<T>("T");
|
||||
lua.new_usertype<U>("U");
|
||||
lua.new_usertype<V>("V");
|
||||
|
||||
// Can only compare identity here
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(t1 == t1)"
|
||||
"assert(t2 == t2)"
|
||||
"assert(t3 == t3)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(t1 == t2)"
|
||||
"assert(not (t1 == t3))"
|
||||
"assert(not (t2 == t3))", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
// Object should compare equal to themselves
|
||||
// (and not invoke operator==; pointer test should be sufficient)
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(u1 == u1)"
|
||||
"assert(u2 == u2)"
|
||||
"assert(u3 == u3)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(not (u1 == u2))"
|
||||
"assert(u1 == u3)"
|
||||
"assert(not (u2 == u3))", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
// Object should compare equal to themselves
|
||||
// (and not invoke operator==; pointer test should be sufficient)
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(v1 == v1)"
|
||||
"assert(v2 == v2)"
|
||||
"assert(v3 == v3)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(not (v1 == v2))"
|
||||
"assert(v1 == v3)"
|
||||
"assert(not (v2 == v3))", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<T>("T");
|
||||
lua.new_simple_usertype<U>("U");
|
||||
lua.new_simple_usertype<V>("V");
|
||||
|
||||
// Can only compare identity here
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(t1 == t1)"
|
||||
"assert(t2 == t2)"
|
||||
"assert(t3 == t3)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(t1 == t2)"
|
||||
"assert(not (t1 == t3))"
|
||||
"assert(not (t2 == t3))", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
// Object should compare equal to themselves
|
||||
// (and not invoke operator==; pointer test should be sufficient)
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(u1 == u1)"
|
||||
"assert(u2 == u2)"
|
||||
"assert(u3 == u3)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(not (u1 == u2))"
|
||||
"assert(u1 == u3)"
|
||||
"assert(not (u2 == u3))", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
// Object should compare equal to themselves
|
||||
// (and not invoke operator==; pointer test should be sufficient)
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(v1 == v1)"
|
||||
"assert(v2 == v2)"
|
||||
"assert(v3 == v3)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
{
|
||||
auto result1 = lua.safe_script("assert(not (v1 == v2))"
|
||||
"assert(v1 == v3)"
|
||||
"assert(not (v2 == v3))", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("operators/call", "test call operator generation") {
|
||||
struct callable {
|
||||
int operator()(int a, std::string b) {
|
||||
return a + static_cast<int>(b.length());
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
SECTION("plain") {
|
||||
{
|
||||
lua.set("obj", callable());
|
||||
auto result1 = lua.safe_script("v = obj(2, 'bark woof')", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
int v = lua["v"];
|
||||
REQUIRE(v == 11);
|
||||
}
|
||||
}
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<callable>("callable");
|
||||
{
|
||||
auto result1 = lua.safe_script("obj = callable.new()\n"
|
||||
"v = obj(2, 'bark woof')", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
int v = lua["v"];
|
||||
REQUIRE(v == 11);
|
||||
}
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<callable>("callable");
|
||||
{
|
||||
lua.safe_script("obj = callable.new()");
|
||||
lua.safe_script("v = obj(2, 'bark woof')");
|
||||
int v = lua["v"];
|
||||
REQUIRE(v == 11);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct stringable {
|
||||
static const void* last_print_ptr;
|
||||
};
|
||||
const void* stringable::last_print_ptr = nullptr;
|
||||
|
||||
std::ostream& operator<<(std::ostream& ostr, const stringable& o) {
|
||||
stringable::last_print_ptr = static_cast<const void*>(&o);
|
||||
return ostr << "{ stringable, std::ostream! }";
|
||||
}
|
||||
|
||||
struct adl_stringable {
|
||||
static const void* last_print_ptr;
|
||||
};
|
||||
const void* adl_stringable::last_print_ptr = nullptr;
|
||||
|
||||
std::string to_string(const adl_stringable& o) {
|
||||
adl_stringable::last_print_ptr = static_cast<const void*>(&o);
|
||||
return "{ adl_stringable, to_string! }";
|
||||
}
|
||||
|
||||
namespace inside {
|
||||
struct adl_stringable2 {
|
||||
static const void* last_print_ptr;
|
||||
};
|
||||
const void* adl_stringable2::last_print_ptr = nullptr;
|
||||
|
||||
std::string to_string(const adl_stringable2& o) {
|
||||
adl_stringable2::last_print_ptr = static_cast<const void*>(&o);
|
||||
return "{ inside::adl_stringable2, inside::to_string! }";
|
||||
}
|
||||
} // namespace inside
|
||||
|
||||
struct member_stringable {
|
||||
static const void* last_print_ptr;
|
||||
|
||||
std::string to_string() const {
|
||||
member_stringable::last_print_ptr = static_cast<const void*>(this);
|
||||
return "{ member_stringable, to_string! }";
|
||||
}
|
||||
};
|
||||
const void* member_stringable::last_print_ptr = nullptr;
|
||||
|
||||
TEST_CASE("operators/stringable", "test std::ostream stringability") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
SECTION("plain") {
|
||||
{
|
||||
lua["obj"] = stringable();
|
||||
auto result1 = lua.safe_script("print(obj)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
stringable& obj = lua["obj"];
|
||||
REQUIRE(stringable::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<stringable>("stringable");
|
||||
{
|
||||
auto result1 = lua.safe_script(R"(obj = stringable.new()
|
||||
print(obj) )", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
stringable& obj = lua["obj"];
|
||||
REQUIRE(stringable::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<stringable>("stringable");
|
||||
{
|
||||
auto result1 = lua.safe_script(R"(obj = stringable.new()
|
||||
print(obj))", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
stringable& obj = lua["obj"];
|
||||
REQUIRE(stringable::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("operators/adl_stringable", "test adl to_string stringability") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
SECTION("plain") {
|
||||
{
|
||||
lua["obj"] = adl_stringable();
|
||||
lua.safe_script("print(obj)");
|
||||
adl_stringable& obj = lua["obj"];
|
||||
REQUIRE(adl_stringable::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<adl_stringable>("stringable");
|
||||
{
|
||||
lua["obj"] = adl_stringable();
|
||||
lua.safe_script("print(obj)");
|
||||
adl_stringable& obj = lua["obj"];
|
||||
REQUIRE(adl_stringable::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<adl_stringable>("stringable");
|
||||
{
|
||||
lua.safe_script("obj = stringable.new()");
|
||||
lua.safe_script("print(obj)");
|
||||
adl_stringable& obj = lua["obj"];
|
||||
REQUIRE(adl_stringable::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("operators/inside::adl_stringable2", "test adl to_string stringability from inside a namespace") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
SECTION("plain") {
|
||||
{
|
||||
lua["obj"] = inside::adl_stringable2();
|
||||
lua.safe_script("print(obj)");
|
||||
inside::adl_stringable2& obj = lua["obj"];
|
||||
REQUIRE(inside::adl_stringable2::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<inside::adl_stringable2>("stringable");
|
||||
{
|
||||
lua.safe_script("obj = stringable.new()");
|
||||
lua.safe_script("print(obj)");
|
||||
inside::adl_stringable2& obj = lua["obj"];
|
||||
REQUIRE(inside::adl_stringable2::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<inside::adl_stringable2>("stringable");
|
||||
{
|
||||
lua.safe_script("obj = stringable.new()");
|
||||
lua.safe_script("print(obj)");
|
||||
inside::adl_stringable2& obj = lua["obj"];
|
||||
REQUIRE(inside::adl_stringable2::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("operators/member_stringable", "test member to_string stringability") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
SECTION("plain") {
|
||||
{
|
||||
lua["obj"] = member_stringable();
|
||||
lua.safe_script("print(obj)");
|
||||
member_stringable& obj = lua["obj"];
|
||||
REQUIRE(member_stringable::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<member_stringable>("stringable");
|
||||
{
|
||||
lua.safe_script("obj = stringable.new()");
|
||||
lua.safe_script("print(obj)");
|
||||
member_stringable& obj = lua["obj"];
|
||||
REQUIRE(member_stringable::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<member_stringable>("stringable");
|
||||
{
|
||||
lua.safe_script("obj = stringable.new()");
|
||||
lua.safe_script("print(obj)");
|
||||
member_stringable& obj = lua["obj"];
|
||||
REQUIRE(member_stringable::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("operators/container-like", "test that generic begin/end and iterator are automatically bound") {
|
||||
#if SOL_LUA_VERSION > 501
|
||||
struct container {
|
||||
typedef int* iterator;
|
||||
typedef int value_type;
|
||||
|
||||
value_type values[10];
|
||||
|
||||
container() {
|
||||
std::iota(begin(), end(), 1);
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
return &values[0];
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return &values[0] + 10;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
SECTION("plain") {
|
||||
{
|
||||
lua["obj"] = container();
|
||||
lua.safe_script("i = 0 for k, v in pairs(obj) do i = i + 1 assert(k == v) end");
|
||||
std::size_t i = lua["i"];
|
||||
REQUIRE(i == 10);
|
||||
}
|
||||
}
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<container>("container");
|
||||
{
|
||||
lua.safe_script("obj = container.new()");
|
||||
lua.safe_script("i = 0 for k, v in pairs(obj) do i = i + 1 assert(k == v) end");
|
||||
std::size_t i = lua["i"];
|
||||
REQUIRE(i == 10);
|
||||
}
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<container>("container");
|
||||
{
|
||||
lua.safe_script("obj = container.new()");
|
||||
lua.safe_script("i = 0 for k, v in pairs(obj) do i = i + 1 assert(k == v) end");
|
||||
std::size_t i = lua["i"];
|
||||
REQUIRE(i == 10);
|
||||
}
|
||||
}
|
||||
#else
|
||||
SUCCEED("");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("operators/length", "test that size is automatically bound to the length operator") {
|
||||
struct sizable {
|
||||
std::size_t size() const {
|
||||
return 6;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
SECTION("plain") {
|
||||
{
|
||||
lua["obj"] = sizable();
|
||||
lua.safe_script("s = #obj");
|
||||
std::size_t s = lua["s"];
|
||||
REQUIRE(s == 6);
|
||||
}
|
||||
}
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<sizable>("sizable");
|
||||
{
|
||||
lua.safe_script("obj = sizable.new()");
|
||||
lua.safe_script("s = #obj");
|
||||
std::size_t s = lua["s"];
|
||||
REQUIRE(s == 6);
|
||||
}
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<sizable>("sizable");
|
||||
{
|
||||
lua.safe_script("obj = sizable.new()");
|
||||
lua.safe_script("s = #obj");
|
||||
std::size_t s = lua["s"];
|
||||
REQUIRE(s == 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("issues/stack overflow", "make sure various operations repeated don't trigger stack overflow") {
|
||||
sol::state lua;
|
||||
lua.safe_script("t = {};t[0]=20");
|
||||
lua.safe_script("lua_function=function(i)return i;end");
|
||||
|
||||
sol::function f = lua["lua_function"];
|
||||
std::string teststring = "testtext";
|
||||
REQUIRE_NOTHROW([&] {
|
||||
for (int i = 0; i < 1000000; ++i) {
|
||||
std::string result = f(teststring);
|
||||
if (result != teststring)
|
||||
throw std::logic_error("RIP");
|
||||
}
|
||||
}());
|
||||
sol::table t = lua["t"];
|
||||
int expected = 20;
|
||||
REQUIRE_NOTHROW([&] {
|
||||
for (int i = 0; i < 1000000; ++i) {
|
||||
int result = t[0];
|
||||
t.size();
|
||||
if (result != expected)
|
||||
throw std::logic_error("RIP");
|
||||
}
|
||||
}());
|
||||
}
|
||||
|
||||
TEST_CASE("issues/stack overflow 2", "make sure basic iterators clean up properly when they're not iterated through (e.g., with empty())") {
|
||||
sol::state lua;
|
||||
sol::table t = lua.create_table_with(1, "wut");
|
||||
int MAX = 50000;
|
||||
auto fx = [&]() {
|
||||
int a = 50;
|
||||
for (int i = 0; i < MAX; ++i) {
|
||||
if (t.empty()) {
|
||||
a += 4;
|
||||
}
|
||||
a += 2;
|
||||
}
|
||||
};
|
||||
REQUIRE_NOTHROW(fx());
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#define SOL_ENABLE_INTEROP 1
|
||||
|
||||
#include <sol.hpp>
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("plain/alignment", "test that aligned classes in certain compilers don't trigger compiler errors") {
|
||||
#ifdef _MSC_VER
|
||||
__declspec(align(16)) struct aligned_class {
|
||||
int var;
|
||||
};
|
||||
|
||||
struct A {
|
||||
aligned_class a;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::math);
|
||||
|
||||
lua.new_usertype<A>("A");
|
||||
A a;
|
||||
lua["a"] = &a;
|
||||
A& la = lua["a"];
|
||||
REQUIRE(&a == &la);
|
||||
#else
|
||||
REQUIRE(true);
|
||||
#endif // VC++ stuff
|
||||
}
|
||||
|
||||
TEST_CASE("plain/indestructible", "test that we error for types that are innately indestructible") {
|
||||
struct indestructible {
|
||||
public:
|
||||
int v = 20;
|
||||
|
||||
struct insider {
|
||||
void operator()(indestructible* i) const {
|
||||
i->~indestructible();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
~indestructible() {
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("doomed") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
std::unique_ptr<indestructible, indestructible::insider> i = sol::detail::make_unique_deleter<indestructible, indestructible::insider>();
|
||||
lua["i"] = *i;
|
||||
lua.safe_script("i = nil");
|
||||
auto result = lua.safe_script("collectgarbage()", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
SECTION("saved") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
std::unique_ptr<indestructible, indestructible::insider> i = sol::detail::make_unique_deleter<indestructible, indestructible::insider>();
|
||||
lua["i"] = *i;
|
||||
lua.new_usertype<indestructible>("indestructible",
|
||||
sol::default_constructor,
|
||||
sol::meta_function::garbage_collect, sol::destructor([](indestructible& i) {
|
||||
indestructible::insider del;
|
||||
del(&i);
|
||||
}));
|
||||
lua.safe_script("i = nil");
|
||||
auto result = lua.safe_script("collectgarbage()", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("plain/constructors and destructors", "Make sure that constructors, destructors, deallocators and others work properly with the desired type") {
|
||||
static int constructed = 0;
|
||||
static int destructed = 0;
|
||||
static int copied = 0;
|
||||
static int moved = 0;
|
||||
|
||||
struct st {
|
||||
int value = 10;
|
||||
|
||||
st() : value(10) {
|
||||
++constructed;
|
||||
}
|
||||
|
||||
st(const st& o) : value(o.value) {
|
||||
++copied;
|
||||
++constructed;
|
||||
}
|
||||
|
||||
st(st&& o) : value(o.value) {
|
||||
++moved;
|
||||
++constructed;
|
||||
}
|
||||
|
||||
~st() {
|
||||
value = 0;
|
||||
++destructed;
|
||||
}
|
||||
};
|
||||
|
||||
struct deallocate_only {
|
||||
void operator()(st* p) const {
|
||||
std::allocator<st> alloc;
|
||||
alloc.deallocate(p, 1);
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
sol::state lua;
|
||||
|
||||
lua["f"] = sol::constructors<st()>();
|
||||
lua["g"] = sol::initializers([](st* mem) { std::allocator<st> alloc; std::allocator_traits<std::allocator<st>>::construct(alloc, mem); });
|
||||
lua["h"] = sol::factories([]() { return st(); });
|
||||
lua["d"] = sol::destructor([](st& m) { m.~st(); });
|
||||
|
||||
sol::protected_function_result result1 = lua.safe_script("v = f()", &sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
st& v = lua["v"];
|
||||
REQUIRE(v.value == 10);
|
||||
REQUIRE(constructed == 1);
|
||||
REQUIRE(destructed == 0);
|
||||
{
|
||||
std::unique_ptr<st, deallocate_only> unsafe(new st());
|
||||
lua["unsafe"] = unsafe.get();
|
||||
sol::protected_function_result result2 = lua.safe_script("d(unsafe)", &sol::script_pass_on_error);
|
||||
REQUIRE(result2.valid());
|
||||
REQUIRE(constructed == 2);
|
||||
REQUIRE(destructed == 1);
|
||||
}
|
||||
REQUIRE(constructed == 2);
|
||||
REQUIRE(destructed == 1);
|
||||
|
||||
{
|
||||
sol::protected_function_result result3 = lua.safe_script("vg = g()", &sol::script_pass_on_error);
|
||||
REQUIRE(result3.valid());
|
||||
st& vg = lua["vg"];
|
||||
REQUIRE(vg.value == 10);
|
||||
REQUIRE(constructed == 3);
|
||||
REQUIRE(destructed == 1);
|
||||
}
|
||||
|
||||
{
|
||||
sol::protected_function_result result4 = lua.safe_script("vh = h()", &sol::script_pass_on_error);
|
||||
REQUIRE(result4.valid());
|
||||
st& vh = lua["vh"];
|
||||
REQUIRE(vh.value == 10);
|
||||
}
|
||||
}
|
||||
int purely_constructed = constructed - moved - copied;
|
||||
int purely_destructed = destructed - moved - copied;
|
||||
REQUIRE(constructed == destructed);
|
||||
REQUIRE(purely_constructed == purely_destructed);
|
||||
REQUIRE(purely_constructed == 4);
|
||||
REQUIRE(purely_destructed == 4);
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE("proxy/function results", "make sure that function results return proper proxies and can be indexed nicely") {
|
||||
sol::state lua;
|
||||
SECTION("unsafe_function_result") {
|
||||
auto ufr = lua.script("return 1, 2, 3, 4");
|
||||
int accum = 0;
|
||||
for (const auto& r : ufr) {
|
||||
int v = r;
|
||||
accum += v;
|
||||
}
|
||||
REQUIRE(accum == 10);
|
||||
}
|
||||
SECTION("protected_function_result") {
|
||||
auto pfr = lua.safe_script("return 1, 2, 3, 4");
|
||||
int accum = 0;
|
||||
for (const auto& r : pfr) {
|
||||
int v = r;
|
||||
accum += v;
|
||||
}
|
||||
REQUIRE(accum == 10);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("proxy/optional conversion", "make sure optional conversions out of a table work properly") {
|
||||
sol::state state{};
|
||||
sol::table table = state.create_table_with("func", 42);
|
||||
sol::optional<sol::function> func = table["func"];
|
||||
REQUIRE(func == sol::nullopt);
|
||||
}
|
||||
|
||||
TEST_CASE("proxy/proper-pushing", "allow proxies to reference other proxies and be serialized as the proxy itself and not a function or something") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::io);
|
||||
|
||||
class T {};
|
||||
lua.new_usertype<T>("T");
|
||||
|
||||
T t;
|
||||
lua["t1"] = &t;
|
||||
lua["t2"] = lua["t1"];
|
||||
lua.safe_script("b = t1 == t2");
|
||||
bool b = lua["b"];
|
||||
REQUIRE(b);
|
||||
}
|
||||
|
||||
TEST_CASE("proxy/equality", "check to make sure equality tests work") {
|
||||
sol::state lua;
|
||||
#ifndef __clang__
|
||||
REQUIRE((lua["a"] == sol::lua_nil));
|
||||
REQUIRE((lua["a"] == nullptr));
|
||||
REQUIRE_FALSE((lua["a"] != sol::lua_nil));
|
||||
REQUIRE_FALSE((lua["a"] != nullptr));
|
||||
REQUIRE_FALSE((lua["a"] == 0));
|
||||
REQUIRE_FALSE((lua["a"] == 2));
|
||||
REQUIRE((lua["a"] != 0));
|
||||
REQUIRE((lua["a"] != 2));
|
||||
#endif // clang screws up by trying to access int128 types that it doesn't support, even when we don't ask for them
|
||||
|
||||
lua["a"] = 2;
|
||||
|
||||
#ifndef __clang__
|
||||
REQUIRE_FALSE((lua["a"] == sol::lua_nil));
|
||||
REQUIRE_FALSE((lua["a"] == nullptr));
|
||||
REQUIRE((lua["a"] != sol::lua_nil));
|
||||
REQUIRE((lua["a"] != nullptr));
|
||||
REQUIRE_FALSE((lua["a"] == 0));
|
||||
REQUIRE((lua["a"] == 2));
|
||||
REQUIRE((lua["a"] != 0));
|
||||
REQUIRE_FALSE((lua["a"] != 2));
|
||||
#endif // clang screws up by trying to access int128 types that it doesn't support, even when we don't ask for them
|
||||
}
|
||||
+977
@@ -0,0 +1,977 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
TEST_CASE("simple_usertype/usertypes", "Ensure that simple usertypes properly work here") {
|
||||
struct marker {
|
||||
bool value = false;
|
||||
};
|
||||
struct bark {
|
||||
int var = 50;
|
||||
marker mark;
|
||||
|
||||
void fun() {
|
||||
var = 51;
|
||||
}
|
||||
|
||||
int get() const {
|
||||
return var;
|
||||
}
|
||||
|
||||
int set(int x) {
|
||||
var = x;
|
||||
return var;
|
||||
}
|
||||
|
||||
std::string special() const {
|
||||
return mark.value ? "woof" : "pantpant";
|
||||
}
|
||||
|
||||
const marker& the_marker() const {
|
||||
return mark;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.new_simple_usertype<bark>("bark",
|
||||
"fun", &bark::fun,
|
||||
"get", &bark::get,
|
||||
"var", sol::as_function(&bark::var),
|
||||
"the_marker", sol::as_function(&bark::the_marker),
|
||||
"x", sol::overload(&bark::get),
|
||||
"y", sol::overload(&bark::set),
|
||||
"z", sol::overload(&bark::get, &bark::set));
|
||||
|
||||
lua.safe_script("b = bark.new()");
|
||||
bark& b = lua["b"];
|
||||
|
||||
lua.safe_script("b:fun()");
|
||||
int var = b.var;
|
||||
REQUIRE(var == 51);
|
||||
|
||||
lua.safe_script("b:var(20)");
|
||||
lua.safe_script("v = b:var()");
|
||||
int v = lua["v"];
|
||||
REQUIRE(v == 20);
|
||||
REQUIRE(b.var == 20);
|
||||
|
||||
lua.safe_script("m = b:the_marker()");
|
||||
marker& m = lua["m"];
|
||||
REQUIRE_FALSE(b.mark.value);
|
||||
REQUIRE_FALSE(m.value);
|
||||
m.value = true;
|
||||
REQUIRE(&b.mark == &m);
|
||||
REQUIRE(b.mark.value);
|
||||
|
||||
sol::table barktable = lua["bark"];
|
||||
barktable["special"] = &bark::special;
|
||||
|
||||
lua.safe_script("s = b:special()");
|
||||
std::string s = lua["s"];
|
||||
REQUIRE(s == "woof");
|
||||
|
||||
lua.safe_script("b:y(24)");
|
||||
lua.safe_script("x = b:x()");
|
||||
int x = lua["x"];
|
||||
REQUIRE(x == 24);
|
||||
|
||||
lua.safe_script("z = b:z(b:z() + 5)");
|
||||
int z = lua["z"];
|
||||
REQUIRE(z == 29);
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/usertype constructors", "Ensure that calls with specific arguments work") {
|
||||
struct marker {
|
||||
bool value = false;
|
||||
};
|
||||
struct bark {
|
||||
int var = 50;
|
||||
marker mark;
|
||||
|
||||
bark() {
|
||||
}
|
||||
bark(int v)
|
||||
: var(v) {
|
||||
}
|
||||
|
||||
void fun() {
|
||||
var = 51;
|
||||
}
|
||||
|
||||
int get() const {
|
||||
return var;
|
||||
}
|
||||
|
||||
int set(int x) {
|
||||
var = x;
|
||||
return var;
|
||||
}
|
||||
|
||||
std::string special() const {
|
||||
return mark.value ? "woof" : "pantpant";
|
||||
}
|
||||
|
||||
const marker& the_marker() const {
|
||||
return mark;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.new_simple_usertype<bark>("bark",
|
||||
sol::constructors<sol::types<>, sol::types<int>>(),
|
||||
"fun", sol::protect(&bark::fun),
|
||||
"get", &bark::get,
|
||||
"var", sol::as_function(&bark::var),
|
||||
"the_marker", &bark::the_marker,
|
||||
"x", sol::overload(&bark::get),
|
||||
"y", sol::overload(&bark::set),
|
||||
"z", sol::overload(&bark::get, &bark::set));
|
||||
|
||||
lua.safe_script("bx = bark.new(760)");
|
||||
bark& bx = lua["bx"];
|
||||
REQUIRE(bx.var == 760);
|
||||
|
||||
lua.safe_script("b = bark.new()");
|
||||
bark& b = lua["b"];
|
||||
|
||||
lua.safe_script("b:fun()");
|
||||
int var = b.var;
|
||||
REQUIRE(var == 51);
|
||||
|
||||
lua.safe_script("b:var(20)");
|
||||
lua.safe_script("v = b:var()");
|
||||
int v = lua["v"];
|
||||
REQUIRE(v == 20);
|
||||
|
||||
lua.safe_script("m = b:the_marker()");
|
||||
marker& m = lua["m"];
|
||||
REQUIRE_FALSE(b.mark.value);
|
||||
REQUIRE_FALSE(m.value);
|
||||
m.value = true;
|
||||
REQUIRE(&b.mark == &m);
|
||||
REQUIRE(b.mark.value);
|
||||
|
||||
sol::table barktable = lua["bark"];
|
||||
barktable["special"] = &bark::special;
|
||||
|
||||
lua.safe_script("s = b:special()");
|
||||
std::string s = lua["s"];
|
||||
REQUIRE(s == "woof");
|
||||
|
||||
lua.safe_script("b:y(24)");
|
||||
lua.safe_script("x = b:x()");
|
||||
int x = lua["x"];
|
||||
REQUIRE(x == 24);
|
||||
|
||||
lua.safe_script("z = b:z(b:z() + 5)");
|
||||
int z = lua["z"];
|
||||
REQUIRE(z == 29);
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/vars", "simple usertype vars can bind various values (no ref)") {
|
||||
int muh_variable = 10;
|
||||
int through_variable = 25;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
struct test {};
|
||||
lua.new_simple_usertype<test>("test",
|
||||
"straight", sol::var(2),
|
||||
"global", sol::var(muh_variable),
|
||||
"global2", sol::var(through_variable),
|
||||
"global3", sol::var(std::ref(through_variable)));
|
||||
|
||||
through_variable = 20;
|
||||
|
||||
lua.safe_script(R"(
|
||||
print(test.straight)
|
||||
s = test.straight
|
||||
print(test.global)
|
||||
g = test.global
|
||||
print(test.global2)
|
||||
g2 = test.global2
|
||||
print(test.global3)
|
||||
g3 = test.global3
|
||||
)");
|
||||
|
||||
int s = lua["s"];
|
||||
int g = lua["g"];
|
||||
int g2 = lua["g2"];
|
||||
int g3 = lua["g3"];
|
||||
REQUIRE(s == 2);
|
||||
REQUIRE(g == 10);
|
||||
REQUIRE(g2 == 25);
|
||||
REQUIRE(g3 == 20);
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/variable-control", "test to see if usertypes respond to inheritance and variable controls") {
|
||||
class A {
|
||||
public:
|
||||
virtual void a() {
|
||||
throw std::runtime_error("entered base pure virtual implementation");
|
||||
};
|
||||
};
|
||||
|
||||
class B : public A {
|
||||
public:
|
||||
virtual void a() override {
|
||||
}
|
||||
};
|
||||
|
||||
class sA {
|
||||
public:
|
||||
virtual void a() {
|
||||
throw std::runtime_error("entered base pure virtual implementation");
|
||||
};
|
||||
};
|
||||
|
||||
class sB : public sA {
|
||||
public:
|
||||
virtual void a() override {
|
||||
}
|
||||
};
|
||||
|
||||
struct sV {
|
||||
int a = 10;
|
||||
int b = 20;
|
||||
|
||||
int get_b() const {
|
||||
return b + 2;
|
||||
}
|
||||
|
||||
void set_b(int value) {
|
||||
b = value;
|
||||
}
|
||||
};
|
||||
|
||||
struct sW : sV {};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
lua.new_usertype<A>("A", "a", &A::a);
|
||||
lua.new_usertype<B>("B", sol::base_classes, sol::bases<A>());
|
||||
lua.new_simple_usertype<sA>("sA", "a", &sA::a);
|
||||
lua.new_simple_usertype<sB>("sB", sol::base_classes, sol::bases<sA>());
|
||||
lua.new_simple_usertype<sV>("sV", "a", &sV::a, "b", &sV::b, "pb", sol::property(&sV::get_b, &sV::set_b));
|
||||
lua.new_simple_usertype<sW>("sW", sol::base_classes, sol::bases<sV>());
|
||||
|
||||
B b;
|
||||
lua.set("b", &b);
|
||||
lua.safe_script("b:a()");
|
||||
|
||||
sB sb;
|
||||
lua.set("sb", &sb);
|
||||
lua.safe_script("sb:a()");
|
||||
|
||||
sV sv;
|
||||
lua.set("sv", &sv);
|
||||
lua.safe_script("print(sv.b)assert(sv.b == 20)");
|
||||
|
||||
sW sw;
|
||||
lua.set("sw", &sw);
|
||||
lua.safe_script("print(sw.a)assert(sw.a == 10)");
|
||||
lua.safe_script("print(sw.b)assert(sw.b == 20)");
|
||||
lua.safe_script("print(sw.pb)assert(sw.pb == 22)");
|
||||
lua.safe_script("sw.a = 11");
|
||||
lua.safe_script("sw.b = 21");
|
||||
lua.safe_script("print(sw.a)assert(sw.a == 11)");
|
||||
lua.safe_script("print(sw.b)assert(sw.b == 21)");
|
||||
lua.safe_script("print(sw.pb)assert(sw.pb == 23)");
|
||||
lua.safe_script("sw.pb = 25");
|
||||
lua.safe_script("print(sw.b)assert(sw.b == 25)");
|
||||
lua.safe_script("print(sw.pb)assert(sw.pb == 27)");
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/factory constructor overloads", "simple usertypes should invoke the proper factories") {
|
||||
class A {
|
||||
public:
|
||||
virtual void a() {
|
||||
throw std::runtime_error("entered base pure virtual implementation");
|
||||
};
|
||||
};
|
||||
|
||||
class B : public A {
|
||||
public:
|
||||
int bvar = 24;
|
||||
virtual void a() override {
|
||||
}
|
||||
void f() {
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
sol::constructors<sol::types<>, sol::types<const B&>> c;
|
||||
lua.new_simple_usertype<B>("B",
|
||||
sol::call_constructor, c,
|
||||
"new", sol::factories([]() {
|
||||
return B();
|
||||
}),
|
||||
"new2", sol::initializers([](B& mem) { new (&mem) B(); }, [](B& mem, int v) {
|
||||
new(&mem)B(); mem.bvar = v; }),
|
||||
"f", sol::as_function(&B::bvar),
|
||||
"g", sol::overload([](B&) { return 2; }, [](B&, int v) { return v; }));
|
||||
|
||||
lua.safe_script("b = B()");
|
||||
lua.safe_script("b2 = B.new()");
|
||||
lua.safe_script("b3 = B.new2()");
|
||||
lua.safe_script("b4 = B.new2(11)");
|
||||
|
||||
lua.safe_script("x = b:f()");
|
||||
lua.safe_script("x2 = b2:f()");
|
||||
lua.safe_script("x3 = b3:f()");
|
||||
lua.safe_script("x4 = b4:f()");
|
||||
int x = lua["x"];
|
||||
int x2 = lua["x2"];
|
||||
int x3 = lua["x3"];
|
||||
int x4 = lua["x4"];
|
||||
REQUIRE(x == 24);
|
||||
REQUIRE(x2 == 24);
|
||||
REQUIRE(x3 == 24);
|
||||
REQUIRE(x4 == 11);
|
||||
|
||||
lua.safe_script("y = b:g()");
|
||||
lua.safe_script("y2 = b2:g(3)");
|
||||
lua.safe_script("y3 = b3:g()");
|
||||
lua.safe_script("y4 = b4:g(3)");
|
||||
int y = lua["y"];
|
||||
int y2 = lua["y2"];
|
||||
int y3 = lua["y3"];
|
||||
int y4 = lua["y4"];
|
||||
REQUIRE(y == 2);
|
||||
REQUIRE(y2 == 3);
|
||||
REQUIRE(y3 == 2);
|
||||
REQUIRE(y4 == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/runtime append", "allow extra functions to be appended at runtime directly to the metatable itself") {
|
||||
class A {
|
||||
};
|
||||
|
||||
class B : public A {
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.new_simple_usertype<A>("A");
|
||||
lua.new_simple_usertype<B>("B", sol::base_classes, sol::bases<A>());
|
||||
lua.set("b", std::make_unique<B>());
|
||||
lua["A"]["method"] = []() { return 200; };
|
||||
lua["B"]["method2"] = [](B&) { return 100; };
|
||||
lua.safe_script("x = b.method()");
|
||||
lua.safe_script("y = b:method()");
|
||||
|
||||
int x = lua["x"];
|
||||
int y = lua["y"];
|
||||
REQUIRE(x == 200);
|
||||
REQUIRE(y == 200);
|
||||
|
||||
lua.safe_script("z = b.method2(b)");
|
||||
lua.safe_script("w = b:method2()");
|
||||
int z = lua["z"];
|
||||
int w = lua["w"];
|
||||
REQUIRE(z == 100);
|
||||
REQUIRE(w == 100);
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/table append", "Ensure that appending to the meta table also affects the internal function table for pointers as well") {
|
||||
struct A {
|
||||
int func() {
|
||||
return 5000;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
lua.new_simple_usertype<A>("A");
|
||||
sol::table table = lua["A"];
|
||||
table["func"] = &A::func;
|
||||
A a;
|
||||
lua.set("a", &a);
|
||||
lua.set("pa", &a);
|
||||
lua.set("ua", std::make_unique<A>());
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.safe_script("assert(a:func() == 5000)");
|
||||
lua.safe_script("assert(pa:func() == 5000)");
|
||||
lua.safe_script("assert(ua:func() == 5000)");
|
||||
}());
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/class call propogation", "make sure methods and variables from base classes work properly in SAFE_USERTYPE mode") {
|
||||
class A {
|
||||
public:
|
||||
int var = 200;
|
||||
int thing() const {
|
||||
return 123;
|
||||
}
|
||||
};
|
||||
|
||||
class B : public A {
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_simple_usertype<B>("B",
|
||||
sol::default_constructor,
|
||||
"thing", &B::thing,
|
||||
"var", &B::var);
|
||||
|
||||
lua.safe_script(R"(
|
||||
b = B.new()
|
||||
print(b.var)
|
||||
b:thing()
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/call constructor", "ensure that all kinds of call-based constructors can be serialized") {
|
||||
struct thing {};
|
||||
struct v_test {
|
||||
};
|
||||
struct f_test {
|
||||
int i;
|
||||
f_test(int i)
|
||||
: i(i) {
|
||||
}
|
||||
};
|
||||
struct i_test {
|
||||
int i;
|
||||
i_test(int i)
|
||||
: i(i) {
|
||||
}
|
||||
};
|
||||
struct r_test {
|
||||
int i;
|
||||
r_test(int i)
|
||||
: i(i) {
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
auto f = sol::factories([]() { return f_test(30); });
|
||||
lua.new_simple_usertype<f_test>("f_test",
|
||||
sol::call_constructor, sol::factories([]() {
|
||||
return f_test(20);
|
||||
}),
|
||||
"new", f);
|
||||
|
||||
lua.new_simple_usertype<i_test>("i_test",
|
||||
sol::call_constructor, sol::initializers([](i_test& obj) {
|
||||
new (&obj) i_test(21);
|
||||
}));
|
||||
|
||||
lua.new_simple_usertype<r_test>("r_test",
|
||||
sol::call_constructor, [](sol::table) {
|
||||
return r_test(22);
|
||||
});
|
||||
|
||||
lua.safe_script("a = f_test()");
|
||||
lua.safe_script("b = i_test()");
|
||||
lua.safe_script("c = r_test()");
|
||||
lua.safe_script("d = f_test.new()");
|
||||
f_test& a = lua["a"];
|
||||
f_test& d = lua["d"];
|
||||
i_test& b = lua["b"];
|
||||
r_test& c = lua["c"];
|
||||
REQUIRE(a.i == 20);
|
||||
REQUIRE(b.i == 21);
|
||||
REQUIRE(c.i == 22);
|
||||
REQUIRE(d.i == 30);
|
||||
|
||||
auto vfactories = sol::factories(
|
||||
[](const sol::table& tbl) {
|
||||
for (auto v : tbl) {
|
||||
REQUIRE(v.second.valid());
|
||||
REQUIRE(v.second.is<thing>());
|
||||
}
|
||||
return v_test();
|
||||
});
|
||||
|
||||
lua.new_simple_usertype<v_test>("v_test",
|
||||
sol::meta_function::construct, vfactories,
|
||||
sol::call_constructor, vfactories);
|
||||
|
||||
lua.new_simple_usertype<thing>("thing");
|
||||
lua.safe_script("things = {thing.new(), thing.new()}");
|
||||
|
||||
SECTION("new") {
|
||||
{
|
||||
auto result = lua.safe_script("a = v_test.new(things)", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
}
|
||||
SECTION("call_constructor") {
|
||||
{
|
||||
auto result = lua.safe_script("b = v_test(things)", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/no_constructor", "make sure simple usertype errors when no-constructor types are called") {
|
||||
struct thing {};
|
||||
|
||||
SECTION("new no_constructor") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_simple_usertype<thing>("thing",
|
||||
sol::meta_function::construct, sol::no_constructor);
|
||||
auto result = lua.safe_script("a = thing.new()", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
SECTION("call no_constructor") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_simple_usertype<thing>("thing",
|
||||
sol::call_constructor, sol::no_constructor);
|
||||
auto result = lua.safe_script("a = thing()", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/missing key", "make sure a missing key returns nil") {
|
||||
struct thing {};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_simple_usertype<thing>("thing");
|
||||
{
|
||||
auto result = lua.safe_script("print(thing.missingKey)", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/runtime extensibility", "Check if usertypes are runtime extensible") {
|
||||
struct thing {
|
||||
int v = 20;
|
||||
int func(int a) {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
int val = 0;
|
||||
|
||||
SECTION("just functions") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_simple_usertype<thing>("thing",
|
||||
"func", &thing::func);
|
||||
|
||||
lua.safe_script(R"(
|
||||
t = thing.new()
|
||||
)");
|
||||
|
||||
{
|
||||
auto result = lua.safe_script(R"(
|
||||
t.runtime_func = function (a)
|
||||
return a + 50
|
||||
end
|
||||
)",
|
||||
sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
{
|
||||
auto result = lua.safe_script(R"(
|
||||
function t:runtime_func(a)
|
||||
return a + 52
|
||||
end
|
||||
)",
|
||||
sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
lua.safe_script("val = t:func(2)");
|
||||
val = lua["val"];
|
||||
REQUIRE(val == 2);
|
||||
|
||||
REQUIRE_NOTHROW([&lua]() {
|
||||
lua.safe_script(R"(
|
||||
function thing:runtime_func(a)
|
||||
return a + 1
|
||||
end
|
||||
)");
|
||||
}());
|
||||
|
||||
lua.safe_script("val = t:runtime_func(2)");
|
||||
val = lua["val"];
|
||||
REQUIRE(val == 3);
|
||||
}
|
||||
SECTION("with variable") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_simple_usertype<thing>("thing",
|
||||
"func", &thing::func,
|
||||
"v", &thing::v);
|
||||
|
||||
lua.safe_script(R"(
|
||||
t = thing.new()
|
||||
)");
|
||||
|
||||
{
|
||||
auto result = lua.safe_script(R"(
|
||||
t.runtime_func = function (a)
|
||||
return a + 50
|
||||
end
|
||||
)",
|
||||
sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
{
|
||||
auto result = lua.safe_script(R"(
|
||||
function t:runtime_func(a)
|
||||
return a + 52
|
||||
end
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
lua.safe_script("val = t:func(2)");
|
||||
val = lua["val"];
|
||||
REQUIRE(val == 2);
|
||||
|
||||
REQUIRE_NOTHROW([&lua]() {
|
||||
lua.safe_script(R"(
|
||||
function thing:runtime_func(a)
|
||||
return a + 1
|
||||
end
|
||||
)");
|
||||
}());
|
||||
|
||||
lua.safe_script("val = t:runtime_func(2)");
|
||||
val = lua["val"];
|
||||
REQUIRE(val == 3);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/runtime replacement", "ensure that functions can be properly replaced at runtime for non-indexed things") {
|
||||
struct heart_base_t {};
|
||||
struct heart_t : heart_base_t {
|
||||
void func() {
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("plain") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_simple_usertype<heart_t>("a");
|
||||
REQUIRE_NOTHROW([&lua]() {
|
||||
lua.safe_script("obj = a.new()");
|
||||
lua.safe_script("function a:heartbeat () print('arf') return 1 end");
|
||||
lua.safe_script("v1 = obj:heartbeat()");
|
||||
lua.safe_script("function a:heartbeat () print('bark') return 2 end");
|
||||
lua.safe_script("v2 = obj:heartbeat()");
|
||||
lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
|
||||
lua.safe_script("v3 = obj:heartbeat()");
|
||||
}());
|
||||
int v1 = lua["v1"];
|
||||
int v2 = lua["v2"];
|
||||
int v3 = lua["v3"];
|
||||
REQUIRE(v1 == 1);
|
||||
REQUIRE(v2 == 2);
|
||||
REQUIRE(v3 == 3);
|
||||
}
|
||||
SECTION("variables") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_simple_usertype<heart_t>("a",
|
||||
sol::base_classes, sol::bases<heart_base_t>());
|
||||
|
||||
REQUIRE_NOTHROW([&lua]() {
|
||||
lua.safe_script("obj = a.new()");
|
||||
lua.safe_script("function a:heartbeat () print('arf') return 1 end");
|
||||
lua.safe_script("v1 = obj:heartbeat()");
|
||||
lua.safe_script("function a:heartbeat () print('bark') return 2 end");
|
||||
lua.safe_script("v2 = obj:heartbeat()");
|
||||
lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
|
||||
lua.safe_script("v3 = obj:heartbeat()");
|
||||
}());
|
||||
int v1 = lua["v1"];
|
||||
int v2 = lua["v2"];
|
||||
int v3 = lua["v3"];
|
||||
REQUIRE(v1 == 1);
|
||||
REQUIRE(v2 == 2);
|
||||
REQUIRE(v3 == 3);
|
||||
}
|
||||
SECTION("methods") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_simple_usertype<heart_t>("a",
|
||||
"func", &heart_t::func,
|
||||
sol::base_classes, sol::bases<heart_base_t>());
|
||||
|
||||
REQUIRE_NOTHROW([&lua]() {
|
||||
lua.safe_script("obj = a.new()");
|
||||
lua.safe_script("function a:heartbeat () print('arf') return 1 end");
|
||||
lua.safe_script("v1 = obj:heartbeat()");
|
||||
lua.safe_script("function a:heartbeat () print('bark') return 2 end");
|
||||
lua.safe_script("v2 = obj:heartbeat()");
|
||||
lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
|
||||
lua.safe_script("v3 = obj:heartbeat()");
|
||||
}());
|
||||
int v1 = lua["v1"];
|
||||
int v2 = lua["v2"];
|
||||
int v3 = lua["v3"];
|
||||
REQUIRE(v1 == 1);
|
||||
REQUIRE(v2 == 2);
|
||||
REQUIRE(v3 == 3);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/runtime additions with newindex", "ensure that additions when new_index is overriden don't hit the specified new_index function") {
|
||||
class newindex_object {};
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_simple_usertype<newindex_object>("object",
|
||||
sol::meta_function::new_index, [](newindex_object& o, sol::object key, sol::object value) {
|
||||
return;
|
||||
});
|
||||
|
||||
lua["object"]["test"] = [](newindex_object& o) {
|
||||
std::cout << "test" << std::endl;
|
||||
return 446;
|
||||
};
|
||||
|
||||
auto result1 = lua.safe_script("o = object.new()", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
auto result2 = lua.safe_script("assert(o:test() == 446)", sol::script_pass_on_error);
|
||||
REQUIRE(result2.valid());
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/meta key retrievals", "allow for special meta keys (__index, __newindex) to trigger methods even if overwritten directly") {
|
||||
SECTION("dynamically") {
|
||||
static int writes = 0;
|
||||
static std::string keys[4] = {};
|
||||
static int values[4] = {};
|
||||
struct d_sample {
|
||||
void foo(std::string k, int v) {
|
||||
keys[writes] = k;
|
||||
values[writes] = v;
|
||||
++writes;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.new_simple_usertype<d_sample>("sample");
|
||||
sol::table s = lua["sample"]["new"]();
|
||||
s[sol::metatable_key][sol::meta_function::new_index] = &d_sample::foo;
|
||||
lua["var"] = s;
|
||||
|
||||
lua.safe_script("var = sample.new()");
|
||||
lua.safe_script("var.key = 2");
|
||||
lua.safe_script("var.__newindex = 4");
|
||||
lua.safe_script("var.__index = 3");
|
||||
lua.safe_script("var.__call = 1");
|
||||
REQUIRE(values[0] == 2);
|
||||
REQUIRE(values[1] == 4);
|
||||
REQUIRE(values[2] == 3);
|
||||
REQUIRE(values[3] == 1);
|
||||
REQUIRE(keys[0] == "key");
|
||||
REQUIRE(keys[1] == "__newindex");
|
||||
REQUIRE(keys[2] == "__index");
|
||||
REQUIRE(keys[3] == "__call");
|
||||
}
|
||||
|
||||
SECTION("statically") {
|
||||
static int writes = 0;
|
||||
static std::string keys[4] = {};
|
||||
static int values[4] = {};
|
||||
struct sample {
|
||||
void foo(std::string k, int v) {
|
||||
keys[writes] = k;
|
||||
values[writes] = v;
|
||||
++writes;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.new_simple_usertype<sample>("sample", sol::meta_function::new_index, &sample::foo);
|
||||
|
||||
lua.safe_script("var = sample.new()");
|
||||
lua.safe_script("var.key = 2");
|
||||
lua.safe_script("var.__newindex = 4");
|
||||
lua.safe_script("var.__index = 3");
|
||||
lua.safe_script("var.__call = 1");
|
||||
REQUIRE(values[0] == 2);
|
||||
REQUIRE(values[1] == 4);
|
||||
REQUIRE(values[2] == 3);
|
||||
REQUIRE(values[3] == 1);
|
||||
REQUIRE(keys[0] == "key");
|
||||
REQUIRE(keys[1] == "__newindex");
|
||||
REQUIRE(keys[2] == "__index");
|
||||
REQUIRE(keys[3] == "__call");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/static properties", "allow for static functions to get and set things as a property") {
|
||||
static int b = 50;
|
||||
struct test_t {
|
||||
static double s_func() {
|
||||
return b + 0.5;
|
||||
}
|
||||
|
||||
static void g_func(int v) {
|
||||
b = v;
|
||||
}
|
||||
|
||||
std::size_t func() {
|
||||
return 24;
|
||||
}
|
||||
};
|
||||
test_t manager;
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.new_simple_usertype<test_t>("test",
|
||||
"f", std::function<std::size_t()>(std::bind(std::mem_fn(&test_t::func), &manager)),
|
||||
"g", sol::property(&test_t::s_func, &test_t::g_func));
|
||||
|
||||
lua.safe_script("v1 = test.f()");
|
||||
lua.safe_script("v2 = test.g");
|
||||
lua.safe_script("test.g = 60");
|
||||
lua.safe_script("v2a = test.g");
|
||||
int v1 = lua["v1"];
|
||||
REQUIRE(v1 == 24);
|
||||
double v2 = lua["v2"];
|
||||
REQUIRE(v2 == 50.5);
|
||||
double v2a = lua["v2a"];
|
||||
REQUIRE(v2a == 60.5);
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/indexing", "make sure simple usertypes can be indexed/new_indexed properly without breaking") {
|
||||
static int val = 0;
|
||||
|
||||
class indexing_test {
|
||||
public:
|
||||
indexing_test() {
|
||||
val = 0;
|
||||
}
|
||||
|
||||
sol::object getter(const std::string& name, sol::this_state _s) {
|
||||
REQUIRE(name == "a");
|
||||
return sol::make_object(_s, 2);
|
||||
}
|
||||
|
||||
void setter(std::string name, sol::object n) {
|
||||
REQUIRE(name == "unknown");
|
||||
val = n.as<int>();
|
||||
}
|
||||
|
||||
int hi() {
|
||||
std::cout << "hi" << std::endl;
|
||||
return 25;
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("no runtime additions") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_simple_usertype<indexing_test>("test",
|
||||
sol::meta_function::index, &indexing_test::getter,
|
||||
sol::meta_function::new_index, &indexing_test::setter);
|
||||
|
||||
lua.safe_script(R"(
|
||||
local t = test.new()
|
||||
v = t.a
|
||||
print(v)
|
||||
t.unknown = 50
|
||||
)");
|
||||
int v = lua["v"];
|
||||
REQUIRE(v == 2);
|
||||
REQUIRE(val == 50);
|
||||
}
|
||||
SECTION("runtime additions") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_simple_usertype<indexing_test>("test",
|
||||
sol::meta_function::index, &indexing_test::getter,
|
||||
sol::meta_function::new_index, &indexing_test::setter);
|
||||
|
||||
lua["test"]["hi"] = [](indexing_test& _self) -> int { return _self.hi(); };
|
||||
|
||||
lua.safe_script(R"(
|
||||
local t = test.new()
|
||||
v = t.a;
|
||||
print(v)
|
||||
t.unknown = 50
|
||||
u = t:hi()
|
||||
)");
|
||||
int v = lua["v"];
|
||||
int u = lua["u"];
|
||||
REQUIRE(v == 2);
|
||||
REQUIRE(u == 25);
|
||||
REQUIRE(val == 50);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("simple_usertype/basic type information", "check that we can query some basic type information") {
|
||||
struct my_thing {};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_simple_usertype<my_thing>("my_thing");
|
||||
|
||||
lua.safe_script("obj = my_thing.new()");
|
||||
|
||||
lua.safe_script("assert(my_thing.__type.is(obj))");
|
||||
lua.safe_script("assert(not my_thing.__type.is(1))");
|
||||
lua.safe_script("assert(not my_thing.__type.is(\"not a thing\"))");
|
||||
lua.safe_script("print(my_thing.__type.name)");
|
||||
|
||||
lua.safe_script("assert(obj.__type.is(obj))");
|
||||
lua.safe_script("assert(not obj.__type.is(1))");
|
||||
lua.safe_script("assert(not obj.__type.is(\"not a thing\"))");
|
||||
lua.safe_script("print(obj.__type.name)");
|
||||
|
||||
lua.safe_script("assert(getmetatable(my_thing).__type.is(obj))");
|
||||
lua.safe_script("assert(not getmetatable(my_thing).__type.is(1))");
|
||||
lua.safe_script("assert(not getmetatable(my_thing).__type.is(\"not a thing\"))");
|
||||
lua.safe_script("print(getmetatable(my_thing).__type.name)");
|
||||
|
||||
lua.safe_script("assert(getmetatable(obj).__type.is(obj))");
|
||||
lua.safe_script("assert(not getmetatable(obj).__type.is(1))");
|
||||
lua.safe_script("assert(not getmetatable(obj).__type.is(\"not a thing\"))");
|
||||
lua.safe_script("print(getmetatable(obj).__type.name)");
|
||||
}
|
||||
Vendored
+67
@@ -0,0 +1,67 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef SOL_TEST_SOL_HPP
|
||||
#define SOL_TEST_SOL_HPP
|
||||
|
||||
#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
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef TEST_SINGLE
|
||||
#include <sol_forward.hpp>
|
||||
#endif // Single
|
||||
#include <sol.hpp>
|
||||
|
||||
struct 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) {
|
||||
begintop = lua_gettop(L);
|
||||
}
|
||||
|
||||
void check() {
|
||||
if (begintop != endtop) {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
~test_stack_guard() {
|
||||
endtop = lua_gettop(L);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SOL_TEST_SOL_HPP
|
||||
+706
@@ -0,0 +1,706 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
|
||||
template <typename Name, typename Data>
|
||||
void write_file_attempt(Name&& filename, Data&& data) {
|
||||
bool success = false;
|
||||
for (std::size_t i = 0; i < 20; ++i) {
|
||||
try {
|
||||
std::ofstream file(std::forward<Name>(filename), std::ios::out);
|
||||
file.exceptions(std::ios_base::badbit | std::ios_base::failbit);
|
||||
file << std::forward<Data>(data) << std::endl;
|
||||
file.close();
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
continue;
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
if (!success) {
|
||||
throw std::runtime_error("cannot open file or write out");
|
||||
}
|
||||
}
|
||||
|
||||
struct write_file_attempt_object {
|
||||
template <typename... Args>
|
||||
void operator()(Args&&... args) {
|
||||
write_file_attempt(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
struct string_reader_load {
|
||||
const std::string& str;
|
||||
std::size_t reads;
|
||||
|
||||
string_reader_load(const std::string& s)
|
||||
: str(s), reads(0) {
|
||||
}
|
||||
};
|
||||
|
||||
const char* string_reader(lua_State* L, void* vpstr, size_t* sz) {
|
||||
(void)L;
|
||||
string_reader_load& srl = *static_cast<string_reader_load*>(vpstr);
|
||||
if (srl.reads++ > 0) {
|
||||
*sz = 0;
|
||||
return NULL;
|
||||
}
|
||||
*sz = static_cast<size_t>(srl.str.size());
|
||||
return srl.str.c_str();
|
||||
}
|
||||
|
||||
TEST_CASE("state/require_file", "opening files as 'requires'") {
|
||||
static const char file_require_file[] = "./tmp_thingy.lua";
|
||||
static const char file_require_file_user[] = "./tmp_thingy_user.lua";
|
||||
static const char require_file_code[] = "return { modfunc = function () return 221 end }";
|
||||
static const char require_file_user_code[] = "return { modfunc = function () return foo.new(221) end }";
|
||||
static std::atomic<int> finished(0);
|
||||
static std::once_flag flag_file = {}, flag_file_user = {};
|
||||
std::call_once(flag_file, write_file_attempt_object(), file_require_file, require_file_code);
|
||||
std::call_once(flag_file_user, write_file_attempt_object(), file_require_file_user, require_file_user_code);
|
||||
|
||||
auto clean_files = []() {
|
||||
if (finished.fetch_add(1) < 1) {
|
||||
return;
|
||||
}
|
||||
std::remove(file_require_file);
|
||||
std::remove(file_require_file_user);
|
||||
};
|
||||
|
||||
SECTION("with usertypes") {
|
||||
struct foo {
|
||||
foo(int bar)
|
||||
: bar(bar) {
|
||||
}
|
||||
|
||||
const int bar;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<foo>("foo",
|
||||
sol::constructors<sol::types<int>>{},
|
||||
"bar", &foo::bar);
|
||||
|
||||
const sol::table thingy1 = lua.require_file("thingy", file_require_file_user);
|
||||
|
||||
REQUIRE(thingy1.valid());
|
||||
|
||||
const foo foo_v = thingy1["modfunc"]();
|
||||
|
||||
int val1 = foo_v.bar;
|
||||
|
||||
REQUIRE(val1 == 221);
|
||||
clean_files();
|
||||
}
|
||||
|
||||
SECTION("simple") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
const sol::table thingy1 = lua.require_file("thingy", file_require_file);
|
||||
const sol::table thingy2 = lua.require_file("thingy", file_require_file);
|
||||
|
||||
REQUIRE(thingy1.valid());
|
||||
REQUIRE(thingy2.valid());
|
||||
|
||||
int val1 = thingy1["modfunc"]();
|
||||
int val2 = thingy2["modfunc"]();
|
||||
|
||||
REQUIRE(val1 == 221);
|
||||
REQUIRE(val2 == 221);
|
||||
// must have loaded the same table
|
||||
REQUIRE((thingy1 == thingy2));
|
||||
clean_files();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("state/require_script", "opening strings as 'requires' clauses") {
|
||||
std::string code = "return { modfunc = function () return 221 end }";
|
||||
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
sol::table thingy1 = lua.require_script("thingy", code);
|
||||
sol::table thingy2 = lua.require_script("thingy", code);
|
||||
|
||||
int val1 = thingy1["modfunc"]();
|
||||
int val2 = thingy2["modfunc"]();
|
||||
REQUIRE(val1 == 221);
|
||||
REQUIRE(val2 == 221);
|
||||
// must have loaded the same table
|
||||
REQUIRE((thingy1 == thingy2));
|
||||
}
|
||||
|
||||
TEST_CASE("state/require", "require using a function") {
|
||||
struct open {
|
||||
static int open_func(lua_State* L) {
|
||||
sol::state_view lua = L;
|
||||
return sol::stack::push(L, lua.create_table_with("modfunc", sol::as_function([]() { return 221; })));
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
sol::table thingy1 = lua.require("thingy", open::open_func);
|
||||
sol::table thingy2 = lua.require("thingy", open::open_func);
|
||||
|
||||
int val1 = thingy1["modfunc"]();
|
||||
int val2 = thingy2["modfunc"]();
|
||||
REQUIRE(val1 == 221);
|
||||
REQUIRE(val2 == 221);
|
||||
// THIS IS ONLY REQUIRED IN LUA 5.3, FOR SOME REASON
|
||||
// must have loaded the same table
|
||||
// REQUIRE(thingy1 == thingy2);
|
||||
}
|
||||
|
||||
TEST_CASE("state/multi require", "make sure that requires transfers across hand-rolled script implementation and standard requiref") {
|
||||
struct open {
|
||||
static int open_func(lua_State* L) {
|
||||
sol::state_view lua = L;
|
||||
return sol::stack::push(L, lua.create_table_with("modfunc", sol::as_function([]() { return 221; })));
|
||||
}
|
||||
};
|
||||
|
||||
std::string code = "return { modfunc = function () return 221 end }";
|
||||
sol::state lua;
|
||||
sol::table thingy1 = lua.require("thingy", open::open_func);
|
||||
sol::table thingy2 = lua.require("thingy", open::open_func);
|
||||
sol::table thingy3 = lua.require_script("thingy", code);
|
||||
|
||||
int val1 = thingy1["modfunc"]();
|
||||
int val2 = thingy2["modfunc"]();
|
||||
int val3 = thingy3["modfunc"]();
|
||||
REQUIRE(val1 == 221);
|
||||
REQUIRE(val2 == 221);
|
||||
REQUIRE(val3 == 221);
|
||||
// must have loaded the same table
|
||||
// Lua is not obliged to give a shit. Thanks, Lua
|
||||
//REQUIRE(thingy1 == thingy2);
|
||||
// But we care, thankfully
|
||||
//REQUIRE(thingy1 == thingy3);
|
||||
REQUIRE((thingy2 == thingy3));
|
||||
}
|
||||
|
||||
TEST_CASE("state/require-safety", "make sure unrelated modules aren't harmed in using requires") {
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
std::string t1 = lua.safe_script(R"(require 'io'
|
||||
return 'test1')");
|
||||
sol::object ot2 = lua.require_script("test2", R"(require 'io'
|
||||
return 'test2')");
|
||||
std::string t2 = ot2.as<std::string>();
|
||||
std::string t3 = lua.safe_script(R"(require 'io'
|
||||
return 'test3')");
|
||||
REQUIRE(t1 == "test1");
|
||||
REQUIRE(t2 == "test2");
|
||||
REQUIRE(t3 == "test3");
|
||||
}
|
||||
|
||||
TEST_CASE("state/leak check", "make sure there are no humongous memory leaks in iteration") {
|
||||
#if 0
|
||||
sol::state lua;
|
||||
lua.safe_script(R"(
|
||||
record = {}
|
||||
for i=1,256 do
|
||||
record[i] = i
|
||||
end
|
||||
function run()
|
||||
for i=1,25000 do
|
||||
fun(record)
|
||||
end
|
||||
end
|
||||
function run2()
|
||||
for i=1,50000 do
|
||||
fun(record)
|
||||
end
|
||||
end
|
||||
)");
|
||||
|
||||
lua["fun"] = [](const sol::table &t) {
|
||||
//removing the for loop fixes the memory leak
|
||||
auto b = t.begin();
|
||||
auto e = t.end();
|
||||
for (; b != e; ++b) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
size_t beforewarmup = lua.memory_used();
|
||||
lua["run"]();
|
||||
|
||||
size_t beforerun = lua.memory_used();
|
||||
lua["run"]();
|
||||
size_t afterrun = lua.memory_used();
|
||||
lua["run2"]();
|
||||
size_t afterrun2 = lua.memory_used();
|
||||
|
||||
// Less memory used before the warmup
|
||||
REQUIRE(beforewarmup <= beforerun);
|
||||
// Iteration size and such does not bloat or affect memory
|
||||
// (these are weak checks but they'll warn us nonetheless if something goes wrong)
|
||||
REQUIRE(beforerun == afterrun);
|
||||
REQUIRE(afterrun == afterrun2);
|
||||
#else
|
||||
REQUIRE(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("state/script returns", "make sure script returns are done properly") {
|
||||
std::string script =
|
||||
R"(
|
||||
local example =
|
||||
{
|
||||
str = "this is a string",
|
||||
num = 1234,
|
||||
|
||||
func = function(self)
|
||||
print(self.str)
|
||||
return "fstr"
|
||||
end
|
||||
}
|
||||
|
||||
return example;
|
||||
)";
|
||||
|
||||
auto bar = [&script](sol::this_state l) {
|
||||
sol::state_view lua = l;
|
||||
sol::table data = lua.safe_script(script);
|
||||
|
||||
std::string str = data["str"];
|
||||
int num = data["num"];
|
||||
std::string fstr = data["func"](data);
|
||||
REQUIRE(str == "this is a string");
|
||||
REQUIRE(fstr == "fstr");
|
||||
REQUIRE(num == 1234);
|
||||
};
|
||||
|
||||
auto foo = [&script](int, sol::this_state l) {
|
||||
sol::state_view lua = l;
|
||||
sol::table data = lua.safe_script(script);
|
||||
|
||||
std::string str = data["str"];
|
||||
int num = data["num"];
|
||||
std::string fstr = data["func"](data);
|
||||
REQUIRE(str == "this is a string");
|
||||
REQUIRE(fstr == "fstr");
|
||||
REQUIRE(num == 1234);
|
||||
};
|
||||
|
||||
auto bar2 = [&script](sol::this_state l) {
|
||||
sol::state_view lua = l;
|
||||
sol::table data = lua.do_string(script);
|
||||
|
||||
std::string str = data["str"];
|
||||
int num = data["num"];
|
||||
std::string fstr = data["func"](data);
|
||||
REQUIRE(str == "this is a string");
|
||||
REQUIRE(fstr == "fstr");
|
||||
REQUIRE(num == 1234);
|
||||
};
|
||||
|
||||
auto foo2 = [&script](int, sol::this_state l) {
|
||||
sol::state_view lua = l;
|
||||
sol::table data = lua.do_string(script);
|
||||
|
||||
std::string str = data["str"];
|
||||
int num = data["num"];
|
||||
std::string fstr = data["func"](data);
|
||||
REQUIRE(str == "this is a string");
|
||||
REQUIRE(fstr == "fstr");
|
||||
REQUIRE(num == 1234);
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
lua.open_libraries();
|
||||
|
||||
lua.set_function("foo", foo);
|
||||
lua.set_function("foo2", foo2);
|
||||
lua.set_function("bar", bar);
|
||||
lua.set_function("bar2", bar2);
|
||||
|
||||
lua.safe_script("bar() bar2() foo(1) foo2(1)");
|
||||
}
|
||||
|
||||
TEST_CASE("state/copy and move", "ensure state can be properly copied and moved") {
|
||||
sol::state lua;
|
||||
lua["a"] = 1;
|
||||
|
||||
sol::state lua2(std::move(lua));
|
||||
int a2 = lua2["a"];
|
||||
REQUIRE(a2 == 1);
|
||||
lua = std::move(lua2);
|
||||
int a = lua["a"];
|
||||
REQUIRE(a == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("state/requires-reload", "ensure that reloading semantics do not cause a crash") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
lua.open_libraries();
|
||||
lua.safe_script("require 'io'\nreturn 'test1'");
|
||||
lua.require_script("test2", "require 'io'\nreturn 'test2'");
|
||||
lua.safe_script("require 'io'\nreturn 'test3'");
|
||||
}
|
||||
|
||||
TEST_CASE("state/script, do, and load", "test success and failure cases for loading and running scripts") {
|
||||
const static std::string bad_syntax = "weird\n%$@symb\nols";
|
||||
static const char file_bad_syntax[] = "./temp.bad_syntax.lua";
|
||||
const static std::string bad_runtime = "bad.code = 20";
|
||||
static const char file_bad_runtime[] = "./temp.bad_runtime.lua";
|
||||
const static std::string good = "a = 21\nreturn a";
|
||||
static const char file_good[] = "./temp.good.lua";
|
||||
static std::once_flag flag_file_bs = {}, flag_file_br = {}, flag_file_g = {};
|
||||
static std::atomic<int> finished(0);
|
||||
std::call_once(flag_file_bs, write_file_attempt_object(), file_bad_syntax, bad_syntax);
|
||||
std::call_once(flag_file_br, write_file_attempt_object(), file_bad_runtime, bad_runtime);
|
||||
std::call_once(flag_file_g, write_file_attempt_object(), file_good, good);
|
||||
|
||||
auto clean_files = []() {
|
||||
if (finished.fetch_add(1) < 14) {
|
||||
return;
|
||||
}
|
||||
std::remove(file_bad_syntax);
|
||||
std::remove(file_bad_runtime);
|
||||
std::remove(file_good);
|
||||
};
|
||||
|
||||
SECTION("script") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
int ar = lua.safe_script(good);
|
||||
int a = lua["a"];
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("unsafe_script") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
int ar = lua.unsafe_script(good);
|
||||
int a = lua["a"];
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("script-handler") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
auto errbs = lua.safe_script(bad_syntax, sol::script_pass_on_error);
|
||||
REQUIRE(!errbs.valid());
|
||||
|
||||
auto errbr = lua.safe_script(bad_runtime, sol::script_pass_on_error);
|
||||
REQUIRE(!errbr.valid());
|
||||
|
||||
auto result = lua.safe_script(good, sol::script_pass_on_error);
|
||||
int a = lua["a"];
|
||||
int ar = result;
|
||||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("do_string") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
auto errbs = lua.do_string(bad_syntax);
|
||||
REQUIRE(!errbs.valid());
|
||||
|
||||
auto errbr = lua.do_string(bad_runtime);
|
||||
REQUIRE(!errbr.valid());
|
||||
|
||||
auto result = lua.do_string(good);
|
||||
int a = lua["a"];
|
||||
int ar = result;
|
||||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("load_string") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
auto errbsload = lua.load(bad_syntax);
|
||||
REQUIRE(!errbsload.valid());
|
||||
|
||||
sol::load_result errbrload = lua.load(bad_runtime);
|
||||
REQUIRE(errbrload.valid());
|
||||
sol::protected_function errbrpf = errbrload;
|
||||
auto errbr = errbrpf();
|
||||
REQUIRE(!errbr.valid());
|
||||
|
||||
sol::load_result resultload = lua.load(good);
|
||||
REQUIRE(resultload.valid());
|
||||
sol::protected_function resultpf = resultload;
|
||||
auto result = resultpf();
|
||||
int a = lua["a"];
|
||||
int ar = result;
|
||||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("load") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
string_reader_load bssrl(bad_syntax);
|
||||
void* vpbssrl = static_cast<void*>(&bssrl);
|
||||
auto errbsload = lua.load(&string_reader, vpbssrl, bad_syntax);
|
||||
REQUIRE(!errbsload.valid());
|
||||
|
||||
string_reader_load brsrl(bad_runtime);
|
||||
void* vpbrsrl = static_cast<void*>(&brsrl);
|
||||
sol::load_result errbrload = lua.load(&string_reader, vpbrsrl, bad_runtime);
|
||||
REQUIRE(errbrload.valid());
|
||||
sol::protected_function errbrpf = errbrload;
|
||||
auto errbr = errbrpf();
|
||||
REQUIRE(!errbr.valid());
|
||||
|
||||
string_reader_load gsrl(good);
|
||||
void* vpgsrl = static_cast<void*>(&gsrl);
|
||||
sol::load_result resultload = lua.load(&string_reader, vpgsrl, good);
|
||||
REQUIRE(resultload.valid());
|
||||
sol::protected_function resultpf = resultload;
|
||||
auto result = resultpf();
|
||||
int a = lua["a"];
|
||||
int ar = result;
|
||||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("load_string (text)") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
auto errbsload = lua.load(bad_syntax, bad_syntax, sol::load_mode::text);
|
||||
REQUIRE(!errbsload.valid());
|
||||
|
||||
sol::load_result errbrload = lua.load(bad_runtime, bad_runtime, sol::load_mode::text);
|
||||
REQUIRE(errbrload.valid());
|
||||
sol::protected_function errbrpf = errbrload;
|
||||
auto errbr = errbrpf();
|
||||
REQUIRE(!errbr.valid());
|
||||
|
||||
sol::load_result resultload = lua.load(good, good, sol::load_mode::text);
|
||||
REQUIRE(resultload.valid());
|
||||
sol::protected_function resultpf = resultload;
|
||||
auto result = resultpf();
|
||||
int a = lua["a"];
|
||||
int ar = result;
|
||||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("load (text)") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
string_reader_load bssrl(bad_syntax);
|
||||
void* vpbssrl = static_cast<void*>(&bssrl);
|
||||
auto errbsload = lua.load(&string_reader, vpbssrl, bad_syntax, sol::load_mode::text);
|
||||
REQUIRE(!errbsload.valid());
|
||||
|
||||
string_reader_load brsrl(bad_runtime);
|
||||
void* vpbrsrl = static_cast<void*>(&brsrl);
|
||||
sol::load_result errbrload = lua.load(&string_reader, vpbrsrl, bad_runtime, sol::load_mode::text);
|
||||
REQUIRE(errbrload.valid());
|
||||
sol::protected_function errbrpf = errbrload;
|
||||
auto errbr = errbrpf();
|
||||
REQUIRE(!errbr.valid());
|
||||
|
||||
string_reader_load gsrl(good);
|
||||
void* vpgsrl = static_cast<void*>(&gsrl);
|
||||
sol::load_result resultload = lua.load(&string_reader, vpgsrl, good, sol::load_mode::text);
|
||||
REQUIRE(resultload.valid());
|
||||
sol::protected_function resultpf = resultload;
|
||||
auto result = resultpf();
|
||||
int a = lua["a"];
|
||||
int ar = result;
|
||||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("script_file") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
int ar = lua.safe_script_file(file_good);
|
||||
int a = lua["a"];
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("unsafe_script_file") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
int ar = lua.unsafe_script_file(file_good);
|
||||
int a = lua["a"];
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("script_file-handler") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
auto errbs = lua.safe_script_file(file_bad_syntax, sol::script_pass_on_error);
|
||||
REQUIRE(!errbs.valid());
|
||||
|
||||
auto errbr = lua.safe_script_file(file_bad_runtime, sol::script_pass_on_error);
|
||||
REQUIRE(!errbr.valid());
|
||||
|
||||
auto result = lua.safe_script_file(file_good, sol::script_pass_on_error);
|
||||
int a = lua["a"];
|
||||
int ar = result;
|
||||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("safe_script_file-handler") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
auto errbs = lua.safe_script_file(file_bad_syntax, sol::script_pass_on_error);
|
||||
REQUIRE(!errbs.valid());
|
||||
|
||||
auto errbr = lua.safe_script_file(file_bad_runtime, sol::script_pass_on_error);
|
||||
REQUIRE(!errbr.valid());
|
||||
|
||||
auto result = lua.safe_script_file(file_good, sol::script_pass_on_error);
|
||||
int a = lua["a"];
|
||||
int ar = result;
|
||||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("do_file") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
auto errbs = lua.do_file(file_bad_syntax);
|
||||
REQUIRE(!errbs.valid());
|
||||
|
||||
auto errbr = lua.do_file(file_bad_runtime);
|
||||
REQUIRE(!errbr.valid());
|
||||
|
||||
auto result = lua.do_file(file_good);
|
||||
int a = lua["a"];
|
||||
int ar = result;
|
||||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("load_file") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
auto errbsload = lua.load_file(file_bad_syntax);
|
||||
REQUIRE(!errbsload.valid());
|
||||
|
||||
sol::load_result errbrload = lua.load_file(file_bad_runtime);
|
||||
REQUIRE(errbrload.valid());
|
||||
sol::protected_function errbrpf = errbrload;
|
||||
auto errbr = errbrpf();
|
||||
REQUIRE(!errbr.valid());
|
||||
|
||||
sol::load_result resultload = lua.load_file(file_good);
|
||||
REQUIRE(resultload.valid());
|
||||
sol::protected_function resultpf = resultload;
|
||||
auto result = resultpf();
|
||||
int a = lua["a"];
|
||||
int ar = result;
|
||||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("load_file (text)") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
auto errbsload = lua.load_file(file_bad_syntax, sol::load_mode::text);
|
||||
REQUIRE(!errbsload.valid());
|
||||
|
||||
sol::load_result errbrload = lua.load_file(file_bad_runtime, sol::load_mode::text);
|
||||
REQUIRE(errbrload.valid());
|
||||
sol::protected_function errbrpf = errbrload;
|
||||
auto errbr = errbrpf();
|
||||
REQUIRE(!errbr.valid());
|
||||
|
||||
sol::load_result resultload = lua.load_file(file_good, sol::load_mode::text);
|
||||
REQUIRE(resultload.valid());
|
||||
sol::protected_function resultpf = resultload;
|
||||
auto result = resultpf();
|
||||
int a = lua["a"];
|
||||
int ar = result;
|
||||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("state/script return converts", "make sure that script return values are convertable from one to another") {
|
||||
sol::state lua;
|
||||
|
||||
sol::protected_function_result r1 = lua.unsafe_script("return 2");
|
||||
sol::unsafe_function_result r2 = lua.safe_script("return 3");
|
||||
|
||||
int v1 = r1;
|
||||
int v2 = r2;
|
||||
REQUIRE(v1 == 2);
|
||||
REQUIRE(v2 == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("state/script function returns", "make sure that returned functions are converitble from a result to a function") {
|
||||
SECTION("from result move constructor") {
|
||||
sol::state lua;
|
||||
|
||||
sol::protected_function pf = lua.safe_script("return function () return 2 end", sol::script_pass_on_error);
|
||||
REQUIRE(pf.valid());
|
||||
|
||||
int v1 = pf();
|
||||
REQUIRE(v1 == 2);
|
||||
}
|
||||
SECTION("from result operator=") {
|
||||
sol::state lua;
|
||||
|
||||
sol::protected_function_result r1 = lua.safe_script("return function () return 1 end", sol::script_pass_on_error);
|
||||
REQUIRE(r1.valid());
|
||||
|
||||
sol::protected_function pf = r1;
|
||||
int v1 = pf();
|
||||
REQUIRE(v1 == 1);
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#define SOL_ENABLE_INTEROP 1
|
||||
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("storage/registry construction", "ensure entries from the registry can be retrieved") {
|
||||
const auto& code = R"(
|
||||
function f()
|
||||
return 2
|
||||
end
|
||||
)";
|
||||
|
||||
sol::state lua;
|
||||
{
|
||||
auto r = lua.safe_script(code, sol::script_pass_on_error);
|
||||
REQUIRE(r.valid());
|
||||
}
|
||||
sol::function f = lua["f"];
|
||||
sol::reference r = lua["f"];
|
||||
sol::function regf(lua, f);
|
||||
sol::reference regr(lua, sol::ref_index(f.registry_index()));
|
||||
bool isequal = f == r;
|
||||
REQUIRE(isequal);
|
||||
isequal = f == regf;
|
||||
REQUIRE(isequal);
|
||||
isequal = f == regr;
|
||||
REQUIRE(isequal);
|
||||
}
|
||||
|
||||
TEST_CASE("storage/registry construction empty", "ensure entries from the registry can be retrieved") {
|
||||
sol::state lua;
|
||||
sol::function f = lua["f"];
|
||||
sol::reference r = lua["f"];
|
||||
sol::function regf(lua, f);
|
||||
sol::reference regr(lua, sol::ref_index(f.registry_index()));
|
||||
bool isequal = f == r;
|
||||
REQUIRE(isequal);
|
||||
isequal = f == regf;
|
||||
REQUIRE(isequal);
|
||||
isequal = f == regr;
|
||||
REQUIRE(isequal);
|
||||
}
|
||||
|
||||
TEST_CASE("storage/main thread", "ensure round-tripping and pulling out thread data even on 5.1 with a backup works") {
|
||||
sol::state lua;
|
||||
{
|
||||
sol::stack_guard g(lua);
|
||||
lua_State* orig = lua;
|
||||
lua_State* ts = sol::main_thread(lua, lua);
|
||||
REQUIRE(ts == orig);
|
||||
}
|
||||
{
|
||||
sol::stack_guard g(lua);
|
||||
lua_State* orig = lua;
|
||||
lua_State* ts = sol::main_thread(lua);
|
||||
REQUIRE(ts == orig);
|
||||
}
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
struct test {};
|
||||
template <typename T>
|
||||
struct test_t {};
|
||||
|
||||
namespace muh_namespace {
|
||||
struct ns_test {};
|
||||
|
||||
namespace {
|
||||
struct ns_anon_test {};
|
||||
} // namespace
|
||||
} // namespace muh_namespace
|
||||
|
||||
TEST_CASE("stack/strings", "test that strings can be roundtripped") {
|
||||
sol::state lua;
|
||||
|
||||
static const char utf8str[] = "\xF0\x9F\x8D\x8C\x20\xE6\x99\xA5\x20\x46\x6F\x6F\x20\xC2\xA9\x20\x62\x61\x72\x20\xF0\x9D\x8C\x86\x20\x62\x61\x7A\x20\xE2\x98\x83\x20\x71\x75\x78";
|
||||
static const char16_t utf16str[] = { 0xD83C, 0xDF4C, 0x20, 0x6665, 0x20, 0x46, 0x6F, 0x6F, 0x20, 0xA9, 0x20, 0x62, 0x61, 0x72, 0x20, 0xD834, 0xDF06, 0x20, 0x62, 0x61, 0x7A, 0x20, 0x2603, 0x20, 0x71, 0x75, 0x78, 0x00 };
|
||||
static const char32_t utf32str[] = { 0x1F34C, 0x0020, 0x6665, 0x0020, 0x0046, 0x006F, 0x006F, 0x0020, 0x00A9, 0x0020, 0x0062, 0x0061, 0x0072, 0x0020, 0x1D306, 0x0020, 0x0062, 0x0061, 0x007A, 0x0020, 0x2603, 0x0020, 0x0071, 0x0075, 0x0078, 0x00 };
|
||||
#ifdef _WIN32
|
||||
INFO("win32 widestr");
|
||||
static const wchar_t widestr[] = { 0xD83C, 0xDF4C, 0x20, 0x6665, 0x20, 0x46, 0x6F, 0x6F, 0x20, 0xA9, 0x20, 0x62, 0x61, 0x72, 0x20, 0xD834, 0xDF06, 0x20, 0x62, 0x61, 0x7A, 0x20, 0x2603, 0x20, 0x71, 0x75, 0x78, 0x00 };
|
||||
#else
|
||||
INFO("non-windows widestr");
|
||||
static const wchar_t widestr[] = { 0x1F34C, 0x0020, 0x6665, 0x0020, 0x0046, 0x006F, 0x006F, 0x0020, 0x00A9, 0x0020, 0x0062, 0x0061, 0x0072, 0x0020, 0x1D306, 0x0020, 0x0062, 0x0061, 0x007A, 0x0020, 0x2603, 0x0020, 0x0071, 0x0075, 0x0078, 0x00 };
|
||||
#endif
|
||||
static const std::string utf8str_s = utf8str;
|
||||
static const std::u16string utf16str_s = utf16str;
|
||||
static const std::u32string utf32str_s = utf32str;
|
||||
static const std::wstring widestr_s = widestr;
|
||||
|
||||
INFO("sizeof(wchar_t): " << sizeof(wchar_t));
|
||||
INFO("sizeof(char16_t): " << sizeof(char16_t));
|
||||
INFO("sizeof(char32_t): " << sizeof(char32_t));
|
||||
INFO("utf8str: " << utf8str);
|
||||
INFO("utf8str_s: " << utf8str_s);
|
||||
|
||||
lua["utf8"] = utf8str;
|
||||
lua["utf16"] = utf16str;
|
||||
lua["utf32"] = utf32str;
|
||||
lua["wide"] = widestr;
|
||||
|
||||
std::string utf8_to_utf8 = lua["utf8"];
|
||||
std::string utf16_to_utf8 = lua["utf16"];
|
||||
std::string utf32_to_utf8 = lua["utf32"];
|
||||
std::string wide_to_utf8 = lua["wide"];
|
||||
|
||||
REQUIRE(utf8_to_utf8 == utf8str_s);
|
||||
REQUIRE(utf16_to_utf8 == utf8str_s);
|
||||
REQUIRE(utf32_to_utf8 == utf8str_s);
|
||||
REQUIRE(wide_to_utf8 == utf8str_s);
|
||||
|
||||
std::wstring utf8_to_wide = lua["utf8"];
|
||||
std::wstring utf16_to_wide = lua["utf16"];
|
||||
std::wstring utf32_to_wide = lua["utf32"];
|
||||
std::wstring wide_to_wide = lua["wide"];
|
||||
|
||||
REQUIRE(utf8_to_wide == widestr_s);
|
||||
REQUIRE(utf16_to_wide == widestr_s);
|
||||
REQUIRE(utf32_to_wide == widestr_s);
|
||||
REQUIRE(wide_to_wide == widestr_s);
|
||||
|
||||
std::u16string utf8_to_utf16 = lua["utf8"];
|
||||
std::u16string utf16_to_utf16 = lua["utf16"];
|
||||
std::u16string utf32_to_utf16 = lua["utf32"];
|
||||
std::u16string wide_to_utf16 = lua["wide"];
|
||||
|
||||
REQUIRE(utf8_to_utf16 == utf16str_s);
|
||||
REQUIRE(utf16_to_utf16 == utf16str_s);
|
||||
REQUIRE(utf32_to_utf16 == utf16str_s);
|
||||
REQUIRE(wide_to_utf16 == utf16str_s);
|
||||
|
||||
std::u32string utf8_to_utf32 = lua["utf8"];
|
||||
std::u32string utf16_to_utf32 = lua["utf16"];
|
||||
std::u32string utf32_to_utf32 = lua["utf32"];
|
||||
std::u32string wide_to_utf32 = lua["wide"];
|
||||
|
||||
REQUIRE(utf8_to_utf32 == utf32str_s);
|
||||
REQUIRE(utf16_to_utf32 == utf32str_s);
|
||||
REQUIRE(utf32_to_utf32 == utf32str_s);
|
||||
REQUIRE(wide_to_utf32 == utf32str_s);
|
||||
|
||||
char32_t utf8_to_char32 = lua["utf8"];
|
||||
char32_t utf16_to_char32 = lua["utf16"];
|
||||
char32_t utf32_to_char32 = lua["utf32"];
|
||||
char32_t wide_to_char32 = lua["wide"];
|
||||
|
||||
REQUIRE(utf8_to_char32 == utf32str[0]);
|
||||
REQUIRE(utf16_to_char32 == utf32str[0]);
|
||||
REQUIRE(utf32_to_char32 == utf32str[0]);
|
||||
REQUIRE(wide_to_char32 == utf32str[0]);
|
||||
|
||||
char16_t utf8_to_char16 = lua["utf8"];
|
||||
char16_t utf16_to_char16 = lua["utf16"];
|
||||
char16_t utf32_to_char16 = lua["utf32"];
|
||||
char16_t wide_to_char16 = lua["wide"];
|
||||
|
||||
REQUIRE(utf8_to_char16 == utf16str[0]);
|
||||
REQUIRE(utf16_to_char16 == utf16str[0]);
|
||||
REQUIRE(utf32_to_char16 == utf16str[0]);
|
||||
REQUIRE(wide_to_char16 == utf16str[0]);
|
||||
}
|
||||
|
||||
TEST_CASE("detail/demangling", "test some basic demangling cases") {
|
||||
std::string teststr = sol::detail::short_demangle<test>();
|
||||
std::string nsteststr = sol::detail::short_demangle<muh_namespace::ns_test>();
|
||||
std::string nsateststr = sol::detail::short_demangle<muh_namespace::ns_anon_test>();
|
||||
|
||||
REQUIRE(teststr == "test");
|
||||
REQUIRE(nsteststr == "ns_test");
|
||||
REQUIRE(nsateststr == "ns_anon_test");
|
||||
}
|
||||
|
||||
TEST_CASE("object/string-pushers", "test some basic string pushers with in_place constructor") {
|
||||
sol::state lua;
|
||||
|
||||
sol::object ocs(lua, sol::in_place, "bark\0bark", 9);
|
||||
sol::object os(lua, sol::in_place_type<std::string>, std::string("bark\0bark", 9), 8);
|
||||
sol::object osv(lua, sol::in_place_type<sol::string_view>, sol::string_view("woofwoof", 8), 8);
|
||||
bool test1 = ocs.as<std::string>() == std::string("bark\0bark", 9);
|
||||
bool test2 = os.as<std::string>() == std::string("bark\0bar", 8);
|
||||
bool test3 = osv.as<std::string>() == std::string("woofwoof", 8);
|
||||
REQUIRE(ocs.get_type() == sol::type::string);
|
||||
REQUIRE(ocs.is<std::string>());
|
||||
REQUIRE(ocs.is<sol::string_view>());
|
||||
|
||||
REQUIRE(os.get_type() == sol::type::string);
|
||||
REQUIRE(os.is<std::string>());
|
||||
REQUIRE(os.is<sol::string_view>());
|
||||
|
||||
REQUIRE(osv.get_type() == sol::type::string);
|
||||
REQUIRE(osv.is<std::string>());
|
||||
REQUIRE(osv.is<sol::string_view>());
|
||||
|
||||
REQUIRE(test1);
|
||||
REQUIRE(test2);
|
||||
REQUIRE(test3);
|
||||
}
|
||||
|
||||
TEST_CASE("strings/non const c strings", "push non const qualified c strings as strings") {
|
||||
sol::state lua;
|
||||
|
||||
char cbark[] = "bark";
|
||||
char* bark = cbark;
|
||||
lua["bark"] = bark;
|
||||
sol::type t = lua["bark"].get_type();
|
||||
std::string lbark = lua["bark"];
|
||||
|
||||
REQUIRE((t == sol::type::string));
|
||||
REQUIRE((bark == std::string("bark")));
|
||||
}
|
||||
+638
@@ -0,0 +1,638 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
std::string free_function() {
|
||||
INFO("free_function()");
|
||||
return "test";
|
||||
}
|
||||
|
||||
struct object {
|
||||
std::string operator()() {
|
||||
INFO("member_test()");
|
||||
return "test";
|
||||
}
|
||||
};
|
||||
|
||||
int plop_xyz(int x, int y, std::string z) {
|
||||
INFO(x << " " << y << " " << z);
|
||||
return 11;
|
||||
}
|
||||
|
||||
TEST_CASE("tables/as enums", "Making sure enums can be put in and gotten out as values") {
|
||||
enum direction {
|
||||
up,
|
||||
down,
|
||||
left,
|
||||
right
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua["direction"] = lua.create_table_with(
|
||||
"up", direction::up,
|
||||
"down", direction::down,
|
||||
"left", direction::left,
|
||||
"right", direction::right);
|
||||
|
||||
sol::object obj = lua["direction"]["up"];
|
||||
bool isdir = obj.is<direction>();
|
||||
REQUIRE(isdir);
|
||||
auto dir = obj.as<direction>();
|
||||
REQUIRE(dir == direction::up);
|
||||
}
|
||||
|
||||
TEST_CASE("tables/as enum classes", "Making sure enums can be put in and gotten out as values") {
|
||||
enum class direction {
|
||||
up,
|
||||
down,
|
||||
left,
|
||||
right
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua["direction"] = lua.create_table_with(
|
||||
"up", direction::up,
|
||||
"down", direction::down,
|
||||
"left", direction::left,
|
||||
"right", direction::right);
|
||||
|
||||
sol::object obj = lua["direction"]["up"];
|
||||
bool isdir = obj.is<direction>();
|
||||
REQUIRE(isdir);
|
||||
auto dir = obj.as<direction>();
|
||||
REQUIRE(dir == direction::up);
|
||||
}
|
||||
|
||||
TEST_CASE("tables/cleanup", "make sure tables leave the stack balanced") {
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
auto f = [] { return 5; };
|
||||
for (int i = 0; i < 30; i++) {
|
||||
std::string name = std::string("init") + std::to_string(i);
|
||||
int top = lua_gettop(lua);
|
||||
lua[name] = f;
|
||||
int aftertop = lua_gettop(lua);
|
||||
REQUIRE(aftertop == top);
|
||||
int val = lua[name]();
|
||||
REQUIRE(val == 5);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("tables/nested cleanup", "make sure tables leave the stack balanced") {
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
lua.safe_script("A={}");
|
||||
auto f = [] { return 5; };
|
||||
for (int i = 0; i < 30; i++) {
|
||||
std::string name = std::string("init") + std::to_string(i);
|
||||
int top = lua_gettop(lua);
|
||||
auto A = lua["A"];
|
||||
int beforetop = lua_gettop(lua);
|
||||
REQUIRE(beforetop == top);
|
||||
A[name] = f;
|
||||
int aftertop = lua_gettop(lua);
|
||||
REQUIRE(aftertop == top);
|
||||
int val = A[name]();
|
||||
REQUIRE(val == 5);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("tables/new_enum", "Making sure enums can be put in and gotten out as values") {
|
||||
enum class direction {
|
||||
up,
|
||||
down,
|
||||
left,
|
||||
right
|
||||
};
|
||||
|
||||
SECTION("variadics") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_enum("direction",
|
||||
"up", direction::up,
|
||||
"down", direction::down,
|
||||
"left", direction::left,
|
||||
"right", direction::right);
|
||||
|
||||
direction d = lua["direction"]["left"];
|
||||
REQUIRE(d == direction::left);
|
||||
auto result = lua.safe_script("direction.left = 50", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
d = lua["direction"]["left"];
|
||||
REQUIRE(d == direction::left);
|
||||
}
|
||||
SECTION("initializer_list") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_enum<direction>("direction", { { "up", direction::up }, { "down", direction::down }, { "left", direction::left }, { "right", direction::right } });
|
||||
|
||||
direction d = lua["direction"]["left"];
|
||||
REQUIRE(d == direction::left);
|
||||
auto result = lua.safe_script("direction.left = 50", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
d = lua["direction"]["left"];
|
||||
REQUIRE(d == direction::left);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("tables/for_each", "Testing the use of for_each to get values from a lua table") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.safe_script(
|
||||
"arr = {\n"
|
||||
"[0] = \"Hi\",\n"
|
||||
"[1] = 123.45,\n"
|
||||
"[2] = \"String value\",\n"
|
||||
// Does nothing
|
||||
//"[3] = nil,\n"
|
||||
//"[nil] = 3,\n"
|
||||
"[\"WOOF\"] = 123,\n"
|
||||
"}");
|
||||
sol::table tbl = lua["arr"];
|
||||
std::size_t tablesize = 4;
|
||||
std::size_t iterations = 0;
|
||||
auto fx = [&iterations](sol::object key, sol::object value) {
|
||||
++iterations;
|
||||
sol::type keytype = key.get_type();
|
||||
switch (keytype) {
|
||||
case sol::type::number:
|
||||
switch (key.as<int>()) {
|
||||
case 0:
|
||||
REQUIRE((value.as<std::string>() == "Hi"));
|
||||
break;
|
||||
case 1:
|
||||
REQUIRE((value.as<double>() == 123.45));
|
||||
break;
|
||||
case 2:
|
||||
REQUIRE((value.as<std::string>() == "String value"));
|
||||
break;
|
||||
case 3:
|
||||
REQUIRE((value.is<sol::lua_nil_t>()));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case sol::type::string:
|
||||
if (key.as<std::string>() == "WOOF") {
|
||||
REQUIRE((value.as<double>() == 123));
|
||||
}
|
||||
break;
|
||||
case sol::type::lua_nil:
|
||||
REQUIRE((value.as<double>() == 3));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
auto fxpair = [&fx](std::pair<sol::object, sol::object> kvp) { fx(kvp.first, kvp.second); };
|
||||
tbl.for_each(fx);
|
||||
REQUIRE(iterations == tablesize);
|
||||
|
||||
iterations = 0;
|
||||
tbl.for_each(fxpair);
|
||||
REQUIRE(iterations == tablesize);
|
||||
}
|
||||
|
||||
TEST_CASE("tables/for_each empty", "empty tables should not crash") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.safe_script("arr = {}");
|
||||
sol::table tbl = lua["arr"];
|
||||
REQUIRE(tbl.empty());
|
||||
std::size_t tablesize = 0;
|
||||
std::size_t iterations = 0;
|
||||
auto fx = [&iterations](sol::object key, sol::object value) {
|
||||
++iterations;
|
||||
sol::type keytype = key.get_type();
|
||||
switch (keytype) {
|
||||
case sol::type::number:
|
||||
switch (key.as<int>()) {
|
||||
case 0:
|
||||
REQUIRE((value.as<std::string>() == "Hi"));
|
||||
break;
|
||||
case 1:
|
||||
REQUIRE((value.as<double>() == 123.45));
|
||||
break;
|
||||
case 2:
|
||||
REQUIRE((value.as<std::string>() == "String value"));
|
||||
break;
|
||||
case 3:
|
||||
REQUIRE((value.is<sol::lua_nil_t>()));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case sol::type::string:
|
||||
if (key.as<std::string>() == "WOOF") {
|
||||
REQUIRE((value.as<double>() == 123));
|
||||
}
|
||||
break;
|
||||
case sol::type::lua_nil:
|
||||
REQUIRE((value.as<double>() == 3));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
auto fxpair = [&fx](std::pair<sol::object, sol::object> kvp) { fx(kvp.first, kvp.second); };
|
||||
tbl.for_each(fx);
|
||||
REQUIRE(iterations == tablesize);
|
||||
|
||||
iterations = 0;
|
||||
tbl.for_each(fxpair);
|
||||
REQUIRE(iterations == tablesize);
|
||||
|
||||
iterations = 0;
|
||||
for (const auto& kvp : tbl) {
|
||||
fxpair(kvp);
|
||||
++iterations;
|
||||
}
|
||||
REQUIRE(iterations == tablesize);
|
||||
}
|
||||
|
||||
TEST_CASE("tables/iterators", "Testing the use of iteratrs to get values from a lua table") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.safe_script(
|
||||
"arr = {\n"
|
||||
"[0] = \"Hi\",\n"
|
||||
"[1] = 123.45,\n"
|
||||
"[2] = \"String value\",\n"
|
||||
// Does nothing
|
||||
//"[3] = nil,\n"
|
||||
//"[nil] = 3,\n"
|
||||
"[\"WOOF\"] = 123,\n"
|
||||
"}");
|
||||
sol::table tbl = lua["arr"];
|
||||
std::size_t tablesize = 4;
|
||||
std::size_t iterations = 0;
|
||||
|
||||
int begintop = 0;
|
||||
int endtop = 0;
|
||||
{
|
||||
test_stack_guard s(lua.lua_state(), begintop, endtop);
|
||||
for (auto& kvp : tbl) {
|
||||
[&iterations](sol::object key, sol::object value) {
|
||||
++iterations;
|
||||
sol::type keytype = key.get_type();
|
||||
switch (keytype) {
|
||||
case sol::type::number:
|
||||
switch (key.as<int>()) {
|
||||
case 0:
|
||||
REQUIRE((value.as<std::string>() == "Hi"));
|
||||
break;
|
||||
case 1:
|
||||
REQUIRE((value.as<double>() == 123.45));
|
||||
break;
|
||||
case 2:
|
||||
REQUIRE((value.as<std::string>() == "String value"));
|
||||
break;
|
||||
case 3:
|
||||
REQUIRE((value.is<sol::lua_nil_t>()));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case sol::type::string:
|
||||
if (key.as<std::string>() == "WOOF") {
|
||||
REQUIRE((value.as<double>() == 123));
|
||||
}
|
||||
break;
|
||||
case sol::type::lua_nil:
|
||||
REQUIRE((value.as<double>() == 3));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}(kvp.first, kvp.second);
|
||||
}
|
||||
}
|
||||
REQUIRE(begintop == endtop);
|
||||
REQUIRE(iterations == tablesize);
|
||||
}
|
||||
|
||||
TEST_CASE("tables/variables", "Check if tables and variables work as intended") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::os);
|
||||
lua.get<sol::table>("os").set("name", "windows");
|
||||
{
|
||||
auto result = lua.safe_script("assert(os.name == \"windows\")", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("tables/create", "Check if creating a table is kosher") {
|
||||
sol::state lua;
|
||||
lua["testtable"] = sol::table::create(lua.lua_state(), 0, 0, "Woof", "Bark", 1, 2, 3, 4);
|
||||
sol::object testobj = lua["testtable"];
|
||||
REQUIRE(testobj.is<sol::table>());
|
||||
sol::table testtable = testobj.as<sol::table>();
|
||||
REQUIRE((testtable["Woof"] == std::string("Bark")));
|
||||
REQUIRE((testtable[1] == 2));
|
||||
REQUIRE((testtable[3] == 4));
|
||||
}
|
||||
|
||||
TEST_CASE("tables/create local", "Check if creating a table is kosher") {
|
||||
sol::state lua;
|
||||
lua["testtable"] = lua.create_table(0, 0, "Woof", "Bark", 1, 2, 3, 4);
|
||||
sol::object testobj = lua["testtable"];
|
||||
REQUIRE(testobj.is<sol::table>());
|
||||
sol::table testtable = testobj.as<sol::table>();
|
||||
REQUIRE((testtable["Woof"] == std::string("Bark")));
|
||||
REQUIRE((testtable[1] == 2));
|
||||
REQUIRE((testtable[3] == 4));
|
||||
}
|
||||
|
||||
TEST_CASE("tables/create local named", "Check if creating a table is kosher") {
|
||||
sol::state lua;
|
||||
sol::table testtable = lua.create_table("testtable", 0, 0, "Woof", "Bark", 1, 2, 3, 4);
|
||||
sol::object testobj = lua["testtable"];
|
||||
REQUIRE(testobj.is<sol::table>());
|
||||
REQUIRE((testobj == testtable));
|
||||
REQUIRE_FALSE((testobj != testtable));
|
||||
REQUIRE((testtable["Woof"] == std::string("Bark")));
|
||||
REQUIRE((testtable[1] == 2));
|
||||
REQUIRE((testtable[3] == 4));
|
||||
}
|
||||
|
||||
TEST_CASE("tables/create-with-local", "Check if creating a table is kosher") {
|
||||
sol::state lua;
|
||||
lua["testtable"] = lua.create_table_with("Woof", "Bark", 1, 2, 3, 4);
|
||||
sol::object testobj = lua["testtable"];
|
||||
REQUIRE(testobj.is<sol::table>());
|
||||
sol::table testtable = testobj.as<sol::table>();
|
||||
REQUIRE((testtable["Woof"] == std::string("Bark")));
|
||||
REQUIRE((testtable[1] == 2));
|
||||
REQUIRE((testtable[3] == 4));
|
||||
}
|
||||
|
||||
TEST_CASE("tables/function variables", "Check if tables and function calls work as intended") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::os);
|
||||
auto run_script = [](sol::state& lua) -> void {
|
||||
lua.safe_script("assert(os.fun() == \"test\")");
|
||||
};
|
||||
|
||||
lua.get<sol::table>("os").set_function("fun",
|
||||
[]() {
|
||||
INFO("stateless lambda()");
|
||||
return "test";
|
||||
});
|
||||
REQUIRE_NOTHROW(run_script(lua));
|
||||
|
||||
lua.get<sol::table>("os").set_function("fun", &free_function);
|
||||
REQUIRE_NOTHROW(run_script(lua));
|
||||
|
||||
// l-value, canNOT optimise
|
||||
// prefer value semantics unless wrapped with std::reference_wrapper
|
||||
{
|
||||
auto lval = object();
|
||||
lua.get<sol::table>("os").set_function("fun", &object::operator(), lval);
|
||||
}
|
||||
REQUIRE_NOTHROW(run_script(lua));
|
||||
|
||||
auto reflval = object();
|
||||
lua.get<sol::table>("os").set_function("fun", &object::operator(), std::ref(reflval));
|
||||
REQUIRE_NOTHROW(run_script(lua));
|
||||
|
||||
// stateful lambda: non-convertible, cannot be optimised
|
||||
int breakit = 50;
|
||||
lua.get<sol::table>("os").set_function("fun",
|
||||
[&breakit]() {
|
||||
INFO("stateful lambda() with breakit:" << breakit);
|
||||
return "test";
|
||||
});
|
||||
REQUIRE_NOTHROW(run_script(lua));
|
||||
|
||||
// r-value, cannot optimise
|
||||
lua.get<sol::table>("os").set_function("fun", &object::operator(), object());
|
||||
REQUIRE_NOTHROW(run_script(lua));
|
||||
|
||||
// r-value, cannot optimise
|
||||
auto rval = object();
|
||||
lua.get<sol::table>("os").set_function("fun", &object::operator(), std::move(rval));
|
||||
REQUIRE_NOTHROW(run_script(lua));
|
||||
}
|
||||
|
||||
TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works properly") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.safe_script("foo = 20\nbar = \"hello world\"");
|
||||
// basic retrieval
|
||||
std::string bar = lua["bar"];
|
||||
int foo = lua["foo"];
|
||||
REQUIRE(bar == "hello world");
|
||||
REQUIRE(foo == 20);
|
||||
// test operator= for stringification
|
||||
// errors due to ambiguous operators
|
||||
bar = lua["bar"];
|
||||
|
||||
// basic setting
|
||||
lua["bar"] = 20.4;
|
||||
lua["foo"] = "goodbye";
|
||||
|
||||
// doesn't modify the actual values obviously.
|
||||
REQUIRE(bar == "hello world");
|
||||
REQUIRE(foo == 20);
|
||||
|
||||
// function setting
|
||||
lua["test"] = plop_xyz;
|
||||
{
|
||||
auto result = lua.safe_script("assert(test(10, 11, \"hello\") == 11)", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
|
||||
// function retrieval
|
||||
sol::function test = lua["test"];
|
||||
REQUIRE(test.call<int>(10, 11, "hello") == 11);
|
||||
|
||||
// setting a lambda
|
||||
lua["lamb"] = [](int x) {
|
||||
return x * 2;
|
||||
};
|
||||
|
||||
{
|
||||
auto result = lua.safe_script("assert(lamb(220) == 440)", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
|
||||
// function retrieval of a lambda
|
||||
sol::function lamb = lua["lamb"];
|
||||
REQUIRE(lamb.call<int>(220) == 440);
|
||||
|
||||
// test const table retrieval
|
||||
auto assert1 = [](const sol::table& t) {
|
||||
std::string a = t["foo"];
|
||||
double b = t["bar"];
|
||||
REQUIRE(a == "goodbye");
|
||||
REQUIRE(b == 20.4);
|
||||
};
|
||||
|
||||
REQUIRE_NOTHROW(assert1(lua.globals()));
|
||||
}
|
||||
|
||||
TEST_CASE("tables/operator[] valid", "Test if proxies on tables can lazily evaluate validity") {
|
||||
sol::state lua;
|
||||
bool isFullScreen = false;
|
||||
auto fullscreennopers = lua["fullscreen"]["nopers"];
|
||||
auto fullscreen = lua["fullscreen"];
|
||||
REQUIRE_FALSE(fullscreennopers.valid());
|
||||
REQUIRE_FALSE(fullscreen.valid());
|
||||
|
||||
lua["fullscreen"] = true;
|
||||
|
||||
REQUIRE_FALSE(fullscreennopers.valid());
|
||||
REQUIRE(fullscreen.valid());
|
||||
isFullScreen = lua["fullscreen"];
|
||||
REQUIRE(isFullScreen);
|
||||
|
||||
lua["fullscreen"] = false;
|
||||
REQUIRE_FALSE(fullscreennopers.valid());
|
||||
REQUIRE(fullscreen.valid());
|
||||
isFullScreen = lua["fullscreen"];
|
||||
REQUIRE_FALSE(isFullScreen);
|
||||
}
|
||||
|
||||
TEST_CASE("tables/operator[] optional", "Test if proxies on tables can lazily evaluate validity") {
|
||||
sol::state lua;
|
||||
|
||||
sol::optional<int> test1 = lua["no_exist_yet"];
|
||||
bool present = (bool)test1;
|
||||
REQUIRE_FALSE(present);
|
||||
|
||||
lua["no_exist_yet"] = 262;
|
||||
sol::optional<int> test2 = lua["no_exist_yet"];
|
||||
present = (bool)test2;
|
||||
REQUIRE(present);
|
||||
REQUIRE(test2.value() == 262);
|
||||
|
||||
sol::optional<int> nope = lua["nope"]["kek"]["hah"];
|
||||
auto nope2 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
|
||||
present = (bool)nope;
|
||||
REQUIRE_FALSE(present);
|
||||
present = (bool)nope2;
|
||||
REQUIRE_FALSE(present);
|
||||
lua.create_named_table("nope", "kek", lua.create_table_with("hah", 1));
|
||||
sol::optional<int> non_nope = lua["nope"]["kek"]["hah"].get<sol::optional<int>>();
|
||||
sol::optional<int> non_nope2 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
|
||||
present = (bool)non_nope;
|
||||
REQUIRE(present);
|
||||
present = (bool)non_nope2;
|
||||
REQUIRE(present);
|
||||
REQUIRE(non_nope.value() == 1);
|
||||
REQUIRE(non_nope2.value() == 1);
|
||||
|
||||
INFO("Keys: nope, kek, hah");
|
||||
lua.set(std::make_tuple("nope", "kek", "hah"), 35);
|
||||
sol::optional<int> non_nope3 = lua["nope"]["kek"]["hah"].get<sol::optional<int>>();
|
||||
sol::optional<int> non_nope4 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
|
||||
present = (bool)non_nope3;
|
||||
REQUIRE(present);
|
||||
present = (bool)non_nope4;
|
||||
REQUIRE(present);
|
||||
REQUIRE(non_nope3.value() == 35);
|
||||
REQUIRE(non_nope4.value() == 35);
|
||||
}
|
||||
|
||||
TEST_CASE("tables/add", "Basic test to make sure the 'add' feature works") {
|
||||
static const int sz = 120;
|
||||
|
||||
sol::state lua;
|
||||
sol::table t = lua.create_table(sz, 0);
|
||||
|
||||
std::vector<int> bigvec(sz);
|
||||
std::iota(bigvec.begin(), bigvec.end(), 1);
|
||||
|
||||
for (std::size_t i = 0; i < bigvec.size(); ++i) {
|
||||
t.add(bigvec[i]);
|
||||
}
|
||||
for (std::size_t i = 0; i < bigvec.size(); ++i) {
|
||||
int val = t[i + 1];
|
||||
REQUIRE(val == bigvec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("tables/raw set and raw get", "ensure raw setting and getting works through metatables") {
|
||||
sol::state lua;
|
||||
sol::table t = lua.create_table();
|
||||
t[sol::metatable_key] = lua.create_table_with(
|
||||
sol::meta_function::new_index, [](lua_State* L) { return luaL_error(L, "nay"); },
|
||||
sol::meta_function::index, [](lua_State* L) { return luaL_error(L, "nay"); });
|
||||
t.raw_set("a", 2.5);
|
||||
double la = t.raw_get<double>("a");
|
||||
REQUIRE(la == 2.5);
|
||||
}
|
||||
|
||||
TEST_CASE("tables/boolean keys", "make sure boolean keys don't get caught up in `is_integral` specializations") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.safe_script(R"(
|
||||
tbl = {}
|
||||
tbl[true] = 10
|
||||
tbl[1] = 20
|
||||
|
||||
print(tbl[true])
|
||||
print(tbl[1])
|
||||
)");
|
||||
sol::table tbl = lua["tbl"];
|
||||
int v1 = tbl[true];
|
||||
int v2 = tbl[1];
|
||||
REQUIRE(v1 == 10);
|
||||
REQUIRE(v2 == 20);
|
||||
|
||||
tbl[true] = 30;
|
||||
tbl[1] = 40;
|
||||
v1 = tbl[true];
|
||||
v2 = tbl[1];
|
||||
REQUIRE(v1 == 30);
|
||||
REQUIRE(v2 == 40);
|
||||
}
|
||||
|
||||
TEST_CASE("tables/optional move", "ensure pushing a sol::optional<T> rvalue correctly moves the contained object into tables") {
|
||||
sol::state sol_state;
|
||||
struct move_only {
|
||||
int secret_code;
|
||||
move_only(const move_only&) = delete;
|
||||
move_only(move_only&&) = default;
|
||||
};
|
||||
sol_state["requires_move"] = sol::optional<move_only>{ move_only{ 0x4D } };
|
||||
REQUIRE(sol_state["requires_move"].get<move_only>().secret_code == 0x4D);
|
||||
}
|
||||
+1997
File diff suppressed because it is too large
Load Diff
+270
@@ -0,0 +1,270 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
#endif
|
||||
|
||||
std::mutex basic_init_require_mutex;
|
||||
|
||||
void basic_initialization_and_lib_open() {
|
||||
sol::state lua;
|
||||
try {
|
||||
lua.open_libraries();
|
||||
lua["a"] = 24;
|
||||
int a = lua["a"];
|
||||
{
|
||||
std::lock_guard<std::mutex> lg(basic_init_require_mutex);
|
||||
REQUIRE(a == 24);
|
||||
}
|
||||
}
|
||||
catch (const sol::error& e) {
|
||||
std::lock_guard<std::mutex> lg(basic_init_require_mutex);
|
||||
INFO(e.what());
|
||||
REQUIRE(false);
|
||||
}
|
||||
catch (...) {
|
||||
std::lock_guard<std::mutex> lg(basic_init_require_mutex);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("utility/variant", "test that variant can be round-tripped") {
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
SECTION("okay") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set_function("f", [](int v) {
|
||||
return v == 2;
|
||||
});
|
||||
lua.set_function("g", [](std::variant<float, int, std::string> vv) {
|
||||
int v = std::get<int>(vv);
|
||||
return v == 2;
|
||||
});
|
||||
lua["v"] = std::variant<float, int, std::string>(2);
|
||||
{
|
||||
auto result = lua.safe_script("assert(f(v))", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
};
|
||||
{
|
||||
auto result = lua.safe_script("assert(g(v))", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
};
|
||||
}
|
||||
SECTION("throws") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set_function("f", [](int v) {
|
||||
return v == 2;
|
||||
});
|
||||
lua.set_function("g", [](std::variant<float, int, std::string> vv) {
|
||||
int v = std::get<int>(vv);
|
||||
return v == 2;
|
||||
});
|
||||
lua["v"] = std::variant<float, int, std::string>(std::string("bark"));
|
||||
{
|
||||
auto result = lua.safe_script("assert(f(v))", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
};
|
||||
{
|
||||
auto result = lua.safe_script("assert(g(v))", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
};
|
||||
}
|
||||
#else
|
||||
REQUIRE(true);
|
||||
#endif // C++17
|
||||
}
|
||||
|
||||
TEST_CASE("utility/optional", "test that shit optional can be round-tripped") {
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
SECTION("okay") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set_function("f", [](int v) {
|
||||
return v == 2;
|
||||
});
|
||||
lua.set_function("g", [](std::optional<int> vv) {
|
||||
return vv && *vv == 2;
|
||||
});
|
||||
lua["v"] = std::optional<int>(2);
|
||||
{
|
||||
auto result = lua.safe_script("assert(f(v))", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("assert(g(v))", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
}
|
||||
SECTION("throws") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set_function("f", [](int v) {
|
||||
return v == 2;
|
||||
});
|
||||
lua.set_function("g", [](std::optional<int> vv) {
|
||||
return vv && *vv == 2;
|
||||
});
|
||||
lua["v"] = std::optional<int>(std::nullopt);
|
||||
{
|
||||
auto result = lua.safe_script("assert(f(v))", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
};
|
||||
{
|
||||
auto result = lua.safe_script("assert(g(v))", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
};
|
||||
}
|
||||
SECTION("in classes") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
struct opt_c {
|
||||
std::optional<int> member;
|
||||
};
|
||||
|
||||
auto uto = lua.new_usertype<opt_c>("opt_c",
|
||||
"value", &opt_c::member);
|
||||
|
||||
opt_c obj;
|
||||
lua["obj"] = std::ref(obj);
|
||||
|
||||
lua.safe_script("print(obj.value) obj.value = 20 print(obj.value)");
|
||||
REQUIRE(obj.member == 20);
|
||||
lua.safe_script("print(obj.value) obj.value = nil print(obj.value)");
|
||||
REQUIRE(obj.member == std::nullopt);
|
||||
}
|
||||
#else
|
||||
REQUIRE(true);
|
||||
#endif // C++17
|
||||
}
|
||||
|
||||
TEST_CASE("utility/string_view", "test that string_view can be taken as an argument") {
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set_function("f", [](std::string_view v) {
|
||||
return v == "bark!";
|
||||
});
|
||||
lua["v"] = "bark!";
|
||||
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.safe_script("assert(f(v))");
|
||||
}());
|
||||
#else
|
||||
REQUIRE(true);
|
||||
#endif // C++17
|
||||
}
|
||||
|
||||
TEST_CASE("utility/thread", "fire up lots of threads at the same time to make sure the initialization changes do not cause horrible crashing data races") {
|
||||
REQUIRE_NOTHROW([]() {
|
||||
std::thread thrds[16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
thrds[i] = std::thread(&basic_initialization_and_lib_open);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
thrds[i].join();
|
||||
}
|
||||
}());
|
||||
}
|
||||
|
||||
TEST_CASE("utility/pointer", "check we can get pointer value from references") {
|
||||
sol::state lua;
|
||||
lua.set_function("f", [](bool aorb, sol::reference a, sol::stack_reference b) {
|
||||
if (aorb) {
|
||||
return a.pointer();
|
||||
}
|
||||
return b.pointer();
|
||||
});
|
||||
auto result0 = lua.safe_script("v0 = 'hi'", sol::script_pass_on_error);
|
||||
REQUIRE(result0.valid());
|
||||
auto result1 = lua.safe_script("v1 = f(true, v0)", sol::script_pass_on_error);
|
||||
REQUIRE(result1.valid());
|
||||
auto result2 = lua.safe_script("v2 = f(false, nil, v0)", sol::script_pass_on_error);
|
||||
REQUIRE(result2.valid());
|
||||
const void* ap = lua["v1"];
|
||||
const void* bp = lua["v2"];
|
||||
REQUIRE(ap == bp);
|
||||
}
|
||||
|
||||
TEST_CASE("utility/this_state", "Ensure this_state argument can be gotten anywhere in the function.") {
|
||||
struct bark {
|
||||
int with_state(sol::this_state l, int a, int b) {
|
||||
lua_State* L = l;
|
||||
int c = lua_gettop(L);
|
||||
return a + b + (c - c);
|
||||
}
|
||||
|
||||
static int with_state_2(int a, sol::this_state l, int b) {
|
||||
INFO("inside with_state_2");
|
||||
lua_State* L = l;
|
||||
INFO("L is" << (void*)L);
|
||||
int c = lua_gettop(L);
|
||||
return a * b + (c - c);
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
INFO("created lua state");
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_usertype<bark>("bark",
|
||||
"with_state", &bark::with_state);
|
||||
|
||||
INFO("setting b and with_state_2");
|
||||
bark b;
|
||||
lua.set("b", &b);
|
||||
lua.set("with_state_2", bark::with_state_2);
|
||||
INFO("finished setting");
|
||||
INFO("getting fx");
|
||||
sol::function fx = lua["with_state_2"];
|
||||
INFO("calling fx");
|
||||
int a = fx(25, 25);
|
||||
INFO("finished setting fx");
|
||||
INFO("calling a script");
|
||||
lua.safe_script("a = with_state_2(25, 25)");
|
||||
INFO("calling c script");
|
||||
lua.safe_script("c = b:with_state(25, 25)");
|
||||
INFO("getting a");
|
||||
int la = lua["a"];
|
||||
INFO("getting b");
|
||||
int lc = lua["c"];
|
||||
|
||||
REQUIRE(lc == 50);
|
||||
REQUIRE(a == 625);
|
||||
REQUIRE(la == 625);
|
||||
}
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <deque>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
TEST_CASE("variadics/variadic_args", "Check to see we can receive multiple arguments through a variadic") {
|
||||
struct structure {
|
||||
int x;
|
||||
bool b;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.set_function("v", [](sol::this_state, sol::variadic_args va) -> structure {
|
||||
int r = 0;
|
||||
for (auto v : va) {
|
||||
int value = v;
|
||||
r += value;
|
||||
}
|
||||
return { r, r > 200 };
|
||||
});
|
||||
|
||||
lua.safe_script("x = v(25, 25)");
|
||||
lua.safe_script("x2 = v(25, 25, 100, 50, 250, 150)");
|
||||
lua.safe_script("x3 = v(1, 2, 3, 4, 5, 6)");
|
||||
|
||||
structure& lx = lua["x"];
|
||||
structure& lx2 = lua["x2"];
|
||||
structure& lx3 = lua["x3"];
|
||||
REQUIRE(lx.x == 50);
|
||||
REQUIRE(lx2.x == 600);
|
||||
REQUIRE(lx3.x == 21);
|
||||
REQUIRE_FALSE(lx.b);
|
||||
REQUIRE(lx2.b);
|
||||
REQUIRE_FALSE(lx3.b);
|
||||
}
|
||||
|
||||
TEST_CASE("variadics/required with variadic_args", "Check if a certain number of arguments can still be required even when using variadic_args") {
|
||||
sol::state lua;
|
||||
lua.set_function("v",
|
||||
[](sol::this_state, sol::variadic_args, int, int) {
|
||||
});
|
||||
{
|
||||
auto result = lua.safe_script("v(20, 25, 30)", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("v(20, 25)", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("v(20)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("variadics/variadic_args get type", "Make sure we can inspect types proper from variadic_args") {
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function("f", [](sol::variadic_args va) {
|
||||
sol::type types[] = {
|
||||
sol::type::number,
|
||||
sol::type::string,
|
||||
sol::type::boolean
|
||||
};
|
||||
bool working = true;
|
||||
auto b = va.begin();
|
||||
for (std::size_t i = 0; i < va.size(); ++i, ++b) {
|
||||
sol::type t1 = va.get_type(i);
|
||||
sol::type t2 = b->get_type();
|
||||
working &= types[i] == t1;
|
||||
working &= types[i] == t2;
|
||||
}
|
||||
REQUIRE(working);
|
||||
});
|
||||
|
||||
lua.safe_script("f(1, 'bark', true)");
|
||||
lua.safe_script("f(2, 'wuf', false)");
|
||||
}
|
||||
|
||||
TEST_CASE("variadics/variadic_results", "returning a variable amount of arguments from C++") {
|
||||
SECTION("as_returns - containers") {
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function("f", []() {
|
||||
std::set<std::string> results{ "arf", "bark", "woof" };
|
||||
return sol::as_returns(std::move(results));
|
||||
});
|
||||
lua.set_function("g", []() {
|
||||
static const std::deque<int> results{ 25, 82 };
|
||||
return sol::as_returns(std::ref(results));
|
||||
});
|
||||
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.safe_script(R"(
|
||||
v1, v2, v3 = f()
|
||||
v4, v5 = g()
|
||||
)");
|
||||
}());
|
||||
|
||||
std::string v1 = lua["v1"];
|
||||
std::string v2 = lua["v2"];
|
||||
std::string v3 = lua["v3"];
|
||||
int v4 = lua["v4"];
|
||||
int v5 = lua["v5"];
|
||||
|
||||
REQUIRE(v1 == "arf");
|
||||
REQUIRE(v2 == "bark");
|
||||
REQUIRE(v3 == "woof");
|
||||
REQUIRE(v4 == 25);
|
||||
REQUIRE(v5 == 82);
|
||||
}
|
||||
SECTION("variadic_results - variadic_args") {
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function("f", [](sol::variadic_args args) {
|
||||
return sol::variadic_results(args.cbegin(), args.cend());
|
||||
});
|
||||
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.safe_script(R"(
|
||||
v1, v2, v3 = f(1, 'bark', true)
|
||||
v4, v5 = f(25, 82)
|
||||
)");
|
||||
}());
|
||||
|
||||
int v1 = lua["v1"];
|
||||
std::string v2 = lua["v2"];
|
||||
bool v3 = lua["v3"];
|
||||
int v4 = lua["v4"];
|
||||
int v5 = lua["v5"];
|
||||
|
||||
REQUIRE(v1 == 1);
|
||||
REQUIRE(v2 == "bark");
|
||||
REQUIRE(v3);
|
||||
REQUIRE(v4 == 25);
|
||||
REQUIRE(v5 == 82);
|
||||
}
|
||||
SECTION("variadic_results") {
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function("f", [](sol::this_state ts, bool maybe) {
|
||||
if (maybe) {
|
||||
sol::variadic_results vr;
|
||||
vr.push_back({ ts, sol::in_place, 1 });
|
||||
vr.push_back({ ts, sol::in_place, 2 });
|
||||
vr.insert(vr.cend(), { ts, sol::in_place, 3 });
|
||||
return vr;
|
||||
}
|
||||
else {
|
||||
sol::variadic_results vr;
|
||||
vr.push_back({ ts, sol::in_place, "bark" });
|
||||
vr.push_back({ ts, sol::in_place, "woof" });
|
||||
vr.insert(vr.cend(), { ts, sol::in_place, "arf" });
|
||||
vr.push_back({ ts, sol::in_place, "borf" });
|
||||
return vr;
|
||||
}
|
||||
});
|
||||
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.safe_script(R"(
|
||||
v1, v2, v3 = f(true)
|
||||
v4, v5, v6, v7 = f(false)
|
||||
)");
|
||||
}());
|
||||
|
||||
int v1 = lua["v1"];
|
||||
int v2 = lua["v2"];
|
||||
int v3 = lua["v3"];
|
||||
std::string v4 = lua["v4"];
|
||||
std::string v5 = lua["v5"];
|
||||
std::string v6 = lua["v6"];
|
||||
std::string v7 = lua["v7"];
|
||||
|
||||
REQUIRE(v1 == 1);
|
||||
REQUIRE(v2 == 2);
|
||||
REQUIRE(v3 == 3);
|
||||
REQUIRE(v4 == "bark");
|
||||
REQUIRE(v5 == "woof");
|
||||
REQUIRE(v6 == "arf");
|
||||
REQUIRE(v7 == "borf");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("variadics/fallback_constructor", "ensure constructor matching behaves properly in the presence of variadic fallbacks") {
|
||||
struct vec2 {
|
||||
float x = 0, y = 0;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.new_simple_usertype<vec2>("vec2",
|
||||
sol::call_constructor, sol::factories([]() { return vec2{}; }, [](vec2 const& v) -> vec2 { return v; }, [](sol::variadic_args va) {
|
||||
vec2 res{};
|
||||
if (va.size() == 1) {
|
||||
res.x = va[0].get<float>();
|
||||
res.y = va[0].get<float>();
|
||||
}
|
||||
else if (va.size() == 2) {
|
||||
res.x = va[0].get<float>();
|
||||
res.y = va[1].get<float>();
|
||||
}
|
||||
else {
|
||||
throw sol::error("invalid args");
|
||||
}
|
||||
return res; }));
|
||||
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.safe_script("v0 = vec2();");
|
||||
lua.safe_script("v1 = vec2(1);");
|
||||
lua.safe_script("v2 = vec2(1, 2);");
|
||||
lua.safe_script("v3 = vec2(v2)");
|
||||
}());
|
||||
|
||||
vec2& v0 = lua["v0"];
|
||||
vec2& v1 = lua["v1"];
|
||||
vec2& v2 = lua["v2"];
|
||||
vec2& v3 = lua["v3"];
|
||||
|
||||
REQUIRE(v0.x == 0);
|
||||
REQUIRE(v0.y == 0);
|
||||
REQUIRE(v1.x == 1);
|
||||
REQUIRE(v1.y == 1);
|
||||
REQUIRE(v2.x == 1);
|
||||
REQUIRE(v2.y == 2);
|
||||
REQUIRE(v3.x == v2.x);
|
||||
REQUIRE(v3.y == v2.y);
|
||||
}
|
||||
Vendored
+654
@@ -0,0 +1,654 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "test_sol.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
bool func_opt_ret_bool(sol::optional<int> i) {
|
||||
if (i) {
|
||||
INFO(i.value());
|
||||
}
|
||||
else {
|
||||
INFO("optional isn't set");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_CASE("table/traversal", "ensure that we can chain requests and tunnel down into a value if we desire") {
|
||||
|
||||
sol::state lua;
|
||||
int begintop = 0, endtop = 0;
|
||||
|
||||
sol::function scriptload = lua.load("t1 = {t2 = {t3 = 24}};");
|
||||
scriptload();
|
||||
{
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
int traversex24 = lua.traverse_get<int>("t1", "t2", "t3");
|
||||
REQUIRE(traversex24 == 24);
|
||||
}
|
||||
REQUIRE(begintop == endtop);
|
||||
|
||||
{
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
int x24 = lua["t1"]["t2"]["t3"];
|
||||
REQUIRE(x24 == 24);
|
||||
}
|
||||
REQUIRE(begintop == endtop);
|
||||
|
||||
{
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
lua["t1"]["t2"]["t3"] = 64;
|
||||
int traversex64 = lua.traverse_get<int>("t1", "t2", "t3");
|
||||
REQUIRE(traversex64 == 64);
|
||||
}
|
||||
REQUIRE(begintop == endtop);
|
||||
|
||||
{
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
int x64 = lua["t1"]["t2"]["t3"];
|
||||
REQUIRE(x64 == 64);
|
||||
}
|
||||
REQUIRE(begintop == endtop);
|
||||
|
||||
{
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
lua.traverse_set("t1", "t2", "t3", 13);
|
||||
int traversex13 = lua.traverse_get<int>("t1", "t2", "t3");
|
||||
REQUIRE(traversex13 == 13);
|
||||
}
|
||||
REQUIRE(begintop == endtop);
|
||||
|
||||
{
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
int x13 = lua["t1"]["t2"]["t3"];
|
||||
REQUIRE(x13 == 13);
|
||||
}
|
||||
REQUIRE(begintop == endtop);
|
||||
}
|
||||
|
||||
TEST_CASE("simple/set", "Check if the set works properly.") {
|
||||
sol::state lua;
|
||||
int begintop = 0, endtop = 0;
|
||||
{
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
lua.set("a", 9);
|
||||
}
|
||||
REQUIRE(begintop == endtop);
|
||||
{
|
||||
auto result = lua.safe_script("if a ~= 9 then error('wrong value') end", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
{
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
lua.set("d", "hello");
|
||||
}
|
||||
REQUIRE(begintop == endtop);
|
||||
{
|
||||
auto result = lua.safe_script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
|
||||
{
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
lua.set("e", std::string("hello"), "f", true);
|
||||
}
|
||||
REQUIRE(begintop == endtop);
|
||||
{
|
||||
auto result = lua.safe_script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("if f ~= true then error('wrong value') end", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("simple/get", "Tests if the get function works properly.") {
|
||||
sol::state lua;
|
||||
int begintop = 0, endtop = 0;
|
||||
|
||||
lua.safe_script("a = 9");
|
||||
{
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
auto a = lua.get<int>("a");
|
||||
REQUIRE(a == 9.0);
|
||||
}
|
||||
REQUIRE(begintop == endtop);
|
||||
|
||||
lua.safe_script("b = nil");
|
||||
{
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
REQUIRE_NOTHROW(lua.get<sol::lua_nil_t>("b"));
|
||||
}
|
||||
REQUIRE(begintop == endtop);
|
||||
|
||||
lua.safe_script("d = 'hello'");
|
||||
lua.safe_script("e = true");
|
||||
{
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
std::string d;
|
||||
bool e;
|
||||
std::tie(d, e) = lua.get<std::string, bool>("d", "e");
|
||||
REQUIRE(d == "hello");
|
||||
REQUIRE(e == true);
|
||||
}
|
||||
REQUIRE(begintop == endtop);
|
||||
}
|
||||
|
||||
TEST_CASE("simple/set and get global integer", "Tests if the get function works properly with global integers") {
|
||||
sol::state lua;
|
||||
lua[1] = 25.4;
|
||||
lua.safe_script("b = 1");
|
||||
double a = lua.get<double>(1);
|
||||
double b = lua.get<double>("b");
|
||||
REQUIRE(a == 25.4);
|
||||
REQUIRE(b == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("simple/get_or", "check if table.get_or works correctly") {
|
||||
sol::state lua;
|
||||
|
||||
auto bob_table = lua.create_table("bob");
|
||||
bob_table.set("is_set", 42);
|
||||
|
||||
int is_set = bob_table.get_or("is_set", 3);
|
||||
int is_not_set = bob_table.get_or("is_not_set", 22);
|
||||
|
||||
REQUIRE(is_set == 42);
|
||||
REQUIRE(is_not_set == 22);
|
||||
|
||||
lua["joe"] = 55.6;
|
||||
double bark = lua.get_or<double>("joe", 60);
|
||||
REQUIRE(bark == 55.6);
|
||||
}
|
||||
|
||||
TEST_CASE("simple/proxy get_or", "check if proxy.get_or works correctly") {
|
||||
sol::state lua;
|
||||
|
||||
auto bob_table = lua.create_table("bob");
|
||||
bob_table.set("is_set", 42);
|
||||
|
||||
int is_set = bob_table["is_set"].get_or(3);
|
||||
int is_not_set = bob_table["is_not_set"].get_or(22);
|
||||
|
||||
REQUIRE(is_set == 42);
|
||||
REQUIRE(is_not_set == 22);
|
||||
|
||||
lua["joe"] = 55.6;
|
||||
double bark = lua["joe"].get_or<double>(60);
|
||||
REQUIRE(bark == 55.6);
|
||||
}
|
||||
|
||||
TEST_CASE("simple/addition", "check if addition works and can be gotten through lua.get and lua.set") {
|
||||
sol::state lua;
|
||||
|
||||
lua.set("b", 0.2);
|
||||
lua.safe_script("c = 9 + b");
|
||||
auto c = lua.get<double>("c");
|
||||
|
||||
REQUIRE(c == 9.2);
|
||||
}
|
||||
|
||||
TEST_CASE("simple/if", "check if if statements work through lua") {
|
||||
sol::state lua;
|
||||
|
||||
std::string program = "if true then f = 0.1 else f = 'test' end";
|
||||
lua.safe_script(program);
|
||||
auto f = lua.get<double>("f");
|
||||
|
||||
REQUIRE(f == 0.1);
|
||||
REQUIRE((f == lua["f"]));
|
||||
}
|
||||
|
||||
TEST_CASE("negative/basic errors", "Check if error handling works correctly") {
|
||||
sol::state lua;
|
||||
|
||||
auto result = lua.safe_script("nil[5]", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
TEST_CASE("libraries", "Check if we can open libraries") {
|
||||
sol::state lua;
|
||||
REQUIRE_NOTHROW(lua.open_libraries(sol::lib::base, sol::lib::os));
|
||||
}
|
||||
|
||||
TEST_CASE("libraries2", "Check if we can open ALL the libraries") {
|
||||
sol::state lua;
|
||||
REQUIRE_NOTHROW(lua.open_libraries(sol::lib::base,
|
||||
sol::lib::bit32,
|
||||
sol::lib::coroutine,
|
||||
sol::lib::debug,
|
||||
sol::lib::ffi,
|
||||
sol::lib::jit,
|
||||
sol::lib::math,
|
||||
sol::lib::os,
|
||||
sol::lib::package,
|
||||
sol::lib::string,
|
||||
sol::lib::table));
|
||||
}
|
||||
|
||||
TEST_CASE("interop/null-to-nil-and-back", "nil should be the given type when a pointer from C++ is returned as nullptr, and nil should result in nullptr in connected C++ code") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set_function("lol", []() -> int* {
|
||||
return nullptr;
|
||||
});
|
||||
lua.set_function("rofl", [](int* x) {
|
||||
INFO(x);
|
||||
});
|
||||
REQUIRE_NOTHROW(lua.safe_script(
|
||||
"x = lol()\n"
|
||||
"rofl(x)\n"
|
||||
"assert(x == nil)"));
|
||||
}
|
||||
|
||||
TEST_CASE("object/conversions", "make sure all basic reference types can be made into objects") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
struct d {};
|
||||
|
||||
lua.safe_script("function f () print('bark') end");
|
||||
lua["d"] = d{};
|
||||
lua["l"] = static_cast<void*>(nullptr);
|
||||
|
||||
sol::table t = lua.create_table();
|
||||
sol::table t2(lua, sol::create);
|
||||
sol::thread th = sol::thread::create(lua);
|
||||
sol::function f = lua["f"];
|
||||
sol::protected_function pf = lua["f"];
|
||||
sol::userdata ud = lua["d"];
|
||||
sol::lightuserdata lud = lua["l"];
|
||||
sol::environment env(lua, sol::create);
|
||||
|
||||
sol::object ot(t);
|
||||
sol::object ot2(t2);
|
||||
sol::object oteq = ot;
|
||||
sol::object oth(th);
|
||||
sol::object of(f);
|
||||
sol::object opf(pf);
|
||||
sol::object od(ud);
|
||||
sol::object ol(lud);
|
||||
sol::object oenv(env);
|
||||
|
||||
auto oni = sol::make_object(lua, 50);
|
||||
auto ond = sol::make_object(lua, 50.0);
|
||||
|
||||
std::string somestring = "look at this text isn't it nice";
|
||||
auto osl = sol::make_object(lua, "Bark bark bark");
|
||||
auto os = sol::make_object(lua, somestring);
|
||||
|
||||
auto omn = sol::make_object(lua, sol::lua_nil);
|
||||
|
||||
REQUIRE(ot.get_type() == sol::type::table);
|
||||
REQUIRE(ot2.get_type() == sol::type::table);
|
||||
REQUIRE(oteq.get_type() == sol::type::table);
|
||||
REQUIRE(oth.get_type() == sol::type::thread);
|
||||
REQUIRE(of.get_type() == sol::type::function);
|
||||
REQUIRE(opf.get_type() == sol::type::function);
|
||||
REQUIRE(od.get_type() == sol::type::userdata);
|
||||
REQUIRE(ol.get_type() == sol::type::lightuserdata);
|
||||
REQUIRE(oni.get_type() == sol::type::number);
|
||||
REQUIRE(ond.get_type() == sol::type::number);
|
||||
REQUIRE(osl.get_type() == sol::type::string);
|
||||
REQUIRE(os.get_type() == sol::type::string);
|
||||
REQUIRE(omn.get_type() == sol::type::lua_nil);
|
||||
REQUIRE(oenv.get_type() == sol::type::table);
|
||||
}
|
||||
|
||||
TEST_CASE("object/main_* conversions", "make sure all basic reference types can be made into objects") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
struct d {};
|
||||
|
||||
lua.safe_script("function f () print('bark') end");
|
||||
lua["d"] = d{};
|
||||
lua["l"] = static_cast<void*>(nullptr);
|
||||
|
||||
sol::main_table t = lua.create_table();
|
||||
sol::main_table t2(lua, sol::create);
|
||||
sol::thread th = sol::thread::create(lua);
|
||||
sol::main_function f = lua["f"];
|
||||
sol::main_protected_function pf = lua["f"];
|
||||
sol::main_userdata ud = lua["d"];
|
||||
sol::main_lightuserdata lud = lua["l"];
|
||||
sol::main_environment env(lua, sol::create);
|
||||
|
||||
sol::main_object ot(t);
|
||||
sol::main_object ot2(t2);
|
||||
sol::main_object oteq = ot;
|
||||
sol::main_object oth(th);
|
||||
sol::main_object of(f);
|
||||
sol::main_object opf(pf);
|
||||
sol::main_object od(ud);
|
||||
sol::main_object ol(lud);
|
||||
sol::main_object oenv(env);
|
||||
|
||||
auto oni = sol::make_object(lua, 50);
|
||||
auto ond = sol::make_object(lua, 50.0);
|
||||
|
||||
std::string somestring = "look at this text isn't it nice";
|
||||
auto osl = sol::make_object(lua, "Bark bark bark");
|
||||
auto os = sol::make_object(lua, somestring);
|
||||
|
||||
auto omn = sol::make_object(lua, sol::lua_nil);
|
||||
|
||||
REQUIRE(ot.get_type() == sol::type::table);
|
||||
REQUIRE(ot2.get_type() == sol::type::table);
|
||||
REQUIRE(oteq.get_type() == sol::type::table);
|
||||
REQUIRE(oth.get_type() == sol::type::thread);
|
||||
REQUIRE(of.get_type() == sol::type::function);
|
||||
REQUIRE(opf.get_type() == sol::type::function);
|
||||
REQUIRE(od.get_type() == sol::type::userdata);
|
||||
REQUIRE(ol.get_type() == sol::type::lightuserdata);
|
||||
REQUIRE(oni.get_type() == sol::type::number);
|
||||
REQUIRE(ond.get_type() == sol::type::number);
|
||||
REQUIRE(osl.get_type() == sol::type::string);
|
||||
REQUIRE(os.get_type() == sol::type::string);
|
||||
REQUIRE(omn.get_type() == sol::type::lua_nil);
|
||||
REQUIRE(oenv.get_type() == sol::type::table);
|
||||
}
|
||||
|
||||
TEST_CASE("feature/indexing overrides", "make sure index functions can be overridden on types") {
|
||||
struct PropertySet {
|
||||
sol::object get_property_lua(const char* name, sol::this_state s) {
|
||||
auto& var = props[name];
|
||||
return sol::make_object(s, var);
|
||||
}
|
||||
|
||||
void set_property_lua(const char* name, sol::stack_object object) {
|
||||
props[name] = object.as<std::string>();
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> props;
|
||||
};
|
||||
|
||||
struct DynamicObject {
|
||||
PropertySet& get_dynamic_props() {
|
||||
return dynamic_props;
|
||||
}
|
||||
|
||||
PropertySet dynamic_props;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<PropertySet>("PropertySet", sol::meta_function::new_index, &PropertySet::set_property_lua, sol::meta_function::index, &PropertySet::get_property_lua);
|
||||
lua.new_usertype<DynamicObject>("DynamicObject", "props", sol::property(&DynamicObject::get_dynamic_props));
|
||||
|
||||
lua.safe_script(R"__(
|
||||
obj = DynamicObject:new()
|
||||
obj.props.name = 'test name'
|
||||
print('name = ' .. obj.props.name)
|
||||
)__");
|
||||
|
||||
std::string name = lua["obj"]["props"]["name"];
|
||||
REQUIRE(name == "test name");
|
||||
}
|
||||
|
||||
TEST_CASE("features/indexing numbers", "make sure indexing functions can be override on usertypes") {
|
||||
class vector {
|
||||
public:
|
||||
double data[3];
|
||||
|
||||
vector()
|
||||
: data{ 0, 0, 0 } {
|
||||
}
|
||||
|
||||
double& operator[](int i) {
|
||||
return data[i];
|
||||
}
|
||||
|
||||
static double my_index(vector& v, int i) {
|
||||
return v[i];
|
||||
}
|
||||
|
||||
static void my_new_index(vector& v, int i, double x) {
|
||||
v[i] = x;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_usertype<vector>("vector", sol::constructors<sol::types<>>(),
|
||||
sol::meta_function::index, &vector::my_index,
|
||||
sol::meta_function::new_index, &vector::my_new_index);
|
||||
lua.safe_script(
|
||||
"v = vector.new()\n"
|
||||
"print(v[1])\n"
|
||||
"v[2] = 3\n"
|
||||
"print(v[2])\n");
|
||||
|
||||
vector& v = lua["v"];
|
||||
REQUIRE(v[0] == 0.0);
|
||||
REQUIRE(v[1] == 0.0);
|
||||
REQUIRE(v[2] == 3.0);
|
||||
}
|
||||
|
||||
TEST_CASE("features/multiple inheritance", "Ensure that multiple inheritance works as advertised") {
|
||||
struct base1 {
|
||||
int a1 = 250;
|
||||
};
|
||||
|
||||
struct base2 {
|
||||
int a2 = 500;
|
||||
};
|
||||
|
||||
struct simple : base1 {
|
||||
};
|
||||
|
||||
struct complex : base1, base2 {
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_usertype<base1>("base1",
|
||||
"a1", &base1::a1);
|
||||
lua.new_usertype<base2>("base2",
|
||||
"a2", &base2::a2);
|
||||
lua.new_usertype<simple>("simple",
|
||||
"a1", &simple::a1,
|
||||
sol::base_classes, sol::bases<base1>());
|
||||
lua.new_usertype<complex>("complex",
|
||||
"a1", &complex::a1,
|
||||
"a2", &complex::a2,
|
||||
sol::base_classes, sol::bases<base1, base2>());
|
||||
lua.safe_script(
|
||||
"c = complex.new()\n"
|
||||
"s = simple.new()\n"
|
||||
"b1 = base1.new()\n"
|
||||
"b2 = base1.new()\n");
|
||||
|
||||
base1* sb1 = lua["s"];
|
||||
REQUIRE(sb1 != nullptr);
|
||||
REQUIRE(sb1->a1 == 250);
|
||||
|
||||
base1* cb1 = lua["c"];
|
||||
base2* cb2 = lua["c"];
|
||||
|
||||
REQUIRE(cb1 != nullptr);
|
||||
REQUIRE(cb2 != nullptr);
|
||||
REQUIRE(cb1->a1 == 250);
|
||||
REQUIRE(cb2->a2 == 500);
|
||||
}
|
||||
|
||||
TEST_CASE("regressions/std::ref", "Ensure that std::reference_wrapper<> isn't considered as a function by using unwrap_unqualified_t trait") {
|
||||
struct base1 {
|
||||
int a1 = 250;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
base1 v;
|
||||
lua["vp"] = &v;
|
||||
lua["vr"] = std::ref(v);
|
||||
|
||||
base1* vp = lua["vp"];
|
||||
base1& vr = lua["vr"];
|
||||
REQUIRE(vp != nullptr);
|
||||
REQUIRE(vp == &v);
|
||||
|
||||
REQUIRE(vp->a1 == 250);
|
||||
REQUIRE(vr.a1 == 250);
|
||||
|
||||
v.a1 = 568;
|
||||
|
||||
REQUIRE(vp->a1 == 568);
|
||||
REQUIRE(vr.a1 == 568);
|
||||
}
|
||||
|
||||
TEST_CASE("optional/left out args", "Make sure arguments can be left out of optional without tanking miserably") {
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
// sol::optional needs an argument no matter what?
|
||||
lua.set_function("func_opt_ret_bool", func_opt_ret_bool);
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.safe_script(R"(
|
||||
func_opt_ret_bool(42)
|
||||
func_opt_ret_bool()
|
||||
print('ok')
|
||||
)");
|
||||
}());
|
||||
}
|
||||
|
||||
TEST_CASE("optional/engaged versus unengaged", "solidify semantics for an engaged and unengaged optional") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set_function("f", [](sol::optional<sol::object> optional_arg) {
|
||||
if (optional_arg) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
auto valid0 = lua.safe_script("assert(not f())", sol::script_pass_on_error);
|
||||
REQUIRE(valid0.valid());
|
||||
auto valid1 = lua.safe_script("assert(not f(nil))", sol::script_pass_on_error);
|
||||
REQUIRE(valid1.valid());
|
||||
auto valid2 = lua.safe_script("assert(f(1))", sol::script_pass_on_error);
|
||||
REQUIRE(valid2.valid());
|
||||
auto valid3 = lua.safe_script("assert(f('hi'))", sol::script_pass_on_error);
|
||||
REQUIRE(valid3.valid());
|
||||
}
|
||||
|
||||
TEST_CASE("pusher/constness", "Make sure more types can handle being const and junk") {
|
||||
struct Foo {
|
||||
Foo(const sol::function& f)
|
||||
: _f(f) {
|
||||
}
|
||||
const sol::function& _f;
|
||||
|
||||
const sol::function& f() const {
|
||||
return _f;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.new_usertype<Foo>("Foo",
|
||||
sol::call_constructor, sol::no_constructor,
|
||||
"f", &Foo::f);
|
||||
|
||||
lua["func"] = []() { return 20; };
|
||||
sol::function f = lua["func"];
|
||||
lua["foo"] = Foo(f);
|
||||
Foo& foo = lua["foo"];
|
||||
int x = foo.f()();
|
||||
REQUIRE(x == 20);
|
||||
}
|
||||
|
||||
TEST_CASE("compilation/const regression", "make sure constness in tables is respected all the way down") {
|
||||
struct State {
|
||||
public:
|
||||
State() {
|
||||
this->state_.registry()["state"] = this;
|
||||
}
|
||||
|
||||
sol::state state_;
|
||||
};
|
||||
|
||||
State state;
|
||||
State* s = state.state_.registry()["state"];
|
||||
REQUIRE(s == &state);
|
||||
}
|
||||
|
||||
TEST_CASE("numbers/integers", "make sure integers are detectable on most platforms") {
|
||||
sol::state lua;
|
||||
|
||||
lua["a"] = 50; // int
|
||||
lua["b"] = 50.5; // double
|
||||
|
||||
sol::object a = lua["a"];
|
||||
sol::object b = lua["b"];
|
||||
|
||||
bool a_is_int = a.is<int>();
|
||||
bool a_is_double = a.is<double>();
|
||||
|
||||
bool b_is_int = b.is<int>();
|
||||
bool b_is_double = b.is<double>();
|
||||
|
||||
REQUIRE(a_is_int);
|
||||
REQUIRE(a_is_double);
|
||||
|
||||
// TODO: will this fail on certain lower Lua versions?
|
||||
REQUIRE_FALSE(b_is_int);
|
||||
REQUIRE(b_is_double);
|
||||
}
|
||||
|
||||
TEST_CASE("object/is", "test whether or not the is abstraction works properly for a user-defined type") {
|
||||
struct thing {};
|
||||
|
||||
SECTION("stack_object") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.set_function("is_thing", [](sol::stack_object obj) { return obj.is<thing>(); });
|
||||
lua["a"] = thing{};
|
||||
{
|
||||
auto result = lua.safe_script("assert(is_thing(a))", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.set_function("is_thing", [](sol::object obj) { return obj.is<thing>(); });
|
||||
lua["a"] = thing{};
|
||||
{
|
||||
auto result = lua.safe_script("assert(is_thing(a))", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
#include "catch.hpp"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int result = Catch::Session().run(argc, argv);
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user