Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

218 lines
5.8KB

  1. /*
  2. * Scope Guard
  3. * Copyright (C) 2017 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. auto guard = sr::unique_resource{Handle{3}, deleter};
  38. static_cast<void>(guard);
  39. }
  40. TEST_CASE("construction with copy", "[UniqueResource]")
  41. {
  42. REQUIRE_CALL(m, deleter(3));
  43. const Handle h{3};
  44. const auto d = [](auto v) { m.deleter(v); };
  45. auto guard = sr::unique_resource{h, d};
  46. static_cast<void>(guard);
  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. sr::unique_resource guard{noMove, d};
  55. static_cast<void>(guard);
  56. }());
  57. }
  58. TEST_CASE("move-construction with move", "[UniqueResource]")
  59. {
  60. REQUIRE_CALL(m, deleter(3));
  61. auto movedFrom = sr::unique_resource{Handle{3}, deleter};
  62. auto guard = std::move(movedFrom);
  63. CHECK(guard.get() == 3);
  64. }
  65. TEST_CASE("move-construction with copy", "[UniqueResource]")
  66. {
  67. REQUIRE_CALL(m, deleter(7));
  68. auto d = [](auto) { deleter(7); };
  69. const CopyMock copyMock;
  70. sr::unique_resource movedFrom{copyMock, d};
  71. auto guard = std::move(movedFrom);
  72. static_cast<void>(guard);
  73. }
  74. TEST_CASE("move assignment calls deleter", "[UniqueResource]")
  75. {
  76. auto moveFrom = sr::unique_resource{Handle{3}, deleter};
  77. REQUIRE_CALL(m, deleter(4));
  78. {
  79. REQUIRE_CALL(m, deleter(3));
  80. auto guard = sr::unique_resource{Handle{4}, deleter};
  81. guard = std::move(moveFrom);
  82. }
  83. }
  84. TEST_CASE("deleter called on destruction", "[UniqueResource]")
  85. {
  86. REQUIRE_CALL(m, deleter(3));
  87. auto guard = sr::unique_resource{Handle{3}, deleter};
  88. static_cast<void>(guard);
  89. }
  90. TEST_CASE("reset calls deleter", "[UniqueResource]")
  91. {
  92. auto guard = sr::unique_resource{Handle{3}, deleter};
  93. {
  94. REQUIRE_CALL(m, deleter(3));
  95. guard.reset();
  96. }
  97. }
  98. TEST_CASE("reset does not call deleter if released", "[UniqueResource]")
  99. {
  100. REQUIRE_CALL(m, deleter(3)).TIMES(0);
  101. auto guard = sr::unique_resource{Handle{3}, deleter};
  102. guard.release();
  103. guard.reset();
  104. }
  105. TEST_CASE("reset sets new rvalue and calls deleter on previous", "[UniqueResource]")
  106. {
  107. REQUIRE_CALL(m, deleter(3));
  108. REQUIRE_CALL(m, deleter(7));
  109. auto guard = sr::unique_resource{Handle{3}, deleter};
  110. guard.reset(Handle{7});
  111. }
  112. TEST_CASE("reset sets new lvalue and calls deleter on previous", "[UniqueResource]")
  113. {
  114. REQUIRE_CALL(m, deleter(3));
  115. REQUIRE_CALL(m, deleter(7));
  116. auto d = [](const auto& v) { deleter(v.m_value); };
  117. auto guard = sr::unique_resource{NotNothrowAssignable{3}, d};
  118. const NotNothrowAssignable h{7};
  119. guard.reset(h);
  120. }
  121. TEST_CASE("reset handles exception on assignment", "[UniqueResource]")
  122. {
  123. REQUIRE_CALL(m, deleter(3));
  124. REQUIRE_CALL(m, deleter(7));
  125. auto d = [](const auto& v) { deleter(v.m_handle); };
  126. auto guard = sr::unique_resource{ConditialThrowOnCopyMock{3, false}, d};
  127. guard.reset(ConditialThrowOnCopyMock{7, true});
  128. }
  129. TEST_CASE("release disables deleter", "[UniqueResource]")
  130. {
  131. REQUIRE_CALL(m, deleter(3)).TIMES(0);
  132. auto guard = sr::unique_resource{Handle{3}, deleter};
  133. guard.release();
  134. }
  135. TEST_CASE("get returns resource", "[UniqueResource]")
  136. {
  137. REQUIRE_CALL(m, deleter(3));
  138. auto guard = sr::unique_resource{Handle{3}, deleter};
  139. CHECK(guard.get() == 3);
  140. }
  141. TEST_CASE("pointer access returns resource" "[UniqueResource]")
  142. {
  143. const auto p = std::make_pair(3, 4);
  144. auto guard = sr::unique_resource{&p, [](auto*) { }};
  145. REQUIRE(guard->first == 3);
  146. REQUIRE(guard->second == 4);
  147. }
  148. TEST_CASE("pointer dereference returns resource" "[UniqueResource]")
  149. {
  150. Handle h{5};
  151. auto guard = sr::unique_resource{PtrHandle{&h}, [](auto*) { }};
  152. REQUIRE(*guard == 5);
  153. }
  154. TEST_CASE("deleter access", "[UniqueResource]")
  155. {
  156. auto guard = sr::unique_resource{Handle{3}, deleter};
  157. guard.release();
  158. {
  159. REQUIRE_CALL(m, deleter(8));
  160. guard.get_deleter()(8);
  161. }
  162. }
  163. TEST_CASE("make unique resource", "[UniqueResource]")
  164. {
  165. REQUIRE_CALL(m, deleter(7));
  166. auto guard = sr::unique_resource{Handle{7}, deleter};
  167. static_cast<void>(guard);
  168. }
  169. TEST_CASE("make unique resource with reference wrapper", "[UniqueResource]")
  170. {
  171. REQUIRE_CALL(m, deleter(3));
  172. Handle h{3};
  173. auto guard = sr::unique_resource{std::ref(h), deleter};
  174. static_cast<void>(guard);
  175. }
  176. TEST_CASE("make unique resource checked", "[UniqueResource]")
  177. {
  178. REQUIRE_CALL(m, deleter(4));
  179. auto guard = sr::make_unique_resource_checked(Handle{4}, Handle{-1}, deleter);
  180. static_cast<void>(guard);
  181. }
  182. TEST_CASE("make unique resource checked releases if invalid", "[UniqueResource]")
  183. {
  184. auto guard = sr::make_unique_resource_checked(Handle{-1}, Handle{-1}, deleter);
  185. static_cast<void>(guard);
  186. }