You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
5.6KB

  1. /*
  2. * Scope Guard
  3. * Copyright (C) 2017-2018 offa
  4. *
  5. * This file is part of Scope Guard.
  6. *
  7. * Scope Guard is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * Scope Guard is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with Scope Guard. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "unique_resource.h"
  21. #include "CallMocks.h"
  22. #include <catch.hpp>
  23. #include <trompeloeil.hpp>
  24. using namespace mock;
  25. using namespace trompeloeil;
  26. namespace
  27. {
  28. CallMock m;
  29. void deleter(Handle h)
  30. {
  31. m.deleter(h);
  32. }
  33. }
  34. TEST_CASE("construction with move", "[UniqueResource]")
  35. {
  36. REQUIRE_CALL(m, deleter(3));
  37. [[maybe_unused]] auto guard = sr::unique_resource{Handle{3}, deleter};
  38. }
  39. TEST_CASE("construction with copy", "[UniqueResource]")
  40. {
  41. REQUIRE_CALL(m, deleter(3));
  42. const Handle h{3};
  43. const auto d = [](auto v) { m.deleter(v); };
  44. [[maybe_unused]] auto guard = sr::unique_resource{h, d};
  45. }
  46. TEST_CASE("construction with copy calls deleter and rethrows on failed copy", "[UniqueResource]")
  47. {
  48. REQUIRE_THROWS([] {
  49. const ThrowOnCopyMock noMove;
  50. const auto d = [](const auto&) { m.deleter(3); };
  51. REQUIRE_CALL(m, deleter(3));
  52. [[maybe_unused]] sr::unique_resource guard{noMove, d};
  53. }());
  54. }
  55. TEST_CASE("move-construction with move", "[UniqueResource]")
  56. {
  57. REQUIRE_CALL(m, deleter(3));
  58. auto movedFrom = sr::unique_resource{Handle{3}, deleter};
  59. auto guard = std::move(movedFrom);
  60. CHECK(guard.get() == 3);
  61. }
  62. TEST_CASE("move-construction with copy", "[UniqueResource]")
  63. {
  64. REQUIRE_CALL(m, deleter(7));
  65. auto d = [](auto) { deleter(7); };
  66. const CopyMock copyMock;
  67. sr::unique_resource movedFrom{copyMock, d};
  68. [[maybe_unused]] auto guard = std::move(movedFrom);
  69. }
  70. TEST_CASE("move assignment calls deleter", "[UniqueResource]")
  71. {
  72. auto moveFrom = sr::unique_resource{Handle{3}, deleter};
  73. REQUIRE_CALL(m, deleter(4));
  74. {
  75. REQUIRE_CALL(m, deleter(3));
  76. auto guard = sr::unique_resource{Handle{4}, deleter};
  77. guard = std::move(moveFrom);
  78. }
  79. }
  80. TEST_CASE("deleter called on destruction", "[UniqueResource]")
  81. {
  82. REQUIRE_CALL(m, deleter(3));
  83. [[maybe_unused]] auto guard = sr::unique_resource{Handle{3}, deleter};
  84. }
  85. TEST_CASE("reset calls deleter", "[UniqueResource]")
  86. {
  87. auto guard = sr::unique_resource{Handle{3}, deleter};
  88. {
  89. REQUIRE_CALL(m, deleter(3));
  90. guard.reset();
  91. }
  92. }
  93. TEST_CASE("reset does not call deleter if released", "[UniqueResource]")
  94. {
  95. REQUIRE_CALL(m, deleter(3)).TIMES(0);
  96. auto guard = sr::unique_resource{Handle{3}, deleter};
  97. guard.release();
  98. guard.reset();
  99. }
  100. TEST_CASE("reset sets new rvalue and calls deleter on previous", "[UniqueResource]")
  101. {
  102. REQUIRE_CALL(m, deleter(3));
  103. REQUIRE_CALL(m, deleter(7));
  104. auto guard = sr::unique_resource{Handle{3}, deleter};
  105. guard.reset(Handle{7});
  106. }
  107. TEST_CASE("reset sets new lvalue and calls deleter on previous", "[UniqueResource]")
  108. {
  109. REQUIRE_CALL(m, deleter(3));
  110. REQUIRE_CALL(m, deleter(7));
  111. auto d = [](const auto& v) { deleter(v.m_value); };
  112. auto guard = sr::unique_resource{NotNothrowAssignable{3}, d};
  113. const NotNothrowAssignable h{7};
  114. guard.reset(h);
  115. }
  116. TEST_CASE("reset handles exception on assignment", "[UniqueResource]")
  117. {
  118. REQUIRE_CALL(m, deleter(3));
  119. REQUIRE_CALL(m, deleter(7));
  120. auto d = [](const auto& v) { deleter(v.m_handle); };
  121. auto guard = sr::unique_resource{ConditialThrowOnCopyMock{3, false}, d};
  122. guard.reset(ConditialThrowOnCopyMock{7, true});
  123. }
  124. TEST_CASE("release disables deleter", "[UniqueResource]")
  125. {
  126. REQUIRE_CALL(m, deleter(3)).TIMES(0);
  127. auto guard = sr::unique_resource{Handle{3}, deleter};
  128. guard.release();
  129. }
  130. TEST_CASE("get returns resource", "[UniqueResource]")
  131. {
  132. REQUIRE_CALL(m, deleter(3));
  133. auto guard = sr::unique_resource{Handle{3}, deleter};
  134. CHECK(guard.get() == 3);
  135. }
  136. TEST_CASE("pointer access returns resource" "[UniqueResource]")
  137. {
  138. const auto p = std::make_pair(3, 4);
  139. auto guard = sr::unique_resource{&p, [](auto*) { }};
  140. REQUIRE(guard->first == 3);
  141. REQUIRE(guard->second == 4);
  142. }
  143. TEST_CASE("pointer dereference returns resource" "[UniqueResource]")
  144. {
  145. Handle h{5};
  146. auto guard = sr::unique_resource{PtrHandle{&h}, [](auto*) { }};
  147. REQUIRE(*guard == 5);
  148. }
  149. TEST_CASE("deleter access", "[UniqueResource]")
  150. {
  151. auto guard = sr::unique_resource{Handle{3}, deleter};
  152. guard.release();
  153. {
  154. REQUIRE_CALL(m, deleter(8));
  155. guard.get_deleter()(8);
  156. }
  157. }
  158. TEST_CASE("make unique resource", "[UniqueResource]")
  159. {
  160. REQUIRE_CALL(m, deleter(7));
  161. [[maybe_unused]] auto guard = sr::unique_resource{Handle{7}, deleter};
  162. }
  163. TEST_CASE("make unique resource with reference wrapper", "[UniqueResource]")
  164. {
  165. REQUIRE_CALL(m, deleter(3));
  166. Handle h{3};
  167. [[maybe_unused]] auto guard = sr::unique_resource{std::ref(h), deleter};
  168. }
  169. TEST_CASE("make unique resource checked", "[UniqueResource]")
  170. {
  171. REQUIRE_CALL(m, deleter(4));
  172. [[maybe_unused]] auto guard = sr::make_unique_resource_checked(Handle{4}, Handle{-1}, deleter);
  173. }
  174. TEST_CASE("make unique resource checked releases if invalid", "[UniqueResource]")
  175. {
  176. [[maybe_unused]] auto guard = sr::make_unique_resource_checked(Handle{-1}, Handle{-1}, deleter);
  177. }