variables (fixes #118).main
| TEST_CASE("exit function called on destruction", "[ScopeExit]") | TEST_CASE("exit function called on destruction", "[ScopeExit]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter()); | REQUIRE_CALL(m, deleter()); | ||||
| auto guard = sr::scope_exit{deleter}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::scope_exit{deleter}; | |||||
| } | } | ||||
| TEST_CASE("exit function lambda called on destruction", "[ScopeExit]") | TEST_CASE("exit function lambda called on destruction", "[ScopeExit]") | ||||
| { | { | ||||
| CallMock cm; | CallMock cm; | ||||
| REQUIRE_CALL(cm, deleter()); | REQUIRE_CALL(cm, deleter()); | ||||
| auto guard = sr::scope_exit{[&cm] { cm.deleter(); }}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::scope_exit{[&cm] { cm.deleter(); }}; | |||||
| } | } | ||||
| TEST_CASE("exit function called and rethrow on copy exception", "[ScopeExit]") | TEST_CASE("exit function called and rethrow on copy exception", "[ScopeExit]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter()); | REQUIRE_CALL(m, deleter()); | ||||
| auto movedFrom = sr::scope_exit{deleter}; | auto movedFrom = sr::scope_exit{deleter}; | ||||
| auto guard = std::move(movedFrom); | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = std::move(movedFrom); | |||||
| } | } | ||||
| TEST_CASE("move with copy init releases moved-from object", "[ScopeExit]") | TEST_CASE("move with copy init releases moved-from object", "[ScopeExit]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter()); | REQUIRE_CALL(m, deleter()); | ||||
| auto movedFrom = sr::scope_exit{deleter}; | auto movedFrom = sr::scope_exit{deleter}; | ||||
| auto guard = std::move(movedFrom); | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = std::move(movedFrom); | |||||
| } | } | ||||
| TEST_CASE("move transfers state if released", "[ScopeExit]") | TEST_CASE("move transfers state if released", "[ScopeExit]") | ||||
| REQUIRE_CALL(m, deleter()).TIMES(0); | REQUIRE_CALL(m, deleter()).TIMES(0); | ||||
| auto movedFrom = sr::scope_exit{deleter}; | auto movedFrom = sr::scope_exit{deleter}; | ||||
| movedFrom.release(); | movedFrom.release(); | ||||
| auto guard = std::move(movedFrom); | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = std::move(movedFrom); | |||||
| } | } | ||||
| TEST_CASE("exit function called on destruction", "[ScopeFail]") | TEST_CASE("exit function called on destruction", "[ScopeFail]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter()).TIMES(0); | REQUIRE_CALL(m, deleter()).TIMES(0); | ||||
| auto guard = sr::scope_fail{deleter}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::scope_fail{deleter}; | |||||
| } | } | ||||
| TEST_CASE("exit function lambda called on destruction", "[ScopeFail]") | TEST_CASE("exit function lambda called on destruction", "[ScopeFail]") | ||||
| { | { | ||||
| CallMock cm; | CallMock cm; | ||||
| REQUIRE_CALL(cm, deleter()).TIMES(0); | REQUIRE_CALL(cm, deleter()).TIMES(0); | ||||
| auto guard = sr::scope_fail{[&cm] { cm.deleter(); }}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::scope_fail{[&cm] { cm.deleter(); }}; | |||||
| } | } | ||||
| TEST_CASE("exit function called and rethrow on copy exception", "[ScopeFail]") | TEST_CASE("exit function called and rethrow on copy exception", "[ScopeFail]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter()).TIMES(0); | REQUIRE_CALL(m, deleter()).TIMES(0); | ||||
| auto movedFrom = sr::scope_fail{deleter}; | auto movedFrom = sr::scope_fail{deleter}; | ||||
| auto guard = std::move(movedFrom); | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = std::move(movedFrom); | |||||
| } | } | ||||
| TEST_CASE("move with copy init releases moved-from object", "[ScopeFail]") | TEST_CASE("move with copy init releases moved-from object", "[ScopeFail]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter()).TIMES(0); | REQUIRE_CALL(m, deleter()).TIMES(0); | ||||
| auto movedFrom = sr::scope_fail{deleter}; | auto movedFrom = sr::scope_fail{deleter}; | ||||
| auto guard = std::move(movedFrom); | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = std::move(movedFrom); | |||||
| } | } | ||||
| TEST_CASE("move transfers state if released", "[ScopeFail]") | TEST_CASE("move transfers state if released", "[ScopeFail]") | ||||
| REQUIRE_CALL(m, deleter()).TIMES(0); | REQUIRE_CALL(m, deleter()).TIMES(0); | ||||
| auto movedFrom = sr::scope_fail{deleter}; | auto movedFrom = sr::scope_fail{deleter}; | ||||
| movedFrom.release(); | movedFrom.release(); | ||||
| auto guard = std::move(movedFrom); | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = std::move(movedFrom); | |||||
| } | } | ||||
| TEST_CASE("exit function called on exception", "[ScopeFail]") | TEST_CASE("exit function called on exception", "[ScopeFail]") | ||||
| try | try | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter()); | REQUIRE_CALL(m, deleter()); | ||||
| auto guard = sr::scope_fail{deleter}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::scope_fail{deleter}; | |||||
| throw 3; | throw 3; | ||||
| } | } | ||||
| catch( ... ) | catch( ... ) | ||||
| } | } | ||||
| catch( ... ) | catch( ... ) | ||||
| { | { | ||||
| auto guard = sr::scope_fail{deleter}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::scope_fail{deleter}; | |||||
| } | } | ||||
| } | } | ||||
| TEST_CASE("exit function called on destruction", "[ScopeSuccess]") | TEST_CASE("exit function called on destruction", "[ScopeSuccess]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter()); | REQUIRE_CALL(m, deleter()); | ||||
| auto guard = sr::scope_success{deleter}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::scope_success{deleter}; | |||||
| } | } | ||||
| TEST_CASE("exit function lambda called on destruction", "[ScopeSuccess]") | TEST_CASE("exit function lambda called on destruction", "[ScopeSuccess]") | ||||
| { | { | ||||
| CallMock cm; | CallMock cm; | ||||
| REQUIRE_CALL(cm, deleter()); | REQUIRE_CALL(cm, deleter()); | ||||
| auto guard = sr::scope_success{[&cm] { cm.deleter(); }}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::scope_success{[&cm] { cm.deleter(); }}; | |||||
| } | } | ||||
| TEST_CASE("exit function not called and rethrow on copy exception", "[ScopeSuccess]") | TEST_CASE("exit function not called and rethrow on copy exception", "[ScopeSuccess]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter()); | REQUIRE_CALL(m, deleter()); | ||||
| auto movedFrom = sr::scope_success{deleter}; | auto movedFrom = sr::scope_success{deleter}; | ||||
| auto guard = std::move(movedFrom); | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = std::move(movedFrom); | |||||
| } | } | ||||
| TEST_CASE("move with copy init releases moved-from object", "[ScopeSuccess]") | TEST_CASE("move with copy init releases moved-from object", "[ScopeSuccess]") | ||||
| const NotNothrowMoveMock notNothrow{&mock}; | const NotNothrowMoveMock notNothrow{&mock}; | ||||
| REQUIRE_CALL(mock, deleter()); | REQUIRE_CALL(mock, deleter()); | ||||
| sr::scope_success movedFrom{notNothrow}; | sr::scope_success movedFrom{notNothrow}; | ||||
| auto guard = std::move(movedFrom); | |||||
| [[maybe_unused]] auto guard = std::move(movedFrom); | |||||
| } | } | ||||
| TEST_CASE("move transfers state", "[ScopeSuccess]") | TEST_CASE("move transfers state", "[ScopeSuccess]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter()); | REQUIRE_CALL(m, deleter()); | ||||
| auto movedFrom = sr::scope_success{deleter}; | auto movedFrom = sr::scope_success{deleter}; | ||||
| auto guard = std::move(movedFrom); | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = std::move(movedFrom); | |||||
| } | } | ||||
| TEST_CASE("move transfers state if released", "[ScopeSuccess]") | TEST_CASE("move transfers state if released", "[ScopeSuccess]") | ||||
| REQUIRE_CALL(m, deleter()).TIMES(0); | REQUIRE_CALL(m, deleter()).TIMES(0); | ||||
| auto movedFrom = sr::scope_success{deleter}; | auto movedFrom = sr::scope_success{deleter}; | ||||
| movedFrom.release(); | movedFrom.release(); | ||||
| auto guard = std::move(movedFrom); | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = std::move(movedFrom); | |||||
| } | } | ||||
| TEST_CASE("exit function not called on exception", "[ScopeFail]") | TEST_CASE("exit function not called on exception", "[ScopeFail]") | ||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| auto guard = sr::scope_success{deleter}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::scope_success{deleter}; | |||||
| throw 3; | throw 3; | ||||
| } | } | ||||
| catch( ... ) | catch( ... ) | ||||
| catch( ... ) | catch( ... ) | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter()); | REQUIRE_CALL(m, deleter()); | ||||
| auto guard = sr::scope_success{deleter}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::scope_success{deleter}; | |||||
| } | } | ||||
| } | } | ||||
| TEST_CASE("construction with move", "[UniqueResource]") | TEST_CASE("construction with move", "[UniqueResource]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter(3)); | REQUIRE_CALL(m, deleter(3)); | ||||
| auto guard = sr::unique_resource{Handle{3}, deleter}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::unique_resource{Handle{3}, deleter}; | |||||
| } | } | ||||
| TEST_CASE("construction with copy", "[UniqueResource]") | TEST_CASE("construction with copy", "[UniqueResource]") | ||||
| REQUIRE_CALL(m, deleter(3)); | REQUIRE_CALL(m, deleter(3)); | ||||
| const Handle h{3}; | const Handle h{3}; | ||||
| const auto d = [](auto v) { m.deleter(v); }; | const auto d = [](auto v) { m.deleter(v); }; | ||||
| auto guard = sr::unique_resource{h, d}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::unique_resource{h, d}; | |||||
| } | } | ||||
| TEST_CASE("construction with copy calls deleter and rethrows on failed copy", "[UniqueResource]") | TEST_CASE("construction with copy calls deleter and rethrows on failed copy", "[UniqueResource]") | ||||
| const auto d = [](const auto&) { m.deleter(3); }; | const auto d = [](const auto&) { m.deleter(3); }; | ||||
| REQUIRE_CALL(m, deleter(3)); | REQUIRE_CALL(m, deleter(3)); | ||||
| sr::unique_resource guard{noMove, d}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] sr::unique_resource guard{noMove, d}; | |||||
| }()); | }()); | ||||
| } | } | ||||
| const CopyMock copyMock; | const CopyMock copyMock; | ||||
| sr::unique_resource movedFrom{copyMock, d}; | sr::unique_resource movedFrom{copyMock, d}; | ||||
| auto guard = std::move(movedFrom); | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = std::move(movedFrom); | |||||
| } | } | ||||
| TEST_CASE("move assignment calls deleter", "[UniqueResource]") | TEST_CASE("move assignment calls deleter", "[UniqueResource]") | ||||
| TEST_CASE("deleter called on destruction", "[UniqueResource]") | TEST_CASE("deleter called on destruction", "[UniqueResource]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter(3)); | REQUIRE_CALL(m, deleter(3)); | ||||
| auto guard = sr::unique_resource{Handle{3}, deleter}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::unique_resource{Handle{3}, deleter}; | |||||
| } | } | ||||
| TEST_CASE("reset calls deleter", "[UniqueResource]") | TEST_CASE("reset calls deleter", "[UniqueResource]") | ||||
| TEST_CASE("make unique resource", "[UniqueResource]") | TEST_CASE("make unique resource", "[UniqueResource]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter(7)); | REQUIRE_CALL(m, deleter(7)); | ||||
| auto guard = sr::unique_resource{Handle{7}, deleter}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::unique_resource{Handle{7}, deleter}; | |||||
| } | } | ||||
| TEST_CASE("make unique resource with reference wrapper", "[UniqueResource]") | TEST_CASE("make unique resource with reference wrapper", "[UniqueResource]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter(3)); | REQUIRE_CALL(m, deleter(3)); | ||||
| Handle h{3}; | Handle h{3}; | ||||
| auto guard = sr::unique_resource{std::ref(h), deleter}; | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::unique_resource{std::ref(h), deleter}; | |||||
| } | } | ||||
| TEST_CASE("make unique resource checked", "[UniqueResource]") | TEST_CASE("make unique resource checked", "[UniqueResource]") | ||||
| { | { | ||||
| REQUIRE_CALL(m, deleter(4)); | REQUIRE_CALL(m, deleter(4)); | ||||
| auto guard = sr::make_unique_resource_checked(Handle{4}, Handle{-1}, deleter); | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::make_unique_resource_checked(Handle{4}, Handle{-1}, deleter); | |||||
| } | } | ||||
| TEST_CASE("make unique resource checked releases if invalid", "[UniqueResource]") | TEST_CASE("make unique resource checked releases if invalid", "[UniqueResource]") | ||||
| { | { | ||||
| auto guard = sr::make_unique_resource_checked(Handle{-1}, Handle{-1}, deleter); | |||||
| static_cast<void>(guard); | |||||
| [[maybe_unused]] auto guard = sr::make_unique_resource_checked(Handle{-1}, Handle{-1}, deleter); | |||||
| } | } | ||||