Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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