diff options
Diffstat (limited to '')
-rw-r--r-- | unit_tests/init_and_shutdown.cpp | 129 |
1 files changed, 65 insertions, 64 deletions
diff --git a/unit_tests/init_and_shutdown.cpp b/unit_tests/init_and_shutdown.cpp index 7450a80..7e4c215 100644 --- a/unit_tests/init_and_shutdown.cpp +++ b/unit_tests/init_and_shutdown.cpp | |||
@@ -668,75 +668,76 @@ TEST_CASE("lanes.configure") | |||
668 | // ################################################################################################# | 668 | // ################################################################################################# |
669 | // ################################################################################################# | 669 | // ################################################################################################# |
670 | 670 | ||
671 | TEST_CASE("lanes.finally") | 671 | #if LUAJIT_FLAVOR() == 0 |
672 | // TODO: this test crashes inside S.close() against LuaJIT. to be investigated | ||
673 | TEST_CASE("lanes.finally.no fixture") | ||
672 | { | 674 | { |
673 | SECTION("no fixture") | 675 | LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; |
674 | { | 676 | // we need Lanes to be up. Since we run several 'scripts', we store it as a global |
675 | LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; | 677 | S.requireSuccess("lanes = require 'lanes'.configure()"); |
676 | // we need Lanes to be up. Since we run several 'scripts', we store it as a global | 678 | // we can set a function |
677 | S.requireSuccess("lanes = require 'lanes'.configure()"); | 679 | S.requireSuccess("lanes.finally(function() end)"); |
678 | // we can set a function | 680 | // we can clear it |
679 | S.requireSuccess("lanes.finally(function() end)"); | 681 | S.requireSuccess("lanes.finally(nil)"); |
680 | // we can clear it | 682 | // we can set a new one |
681 | S.requireSuccess("lanes.finally(nil)"); | 683 | S.requireSuccess("lanes.finally(function() end)"); |
682 | // we can set a new one | 684 | // we can replace an existing function |
683 | S.requireSuccess("lanes.finally(function() end)"); | 685 | S.requireSuccess("lanes.finally(error)"); |
684 | // we can replace an existing function | 686 | // even if the finalizer throws a Lua error, it shouldn't crash anything |
685 | S.requireSuccess("lanes.finally(error)"); | 687 | REQUIRE_NOTHROW(S.close()); // TODO: use lua_atpanic to catch errors during close() |
686 | // even if the finalizer throws a Lua error, it shouldn't crash anything | 688 | REQUIRE_FALSE(S.finalizerWasCalled); |
687 | REQUIRE_NOTHROW(S.close()); // TODO: use lua_atpanic to catch errors during close() | 689 | } |
688 | REQUIRE_FALSE(S.finalizerWasCalled); | 690 | #endif // LUAJIT_FLAVOR |
689 | } | ||
690 | 691 | ||
691 | // --------------------------------------------------------------------------------------------- | 692 | // ################################################################################################# |
692 | 693 | ||
693 | SECTION("with fixture") | 694 | TEST_CASE("lanes.finally.with fixture") |
694 | { | 695 | { |
695 | LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; | 696 | LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; |
696 | 697 | ||
697 | // we need Lanes to be up. Since we run several 'scripts', we store it as a global | 698 | // we need Lanes to be up. Since we run several 'scripts', we store it as a global |
698 | S.requireSuccess("lanes = require 'lanes'.configure()"); | 699 | S.requireSuccess("lanes = require 'lanes'.configure()"); |
699 | // works because we have package.preload.fixture = luaopen_fixture | 700 | // works because we have package.preload.fixture = luaopen_fixture |
700 | S.requireSuccess("fixture = require 'fixture'"); | 701 | S.requireSuccess("fixture = require 'fixture'"); |
701 | // set our detectable finalizer | 702 | // set our detectable finalizer |
702 | S.requireSuccess("lanes.finally(fixture.throwing_finalizer)"); | 703 | S.requireSuccess("lanes.finally(fixture.throwing_finalizer)"); |
703 | // even if the finalizer can request a C++ exception, it shouldn't do it just now since we have no dangling lane | 704 | // even if the finalizer can request a C++ exception, it shouldn't do it just now since we have no dangling lane |
704 | REQUIRE_NOTHROW(S.close()); | 705 | REQUIRE_NOTHROW(S.close()); |
705 | // the finalizer should be called | 706 | // the finalizer should be called |
706 | REQUIRE(S.finalizerWasCalled); | 707 | REQUIRE(S.finalizerWasCalled); |
707 | } | 708 | } |
708 | 709 | ||
709 | // --------------------------------------------------------------------------------------------- | 710 | // ################################################################################################# |
710 | 711 | ||
711 | SECTION("shutdown with an uncooperative lane") | 712 | TEST_CASE("lanes.finally.shutdown with an uncooperative lane") |
712 | { | 713 | { |
713 | LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; | 714 | LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; |
714 | S.requireSuccess("lanes = require 'lanes'.configure()"); | 715 | S.requireSuccess("lanes = require 'lanes'.configure()"); |
715 | 716 | ||
716 | // prepare a callback for lanes.finally() | 717 | // prepare a callback for lanes.finally() |
717 | static bool _wasCalled{}; | 718 | static bool _wasCalled{}; |
718 | static bool _allLanesTerminated{}; | 719 | static bool _allLanesTerminated{}; |
719 | auto _finallyCB{ +[](lua_State* const L_) { _wasCalled = true; _allLanesTerminated = lua_toboolean(L_, 1); return 0; } }; | 720 | auto _finallyCB{ +[](lua_State* const L_) { _wasCalled = true; _allLanesTerminated = lua_toboolean(L_, 1); return 0; } }; |
720 | lua_pushcfunction(S, _finallyCB); | 721 | lua_pushcfunction(S, _finallyCB); |
721 | lua_setglobal(S, "finallyCB"); | 722 | lua_setglobal(S, "finallyCB"); |
722 | // start a lane that lasts a long time | 723 | // start a lane that lasts a long time |
723 | std::string_view const _script{ | 724 | std::string_view const _script{ |
724 | " lanes.finally(finallyCB)" | 725 | " lanes.finally(finallyCB)" |
725 | " g = lanes.gen('*'," | 726 | " g = lanes.gen('*'," |
726 | " {name = 'auto'}," | 727 | " {name = 'auto'}," |
727 | " function()" | 728 | " function()" |
728 | " for i = 1,1e37 do end" // no cooperative cancellation checks here! | 729 | " local f = require 'fixture'" |
729 | " end)" | 730 | " for i = 1,1e37 do f.give_me_back() end" // no cooperative cancellation checks here, but opportunities for the cancellation hook to trigger |
730 | " g()" | 731 | " end)" |
731 | }; | 732 | " g()" |
732 | S.requireSuccess(_script); | 733 | }; |
733 | // close the state before the lane ends. | 734 | S.requireSuccess(_script); |
734 | // since we don't wait at all, it is possible that the OS thread for the lane hasn't even started at that point | 735 | // close the state before the lane ends. |
735 | S.close(); | 736 | // since we don't wait at all, it is possible that the OS thread for the lane hasn't even started at that point |
736 | // the finally handler should have been called, and told all lanes are stopped | 737 | S.close(); |
737 | REQUIRE(_wasCalled); | 738 | // the finally handler should have been called, and told all lanes are stopped |
738 | REQUIRE(_allLanesTerminated); | 739 | REQUIRE(_wasCalled); |
739 | } | 740 | REQUIRE(_allLanesTerminated); |
740 | } | 741 | } |
741 | 742 | ||
742 | // ################################################################################################# | 743 | // ################################################################################################# |