Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

179 lines
4.4KB

  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 <catch.hpp>
  22. #include <trompeloeil.hpp>
  23. using namespace trompeloeil;
  24. namespace
  25. {
  26. using Handle = int;
  27. using PtrHandle = std::add_pointer_t<Handle>;
  28. struct CallMock
  29. {
  30. MAKE_MOCK1(deleter, void(Handle));
  31. };
  32. struct ThrowOnCopyMock
  33. {
  34. ThrowOnCopyMock() { }
  35. ThrowOnCopyMock(const ThrowOnCopyMock&)
  36. {
  37. throw std::exception{};
  38. }
  39. MAKE_CONST_MOCK1(deleter, void(ThrowOnCopyMock));
  40. ThrowOnCopyMock& operator=(const ThrowOnCopyMock&)
  41. {
  42. throw std::exception{};
  43. }
  44. };
  45. struct NotNothrowMoveMock
  46. {
  47. NotNothrowMoveMock(CallMock* mo) : m_mock(mo) { }
  48. NotNothrowMoveMock(const NotNothrowMoveMock& other) : m_mock(other.m_mock) { }
  49. NotNothrowMoveMock(NotNothrowMoveMock&& other) noexcept(false) : m_mock(other.m_mock) { }
  50. void operator()(Handle h) const
  51. {
  52. m_mock->deleter(h);
  53. }
  54. NotNothrowMoveMock& operator=(const NotNothrowMoveMock&)
  55. {
  56. throw "Not implemented";
  57. }
  58. NotNothrowMoveMock& operator=(NotNothrowMoveMock&&)
  59. {
  60. throw "Not implemented";
  61. }
  62. CallMock* m_mock;
  63. };
  64. CallMock m;
  65. void deleter(Handle h)
  66. {
  67. m.deleter(h);
  68. }
  69. }
  70. TEST_CASE("construction with move", "[UniqueResource]")
  71. {
  72. REQUIRE_CALL(m, deleter(3));
  73. auto guard = sr::make_unique_resource(Handle{3}, deleter);
  74. static_cast<void>(guard);
  75. }
  76. TEST_CASE("construction with copy", "[UniqueResource]")
  77. {
  78. REQUIRE_CALL(m, deleter(3));
  79. const Handle h{3};
  80. const auto d = [](auto v) { m.deleter(v); };
  81. auto guard = sr::make_unique_resource(h, d);
  82. static_cast<void>(guard);
  83. }
  84. TEST_CASE("construction with copy calls deleter and rethrows on failed copy", "[UniqueResource]")
  85. {
  86. REQUIRE_THROWS([] {
  87. const ThrowOnCopyMock noMove;
  88. const auto d = [](const auto&) { m.deleter(3); };
  89. REQUIRE_CALL(m, deleter(3));
  90. sr::unique_resource<decltype(noMove), decltype(d)> guard{noMove, d};
  91. static_cast<void>(guard);
  92. }());
  93. }
  94. TEST_CASE("move-construction with move", "[UniqueResource]")
  95. {
  96. REQUIRE_CALL(m, deleter(3));
  97. auto movedFrom = sr::make_unique_resource(Handle{3}, deleter);
  98. auto guard = std::move(movedFrom);
  99. CHECK(guard.get() == 3);
  100. }
  101. TEST_CASE("move-construction with copy", "[UniqueResource]")
  102. {
  103. CallMock mock;
  104. REQUIRE_CALL(mock, deleter(3));
  105. const NotNothrowMoveMock notNothrow{&mock};
  106. Handle h{3};
  107. sr::unique_resource<Handle, decltype(notNothrow)> movedFrom{h, notNothrow};
  108. auto guard = std::move(movedFrom);
  109. CHECK(guard.get() == 3);
  110. }
  111. // TODO: Implement move assignment
  112. TEST_CASE("deleter called on destruction", "[UniqueResource]")
  113. {
  114. REQUIRE_CALL(m, deleter(3));
  115. auto guard = sr::make_unique_resource(Handle{3}, deleter);
  116. static_cast<void>(guard);
  117. }
  118. TEST_CASE("reset calls deleter", "[UniqueResource]")
  119. {
  120. auto guard = sr::make_unique_resource(Handle{3}, deleter);
  121. {
  122. REQUIRE_CALL(m, deleter(3));
  123. guard.reset();
  124. }
  125. }
  126. TEST_CASE("reset does not call deleter if released", "[UniqueResource]")
  127. {
  128. REQUIRE_CALL(m, deleter(3)).TIMES(0);
  129. auto guard = sr::make_unique_resource(Handle{3}, deleter);
  130. guard.release();
  131. guard.reset();
  132. }
  133. // TODO: Reset with new value
  134. TEST_CASE("release disables deleter", "[UniqueResource]")
  135. {
  136. REQUIRE_CALL(m, deleter(3)).TIMES(0);
  137. auto guard = sr::make_unique_resource(Handle{3}, deleter);
  138. guard.release();
  139. }
  140. TEST_CASE("get returns resource", "[UniqueResource]")
  141. {
  142. REQUIRE_CALL(m, deleter(3));
  143. auto guard = sr::make_unique_resource(Handle{3}, deleter);
  144. CHECK(guard.get() == 3);
  145. }