| @@ -63,7 +63,10 @@ namespace sr | |||
| && std::is_nothrow_move_constructible_v<D>) | |||
| : resource(std::move_if_noexcept(other.resource.get()), scope_exit{[] { }}), | |||
| deleter(std::move_if_noexcept(other.deleter.get()), scope_exit{[&other] { | |||
| other.get_deleter()(other.resource.get()); | |||
| if( other.execute_on_reset == true ) | |||
| { | |||
| other.get_deleter()(other.resource.get()); | |||
| } | |||
| other.release(); }}), | |||
| execute_on_reset(std::exchange(other.execute_on_reset, false)) | |||
| { | |||
| @@ -168,5 +168,28 @@ namespace mock | |||
| CopyMock(const CopyMock&) { } | |||
| }; | |||
| struct ConditionalThrowOnCopyDeleter | |||
| { | |||
| ConditionalThrowOnCopyDeleter() { } | |||
| ConditionalThrowOnCopyDeleter(const ConditionalThrowOnCopyDeleter&) | |||
| { | |||
| if( throwOnNextCopy == true ) | |||
| { | |||
| throw std::exception{}; | |||
| } | |||
| throwOnNextCopy = false; | |||
| } | |||
| MAKE_CONST_MOCK1(deleter, void(Handle)); | |||
| void operator()(Handle h) const | |||
| { | |||
| this->deleter(h); | |||
| } | |||
| static inline bool throwOnNextCopy{false}; | |||
| }; | |||
| } | |||
| @@ -81,6 +81,15 @@ TEST_CASE("move-construction with copy", "[UniqueResource]") | |||
| [[maybe_unused]] auto guard = std::move(movedFrom); | |||
| } | |||
| TEST_CASE("move-construction prevents double release", "[UniqueResource]") | |||
| { | |||
| auto movedFrom = sr::unique_resource{Handle{3}, ConditionalThrowOnCopyDeleter{}}; | |||
| movedFrom.release(); | |||
| ConditionalThrowOnCopyDeleter::throwOnNextCopy = true; | |||
| REQUIRE_THROWS([&movedFrom] { [[maybe_unused]] auto guard = std::move(movedFrom); }()); | |||
| } | |||
| TEST_CASE("move assignment calls deleter", "[UniqueResource]") | |||
| { | |||
| auto moveFrom = sr::unique_resource{Handle{3}, deleter}; | |||