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.

211 line
6.0KB

  1. // MIT License
  2. //
  3. // Copyright (c) 2017-2018 offa
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in all
  13. // copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. // SOFTWARE.
  22. #include "unique_resource.h"
  23. #include "CallMocks.h"
  24. #include <catch.hpp>
  25. #include <trompeloeil.hpp>
  26. using namespace mock;
  27. using namespace trompeloeil;
  28. namespace
  29. {
  30. CallMock m;
  31. void deleter(Handle h)
  32. {
  33. m.deleter(h);
  34. }
  35. }
  36. TEST_CASE("construction with move", "[UniqueResource]")
  37. {
  38. REQUIRE_CALL(m, deleter(3));
  39. [[maybe_unused]] auto guard = sr::unique_resource{Handle{3}, deleter};
  40. }
  41. TEST_CASE("construction with copy", "[UniqueResource]")
  42. {
  43. REQUIRE_CALL(m, deleter(3));
  44. const Handle h{3};
  45. const auto d = [](auto v) { m.deleter(v); };
  46. [[maybe_unused]] auto guard = sr::unique_resource{h, d};
  47. }
  48. TEST_CASE("construction with copy calls deleter and rethrows on failed copy", "[UniqueResource]")
  49. {
  50. REQUIRE_THROWS([] {
  51. const ThrowOnCopyMock noMove;
  52. const auto d = [](const auto&) { m.deleter(3); };
  53. REQUIRE_CALL(m, deleter(3));
  54. [[maybe_unused]] sr::unique_resource guard{noMove, d};
  55. }());
  56. }
  57. TEST_CASE("move-construction with move", "[UniqueResource]")
  58. {
  59. REQUIRE_CALL(m, deleter(3));
  60. auto movedFrom = sr::unique_resource{Handle{3}, deleter};
  61. auto guard = std::move(movedFrom);
  62. CHECK(guard.get() == 3);
  63. }
  64. TEST_CASE("move-construction with copy", "[UniqueResource]")
  65. {
  66. REQUIRE_CALL(m, deleter(7));
  67. auto d = [](auto) { deleter(7); };
  68. const CopyMock copyMock;
  69. sr::unique_resource movedFrom{copyMock, d};
  70. [[maybe_unused]] auto guard = std::move(movedFrom);
  71. }
  72. TEST_CASE("move assignment calls deleter", "[UniqueResource]")
  73. {
  74. auto moveFrom = sr::unique_resource{Handle{3}, deleter};
  75. REQUIRE_CALL(m, deleter(4));
  76. {
  77. REQUIRE_CALL(m, deleter(3));
  78. auto guard = sr::unique_resource{Handle{4}, deleter};
  79. guard = std::move(moveFrom);
  80. }
  81. }
  82. TEST_CASE("deleter called on destruction", "[UniqueResource]")
  83. {
  84. REQUIRE_CALL(m, deleter(3));
  85. [[maybe_unused]] auto guard = sr::unique_resource{Handle{3}, deleter};
  86. }
  87. TEST_CASE("reset calls deleter", "[UniqueResource]")
  88. {
  89. auto guard = sr::unique_resource{Handle{3}, deleter};
  90. {
  91. REQUIRE_CALL(m, deleter(3));
  92. guard.reset();
  93. }
  94. }
  95. TEST_CASE("reset does not call deleter if released", "[UniqueResource]")
  96. {
  97. REQUIRE_CALL(m, deleter(3)).TIMES(0);
  98. auto guard = sr::unique_resource{Handle{3}, deleter};
  99. guard.release();
  100. guard.reset();
  101. }
  102. TEST_CASE("reset sets new rvalue and calls deleter on previous", "[UniqueResource]")
  103. {
  104. REQUIRE_CALL(m, deleter(3));
  105. REQUIRE_CALL(m, deleter(7));
  106. auto guard = sr::unique_resource{Handle{3}, deleter};
  107. guard.reset(Handle{7});
  108. }
  109. TEST_CASE("reset sets new lvalue and calls deleter on previous", "[UniqueResource]")
  110. {
  111. REQUIRE_CALL(m, deleter(3));
  112. REQUIRE_CALL(m, deleter(7));
  113. auto d = [](const auto& v) { deleter(v.value); };
  114. auto guard = sr::unique_resource{NotNothrowAssignable{3}, d};
  115. const NotNothrowAssignable h{7};
  116. guard.reset(h);
  117. }
  118. TEST_CASE("reset handles exception on assignment", "[UniqueResource]")
  119. {
  120. REQUIRE_CALL(m, deleter(3));
  121. REQUIRE_CALL(m, deleter(7));
  122. auto d = [](const auto& v) { deleter(v.handle); };
  123. auto guard = sr::unique_resource{ConditialThrowOnCopyMock{3, false}, d};
  124. guard.reset(ConditialThrowOnCopyMock{7, true});
  125. }
  126. TEST_CASE("release disables deleter", "[UniqueResource]")
  127. {
  128. REQUIRE_CALL(m, deleter(3)).TIMES(0);
  129. auto guard = sr::unique_resource{Handle{3}, deleter};
  130. guard.release();
  131. }
  132. TEST_CASE("get returns resource", "[UniqueResource]")
  133. {
  134. REQUIRE_CALL(m, deleter(3));
  135. auto guard = sr::unique_resource{Handle{3}, deleter};
  136. CHECK(guard.get() == 3);
  137. }
  138. TEST_CASE("pointer access returns resource" "[UniqueResource]")
  139. {
  140. const auto p = std::make_pair(3, 4);
  141. auto guard = sr::unique_resource{&p, [](auto*) { }};
  142. REQUIRE(guard->first == 3);
  143. REQUIRE(guard->second == 4);
  144. }
  145. TEST_CASE("pointer dereference returns resource" "[UniqueResource]")
  146. {
  147. Handle h{5};
  148. auto guard = sr::unique_resource{PtrHandle{&h}, [](auto*) { }};
  149. REQUIRE(*guard == 5);
  150. }
  151. TEST_CASE("deleter access", "[UniqueResource]")
  152. {
  153. auto guard = sr::unique_resource{Handle{3}, deleter};
  154. guard.release();
  155. {
  156. REQUIRE_CALL(m, deleter(8));
  157. guard.get_deleter()(8);
  158. }
  159. }
  160. TEST_CASE("make unique resource", "[UniqueResource]")
  161. {
  162. REQUIRE_CALL(m, deleter(7));
  163. [[maybe_unused]] auto guard = sr::unique_resource{Handle{7}, deleter};
  164. }
  165. TEST_CASE("make unique resource with reference wrapper", "[UniqueResource]")
  166. {
  167. REQUIRE_CALL(m, deleter(3));
  168. Handle h{3};
  169. [[maybe_unused]] auto guard = sr::unique_resource{std::ref(h), deleter};
  170. }
  171. TEST_CASE("make unique resource checked", "[UniqueResource]")
  172. {
  173. REQUIRE_CALL(m, deleter(4));
  174. [[maybe_unused]] auto guard = sr::make_unique_resource_checked(Handle{4}, Handle{-1}, deleter);
  175. }
  176. TEST_CASE("make unique resource checked releases if invalid", "[UniqueResource]")
  177. {
  178. [[maybe_unused]] auto guard = sr::make_unique_resource_checked(Handle{-1}, Handle{-1}, deleter);
  179. }