Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

247 lines
6.5KB

  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 <functional>
  22. #include <catch.hpp>
  23. #include <trompeloeil.hpp>
  24. using namespace trompeloeil;
  25. namespace
  26. {
  27. using Handle = int;
  28. using PtrHandle = std::add_pointer_t<Handle>;
  29. struct CallMock
  30. {
  31. MAKE_MOCK1(deleter, void(Handle));
  32. };
  33. CallMock m;
  34. void deleter(Handle h)
  35. {
  36. m.deleter(h);
  37. }
  38. }
  39. TEST_CASE("deleter called on destruction", "[UniqueResource]")
  40. {
  41. REQUIRE_CALL(m, deleter(3));
  42. auto guard = sr::unique_resource(Handle{3}, deleter);
  43. static_cast<void>(guard);
  44. }
  45. TEST_CASE("deleter is not called if released", "[UniqueResource]")
  46. {
  47. REQUIRE_CALL(m, deleter(3)).TIMES(0);
  48. auto guard = sr::unique_resource(Handle{3}, deleter);
  49. guard.release();
  50. }
  51. TEST_CASE("deleter called if checked valid", "[UniqueResource]")
  52. {
  53. REQUIRE_CALL(m, deleter(3));
  54. auto guard = sr::unique_resource_checked(Handle{3}, Handle{6}, deleter);
  55. static_cast<void>(guard);
  56. }
  57. TEST_CASE("deleter not called if checked invalid", "[UniqueResource]")
  58. {
  59. REQUIRE_CALL(m, deleter(3)).TIMES(0);
  60. auto guard = sr::unique_resource_checked(Handle{3}, Handle{3}, deleter);
  61. static_cast<void>(guard);
  62. }
  63. TEST_CASE("release returns reference to resource", "[UniqueResource]")
  64. {
  65. auto guard = sr::unique_resource(Handle{3}, [](auto) { });
  66. const auto result = guard.release();
  67. REQUIRE(3 == result);
  68. }
  69. TEST_CASE("move releases moved-from object", "[UniqueResource]")
  70. {
  71. REQUIRE_CALL(m, deleter(3));
  72. auto movedFrom = sr::unique_resource(Handle{3}, deleter);
  73. auto guard = std::move(movedFrom);
  74. static_cast<void>(guard);
  75. }
  76. TEST_CASE("move transfers state", "[UniqueResource]")
  77. {
  78. REQUIRE_CALL(m, deleter(3));
  79. auto movedFrom = sr::unique_resource(Handle{3}, deleter);
  80. auto guard = std::move(movedFrom);
  81. static_cast<void>(guard);
  82. }
  83. TEST_CASE("move transfers state if released", "[UniqueResource]")
  84. {
  85. REQUIRE_CALL(m, deleter(ANY(Handle))).TIMES(0); // TODO: Use ANY(T)
  86. auto movedFrom = sr::unique_resource(Handle{3}, deleter);
  87. movedFrom.release();
  88. auto guard = std::move(movedFrom);
  89. static_cast<void>(guard);
  90. }
  91. TEST_CASE("move assignment releases moved-from object", "[UniqueResource]")
  92. {
  93. REQUIRE_CALL(m, deleter(5));
  94. REQUIRE_CALL(m, deleter(3));
  95. auto movedFrom = sr::unique_resource(Handle{3}, deleter);
  96. auto guard = sr::unique_resource(Handle{5}, deleter);
  97. guard = std::move(movedFrom);
  98. static_cast<void>(guard);
  99. }
  100. TEST_CASE("move assignment transfers state", "[UniqueResource]")
  101. {
  102. REQUIRE_CALL(m, deleter(5));
  103. REQUIRE_CALL(m, deleter(3));
  104. auto movedFrom = sr::unique_resource(Handle{3}, deleter);
  105. auto guard = sr::unique_resource(Handle{5}, deleter);
  106. guard = std::move(movedFrom);
  107. static_cast<void>(guard);
  108. }
  109. TEST_CASE("move assignment transfers state if released", "[UniqueResource]")
  110. {
  111. REQUIRE_CALL(m, deleter(5));
  112. auto movedFrom = sr::unique_resource(Handle{3}, deleter);
  113. movedFrom.release();
  114. auto guard = sr::unique_resource(Handle{5}, deleter);
  115. guard = std::move(movedFrom);
  116. static_cast<void>(guard);
  117. }
  118. TEST_CASE("no exception propagation from deleter", "[UniqueResource]")
  119. {
  120. REQUIRE_NOTHROW([] {
  121. auto guard = sr::unique_resource(Handle{3}, [](auto) { throw "Don't propagate this!"; });
  122. static_cast<void>(guard);
  123. }());
  124. }
  125. TEST_CASE("invoke executes deleter on resource", "[UniqueResource]")
  126. {
  127. REQUIRE_CALL(m, deleter(3));
  128. auto guard = sr::unique_resource(Handle{3}, deleter);
  129. guard.invoke();
  130. }
  131. TEST_CASE("invoke executes only multiple times if again strategy", "[UniqueResource]")
  132. {
  133. REQUIRE_CALL(m, deleter(3)).TIMES(3);
  134. auto guard = sr::unique_resource(Handle{3}, deleter);
  135. guard.invoke(sr::invoke_it::again);
  136. guard.invoke(sr::invoke_it::again);
  137. }
  138. TEST_CASE("invoke does nothing if released", "[UniqueResource]")
  139. {
  140. REQUIRE_CALL(m, deleter(ANY(Handle))).TIMES(0);
  141. auto guard = sr::unique_resource(Handle{3}, deleter);
  142. guard.release();
  143. guard.invoke(sr::invoke_it::once);
  144. }
  145. TEST_CASE("invoke executes after release if again strategy", "[UniqueResource]")
  146. {
  147. REQUIRE_CALL(m, deleter(3));
  148. auto guard = sr::unique_resource(Handle{3}, deleter);
  149. guard.release();
  150. guard.invoke(sr::invoke_it::again);
  151. }
  152. TEST_CASE("invoke does not propagate exception", "[UniqueResource]")
  153. {
  154. auto guard = sr::unique_resource(Handle{3}, [](auto) { throw "Don't propagate this!"; });
  155. REQUIRE_NOTHROW(guard.invoke());
  156. }
  157. TEST_CASE("reset releases old ressource", "[UniqueResource]")
  158. {
  159. REQUIRE_CALL(m, deleter(3));
  160. REQUIRE_CALL(m, deleter(7));
  161. auto guard = sr::unique_resource(Handle{3}, deleter);
  162. guard.reset(Handle{7});
  163. }
  164. TEST_CASE("reset sets ressource", "[UniqueResource]")
  165. {
  166. auto guard = sr::unique_resource(Handle{3}, [](auto) { });
  167. guard.reset(Handle{7});
  168. REQUIRE(guard.get() == 7);
  169. }
  170. TEST_CASE("get accesses ressource", "[UniqueResource]")
  171. {
  172. auto guard = sr::unique_resource(Handle{3}, [](auto) { });
  173. REQUIRE(guard.get() == 3);
  174. }
  175. TEST_CASE("conversion operator", "[UniqueResource]")
  176. {
  177. auto guard = sr::unique_resource(Handle{3}, [](auto) { });
  178. const auto& ref = guard;
  179. REQUIRE(ref == 3);
  180. }
  181. TEST_CASE("pointer access operator" "[UniqueResource]")
  182. {
  183. const auto p = std::make_pair(3, 4);
  184. auto guard = sr::unique_resource(&p, [](auto) { });
  185. const auto x = guard.operator->();
  186. REQUIRE(x->first == 3);
  187. }
  188. TEST_CASE("dereference operator", "[UniqueResource]")
  189. {
  190. Handle h{4};
  191. auto guard = sr::unique_resource(PtrHandle{&h}, [](auto) { });
  192. const auto x = guard.operator*();
  193. REQUIRE(x == 4);
  194. }
  195. TEST_CASE("deleter access", "[UniqueResource]")
  196. {
  197. std::size_t value{0};
  198. auto guard = sr::unique_resource(Handle{3}, [&value](auto v) { value = v; });
  199. REQUIRE(value == 0);
  200. guard.get_deleter()(6);
  201. REQUIRE(value == 6);
  202. }