diff options
author | clyne <clyne@bitgloo.com> | 2022-11-17 07:41:09 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-17 07:41:09 -0500 |
commit | 6663c25633a27fcc14d0648bd1afea7ea12f497f (patch) | |
tree | dcc2ec993db3c4b75c3e7e3df35b0494a9ce1f32 /lib/sol2/tests/runtime_tests/source/coroutines.cpp | |
parent | da0913771538fd9b1ca538615fd9aa0388608466 (diff) | |
parent | 57013add5b7c524086272be7d395f9ec5109bde2 (diff) |
Lib cleanup
Diffstat (limited to 'lib/sol2/tests/runtime_tests/source/coroutines.cpp')
-rw-r--r-- | lib/sol2/tests/runtime_tests/source/coroutines.cpp | 636 |
1 files changed, 0 insertions, 636 deletions
diff --git a/lib/sol2/tests/runtime_tests/source/coroutines.cpp b/lib/sol2/tests/runtime_tests/source/coroutines.cpp deleted file mode 100644 index db07494..0000000 --- a/lib/sol2/tests/runtime_tests/source/coroutines.cpp +++ /dev/null @@ -1,636 +0,0 @@ -// sol3 - -// The MIT License (MIT) - -// Copyright (c) 2013-2019 Rapptz, ThePhD and contributors - -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#include "sol_test.hpp" - -#include <catch.hpp> - -struct coro_h { - int x = 500; - int func() { - x += 1; - return x; - } -}; - -struct coro_test { - std::string identifier; - sol::reference obj; - - coro_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; - } - - ~coro_test() { - } -}; - -struct coro_test_implicit { - std::string identifier; - sol::main_reference obj; - - coro_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; - } - - ~coro_test_implicit() { - } -}; - -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; - sol::stack_guard luasg(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; - sol::stack_guard luasg(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; - sol::stack_guard luasg(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 = coro_test.new("x") -local co = coroutine.wrap( - function() - local t = coro_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 -)"; - - sol::state lua; - lua.open_libraries(sol::lib::coroutine, sol::lib::base); - - lua.new_usertype<coro_test>("coro_test", - sol::constructors<coro_test(sol::this_state, std::string)>(), - "store", &coro_test::store, - "copy_store", &coro_test::copy_store, - "get", &coro_test::get); - - auto r = lua.safe_script(code, sol::script_pass_on_error); - REQUIRE(r.valid()); - - coro_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 = coro_test.new("x") -local co = coroutine.wrap( - function() - local t = coro_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 coro_test_implicit { - std::string identifier; - sol::reference obj; - - coro_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; - } - - ~coro_test_implicit() { - } - }; - - sol::state lua; - lua.open_libraries(sol::lib::coroutine, sol::lib::base); - - lua.new_usertype<coro_test_implicit>("coro_test", - sol::constructors<coro_test_implicit(sol::this_state, std::string)>(), - "store", &coro_test_implicit::store, - "copy_store", &coro_test_implicit::copy_store, - "get", &coro_test_implicit::get); - - auto r = lua.safe_script(code, sol::script_pass_on_error); - REQUIRE(r.valid()); - - coro_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 = coro_test.new("x") -local co = coroutine.wrap( - function() - local t = coro_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() -)"; - - sol::state lua; - lua.open_libraries(sol::lib::coroutine, sol::lib::base); - - lua.new_usertype<coro_test_implicit>("coro_test", - sol::constructors<coro_test_implicit(sol::this_state, std::string)>(), - "store", &coro_test_implicit::store, - "copy_store", &coro_test_implicit::copy_store, - "get", &coro_test_implicit::get); - - auto r = lua.safe_script(code, sol::script_pass_on_error); - REQUIRE(r.valid()); - - coro_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_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 sol3 bound function can yield when marked yieldable") { - SECTION("regular functions") { - sol::state lua; - lua.open_libraries(sol::lib::base, sol::lib::coroutine); - - int i = 0; - auto func = [&i]() { - ++i; - return i; - }; - - coro_h hobj{}; - - lua["f"] = sol::yielding(func); - lua["g"] = sol::yielding([]() { return 300; }); - lua["h"] = sol::yielding(&coro_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, sol::script_pass_on_error); - 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 == 501); - - REQUIRE(hobj.x == 501); - } - SECTION("usertypes") { - sol::state lua; - lua.open_libraries(sol::lib::base, sol::lib::coroutine); - - coro_h hobj; - - lua["hobj"] = &hobj; - - lua.new_usertype<coro_h>("coro_h", - "h", sol::yielding(&coro_h::func) - ); - - sol::string_view code = R"( - co4 = coroutine.create(function() - hobj:h() - hobj.h(hobj) - coro_h.h(hobj) - end) - success4, value4 = coroutine.resume(co4) - success5, value5 = coroutine.resume(co4) - success6, value6 = coroutine.resume(co4) - )"; - - auto result = lua.safe_script(code, sol::script_pass_on_error); - REQUIRE(result.valid()); - - bool success4 = lua["success4"]; - int value4 = lua["value4"]; - REQUIRE(success4); - REQUIRE(value4 == 501); - - bool success5 = lua["success5"]; - int value5 = lua["value5"]; - REQUIRE(success5); - REQUIRE(value5 == 502); - - bool success6 = lua["success6"]; - int value6 = lua["value6"]; - REQUIRE(success6); - REQUIRE(value6 == 503); - - REQUIRE(hobj.x == 503); - } -} |