aboutsummaryrefslogtreecommitdiff
path: root/unit_tests
diff options
context:
space:
mode:
Diffstat (limited to 'unit_tests')
-rw-r--r--unit_tests/_pch.cpp14
-rw-r--r--unit_tests/lane_tests.cpp10
-rw-r--r--unit_tests/scripts/lane/uncooperative_shutdown.lua4
-rw-r--r--unit_tests/shared.cpp82
-rw-r--r--unit_tests/shared.h5
5 files changed, 66 insertions, 49 deletions
diff --git a/unit_tests/_pch.cpp b/unit_tests/_pch.cpp
index 189089a..0d37ba4 100644
--- a/unit_tests/_pch.cpp
+++ b/unit_tests/_pch.cpp
@@ -1,15 +1 @@
1#include "_pch.hpp" #include "_pch.hpp"
2
3// IMPORTANT INFORMATION: some relative paths coded in the test implementations suppose that the cwd when debugging is $(SolutionDir)Lanes
4// Therefore that's what needs to be set in Google Test Adapter 'Working Directory' global setting...
5
6//int main(int argc, char* argv[])
7//{
8// // your setup ...
9//
10// int result = Catch::Session().run(argc, argv);
11//
12// // your clean-up...
13//
14// return result;
15//} \ No newline at end of file
diff --git a/unit_tests/lane_tests.cpp b/unit_tests/lane_tests.cpp
index 0c4feba..d6ef2e0 100644
--- a/unit_tests/lane_tests.cpp
+++ b/unit_tests/lane_tests.cpp
@@ -327,10 +327,10 @@ TEST_CASE("scripted tests." #DIR "." #FILE) \
327} 327}
328 328
329MAKE_TEST_CASE(lane, cooperative_shutdown, AssertNoLuaError) 329MAKE_TEST_CASE(lane, cooperative_shutdown, AssertNoLuaError)
330#if LUAJIT_FLAVOR() == 0 330#if LUA_VERSION_NUM >= 504 // // warnings are a Lua 5.4 feature
331// TODO: for some reason, even though we throw as expected, the test fails with LuaJIT. To be investigated 331// NOTE: when this test ends, there are resource leaks and a dangling thread
332MAKE_TEST_CASE(lane, uncooperative_shutdown, AssertThrows) 332MAKE_TEST_CASE(lane, uncooperative_shutdown, AssertWarns)
333#endif // LUAJIT_FLAVOR() 333#endif // LUA_VERSION_NUM
334MAKE_TEST_CASE(lane, tasking_basic, AssertNoLuaError) 334MAKE_TEST_CASE(lane, tasking_basic, AssertNoLuaError)
335MAKE_TEST_CASE(lane, tasking_cancelling, AssertNoLuaError) 335MAKE_TEST_CASE(lane, tasking_cancelling, AssertNoLuaError)
336MAKE_TEST_CASE(lane, tasking_comms_criss_cross, AssertNoLuaError) 336MAKE_TEST_CASE(lane, tasking_comms_criss_cross, AssertNoLuaError)
@@ -350,7 +350,7 @@ TEST_CASE("lanes.scripted tests")
350{ 350{
351 auto const& _testParam = GENERATE( 351 auto const& _testParam = GENERATE(
352 FileRunnerParam{ PUC_LUA_ONLY("lane/cooperative_shutdown"), TestType::AssertNoLuaError }, // 0 352 FileRunnerParam{ PUC_LUA_ONLY("lane/cooperative_shutdown"), TestType::AssertNoLuaError }, // 0
353 FileRunnerParam{ "lane/uncooperative_shutdown", TestType::AssertThrows }, 353 FileRunnerParam{ "lane/uncooperative_shutdown", TestType::AssertWarns },
354 FileRunnerParam{ "lane/tasking_basic", TestType::AssertNoLuaError }, // 2 354 FileRunnerParam{ "lane/tasking_basic", TestType::AssertNoLuaError }, // 2
355 FileRunnerParam{ "lane/tasking_cancelling", TestType::AssertNoLuaError }, // 3 355 FileRunnerParam{ "lane/tasking_cancelling", TestType::AssertNoLuaError }, // 3
356 FileRunnerParam{ "lane/tasking_comms_criss_cross", TestType::AssertNoLuaError }, // 4 356 FileRunnerParam{ "lane/tasking_comms_criss_cross", TestType::AssertNoLuaError }, // 4
diff --git a/unit_tests/scripts/lane/uncooperative_shutdown.lua b/unit_tests/scripts/lane/uncooperative_shutdown.lua
index 51e5762..89e1ff8 100644
--- a/unit_tests/scripts/lane/uncooperative_shutdown.lua
+++ b/unit_tests/scripts/lane/uncooperative_shutdown.lua
@@ -8,7 +8,7 @@ local lanes = require "lanes".configure{shutdown_timeout = 0.001, on_state_creat
8-- launch lanes that blocks forever 8-- launch lanes that blocks forever
9local lane = function() 9local lane = function()
10 local fixture = require "fixture" 10 local fixture = require "fixture"
11 fixture.forever() 11 fixture.sleep_for()
12end 12end
13 13
14-- the generator 14-- the generator
@@ -20,5 +20,5 @@ local h1 = g1()
20-- wait until the lane is running 20-- wait until the lane is running
21repeat until h1.status == "running" 21repeat until h1.status == "running"
22 22
23-- let the script end, Lanes should throw std::logic_error because the lane did not gracefully terminate 23-- this finalizer returns an error string that telling Universe::__gc will use to raise an error when it detects the uncooperative lane
24lanes.finally(fixture.throwing_finalizer) 24lanes.finally(fixture.throwing_finalizer)
diff --git a/unit_tests/shared.cpp b/unit_tests/shared.cpp
index d139579..2e2af73 100644
--- a/unit_tests/shared.cpp
+++ b/unit_tests/shared.cpp
@@ -25,35 +25,19 @@ namespace
25 STACK_CHECK(L_, 0); 25 STACK_CHECK(L_, 0);
26 } 26 }
27 27
28
29 static std::map<lua_State*, std::atomic_flag> sFinalizerHits; 28 static std::map<lua_State*, std::atomic_flag> sFinalizerHits;
30 static std::mutex sCallCountsLock; 29 static std::mutex sCallCountsLock;
31 30
32 // a finalizer that we can detect even after closing the state 31 // a finalizer that we can detect even after closing the state
33 lua_CFunction sThrowingFinalizer = +[](lua_State* L_) { 32 lua_CFunction sFreezingFinalizer = +[](lua_State* const L_) {
34 std::lock_guard _guard{ sCallCountsLock }; 33 std::lock_guard _guard{ sCallCountsLock };
35 sFinalizerHits[L_].test_and_set(); 34 sFinalizerHits[L_].test_and_set();
36 luaG_pushstring(L_, "throw"); 35 luaG_pushstring(L_, "freeze"); // just freeze the thread in place so that it can be debugged
37 return 1; 36 return 1;
38 }; 37 };
39 38
40 // a finalizer that we can detect even after closing the state
41 lua_CFunction sYieldingFinalizer = +[](lua_State* L_) {
42 std::lock_guard _guard{ sCallCountsLock };
43 sFinalizerHits[L_].test_and_set();
44 return 0;
45 };
46
47 // a function that runs forever
48 lua_CFunction sForever = +[](lua_State* L_) {
49 while (true) {
50 std::this_thread::yield();
51 }
52 return 0;
53 };
54
55 // a function that returns immediately (so that LuaJIT issues a function call for it) 39 // a function that returns immediately (so that LuaJIT issues a function call for it)
56 lua_CFunction sGiveMeBack = +[](lua_State* L_) { 40 lua_CFunction sGiveMeBack = +[](lua_State* const L_) {
57 return lua_gettop(L_); 41 return lua_gettop(L_);
58 }; 42 };
59 43
@@ -74,14 +58,42 @@ namespace
74 return 0; 58 return 0;
75 }; 59 };
76 60
61 // a function that sleeps for the specified duration (in seconds)
62 lua_CFunction sSleepFor = +[](lua_State* const L_) {
63 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
64 lua_settop(L_, 1);
65 if (luaG_type(L_, kIdxTop) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion
66 lua_Duration const _duration{ lua_tonumber(L_, kIdxTop) };
67 if (_duration.count() >= 0.0) {
68 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(_duration);
69 } else {
70 raise_luaL_argerror(L_, kIdxTop, "duration cannot be < 0");
71 }
72
73 } else if (!lua_isnoneornil(L_, 2)) {
74 raise_luaL_argerror(L_, StackIndex{ 2 }, "incorrect duration type");
75 }
76 std::this_thread::sleep_until(_until);
77 return 0;
78 };
79
80 // a finalizer that we can detect even after closing the state
81 lua_CFunction sThrowingFinalizer = +[](lua_State* const L_) {
82 std::lock_guard _guard{ sCallCountsLock };
83 sFinalizerHits[L_].test_and_set();
84 bool const _allLanesTerminated = lua_toboolean(L_, kIdxTop);
85 luaG_pushstring(L_, "Finalizer%s", _allLanesTerminated ? "" : ": Uncooperative lanes detected");
86 return 1;
87 };
88
77 static luaL_Reg const sFixture[] = { 89 static luaL_Reg const sFixture[] = {
78 { "forever", sForever }, 90 { "freezing_finalizer", sFreezingFinalizer },
79 { "give_me_back()", sGiveMeBack }, 91 { "give_me_back()", sGiveMeBack },
80 { "newlightuserdata", sNewLightUserData }, 92 { "newlightuserdata", sNewLightUserData },
81 { "newuserdata", sNewUserData }, 93 { "newuserdata", sNewUserData },
82 { "on_state_create", sOnStateCreate }, 94 { "on_state_create", sOnStateCreate },
95 { "sleep_for", sSleepFor },
83 { "throwing_finalizer", sThrowingFinalizer }, 96 { "throwing_finalizer", sThrowingFinalizer },
84 { "yielding_finalizer", sYieldingFinalizer },
85 { nullptr, nullptr } 97 { nullptr, nullptr }
86 }; 98 };
87 } // namespace local 99 } // namespace local
@@ -448,16 +460,34 @@ FileRunner::FileRunner(std::string_view const& where_)
448 460
449void FileRunner::performTest(FileRunnerParam const& testParam_) 461void FileRunner::performTest(FileRunnerParam const& testParam_)
450{ 462{
463 static constexpr auto _atPanic = [](lua_State* const L_) {
464 throw std::logic_error("panic!");
465 return 0;
466 };
467
468#if LUA_VERSION_NUM >= 504 // // warnings are a Lua 5.4 feature
469 std::string _warnMessage;
470 static constexpr auto _onWarn = [](void* const opaque_, char const* const msg_, int const tocont_) {
471 std::string& _warnMessage = *static_cast<std::string*>(opaque_);
472 _warnMessage += msg_;
473 };
474#endif // LUA_VERSION_NUM
475
451 INFO(testParam_.script); 476 INFO(testParam_.script);
452 switch (testParam_.test) { 477 switch (testParam_.test) {
453 case TestType::AssertNoLuaError: 478 case TestType::AssertNoLuaError:
454 requireSuccess(root, testParam_.script); 479 requireSuccess(root, testParam_.script);
455 break; 480 break;
456 case TestType::AssertNoThrow: 481
457 REQUIRE_NOTHROW((std::ignore = doFile(root, testParam_.script), close())); 482#if LUA_VERSION_NUM >= 504 // // warnings are a Lua 5.4 feature
458 break; 483 case TestType::AssertWarns:
459 case TestType::AssertThrows: 484 lua_atpanic(L, _atPanic);
460 REQUIRE_THROWS_AS((std::ignore = doFile(root, testParam_.script), close()), std::logic_error); 485 lua_setwarnf(L, _onWarn, &_warnMessage);
486 std::ignore = doFile(root, testParam_.script);
487 close();
488 WARN(_warnMessage);
489 REQUIRE(_warnMessage != std::string_view{});
461 break; 490 break;
491#endif // LUA_VERSION_NUM
462 } 492 }
463} 493}
diff --git a/unit_tests/shared.h b/unit_tests/shared.h
index 8a84a94..b884df0 100644
--- a/unit_tests/shared.h
+++ b/unit_tests/shared.h
@@ -66,8 +66,9 @@ class LuaState
66enum class [[nodiscard]] TestType 66enum class [[nodiscard]] TestType
67{ 67{
68 AssertNoLuaError, 68 AssertNoLuaError,
69 AssertNoThrow, 69#if LUA_VERSION_NUM >= 504 // warnings are a Lua 5.4 feature
70 AssertThrows, 70 AssertWarns,
71#endif // LUA_VERSION_NUM
71}; 72};
72 73
73struct FileRunnerParam 74struct FileRunnerParam