WistdTests.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. #include <wil/wistd_functional.h>
  2. #include "common.h"
  3. #include "test_objects.h"
  4. // Test methods/objects
  5. int GetValue()
  6. {
  7. return 42;
  8. }
  9. int GetOtherValue()
  10. {
  11. return 8;
  12. }
  13. int Negate(int value)
  14. {
  15. return -value;
  16. }
  17. int Add(int lhs, int rhs)
  18. {
  19. return lhs + rhs;
  20. }
  21. TEST_CASE("WistdFunctionTests::CallOperatorTest", "[wistd]")
  22. {
  23. wistd::function<int()> getValue = GetValue;
  24. REQUIRE(GetValue() == getValue());
  25. wistd::function<int(int)> negate = Negate;
  26. REQUIRE(Negate(42) == negate(42));
  27. wistd::function<int(int, int)> add = Add;
  28. REQUIRE(Add(42, 8) == add(42, 8));
  29. }
  30. TEST_CASE("WistdFunctionTests::AssignmentOperatorTest", "[wistd]")
  31. {
  32. wistd::function<int()> fn = GetValue;
  33. REQUIRE(GetValue() == fn());
  34. fn = GetOtherValue;
  35. REQUIRE(GetOtherValue() == fn());
  36. }
  37. #ifdef WIL_ENABLE_EXCEPTIONS
  38. TEST_CASE("WistdFunctionTests::StdFunctionConstructionTest", "[wistd]")
  39. {
  40. // We should be able to capture a std::function in a wistd::function
  41. wistd::function<int()> fn;
  42. {
  43. value_holder holder{ 42 };
  44. std::function<int()> stdFn = [holder]()
  45. {
  46. return holder.value;
  47. };
  48. fn = stdFn;
  49. }
  50. REQUIRE(42 == fn());
  51. }
  52. #endif
  53. TEST_CASE("WistdFunctionTests::CopyConstructionTest", "[wistd]")
  54. {
  55. object_counter_state state;
  56. {
  57. wistd::function<int()> copyFrom = [counter = object_counter{ state }]()
  58. {
  59. return counter.state->copy_count;
  60. };
  61. REQUIRE(0 == copyFrom());
  62. auto copyTo = copyFrom;
  63. REQUIRE(1 == copyTo());
  64. }
  65. REQUIRE(0 == state.instance_count());
  66. }
  67. TEST_CASE("WistdFunctionTests::CopyAssignmentTest", "[wistd]")
  68. {
  69. object_counter_state state;
  70. {
  71. wistd::function<int()> copyTo;
  72. {
  73. wistd::function<int()> copyFrom = [counter = object_counter{ state }]()
  74. {
  75. return counter.state->copy_count;
  76. };
  77. REQUIRE(0 == copyFrom());
  78. copyTo = copyFrom;
  79. }
  80. REQUIRE(1 == copyTo());
  81. }
  82. REQUIRE(0 == state.instance_count());
  83. }
  84. TEST_CASE("WistdFunctionTests::MoveConstructionTest", "[wistd]")
  85. {
  86. object_counter_state state;
  87. {
  88. wistd::function<int()> moveFrom = [counter = object_counter{ state }]()
  89. {
  90. return counter.state->copy_count;
  91. };
  92. REQUIRE(0 == moveFrom());
  93. auto moveTo = std::move(moveFrom);
  94. REQUIRE(0 == moveTo());
  95. // Because we move the underlying function object, we _must_ invalidate the moved from function
  96. REQUIRE_FALSE(moveFrom != nullptr);
  97. }
  98. REQUIRE(0 == state.instance_count());
  99. }
  100. TEST_CASE("WistdFunctionTests::MoveAssignmentTest", "[wistd]")
  101. {
  102. object_counter_state state;
  103. {
  104. wistd::function<int()> moveTo;
  105. {
  106. wistd::function<int()> moveFrom = [counter = object_counter{ state }]()
  107. {
  108. return counter.state->copy_count;
  109. };
  110. REQUIRE(0 == moveFrom());
  111. moveTo = std::move(moveFrom);
  112. }
  113. REQUIRE(0 == moveTo());
  114. }
  115. REQUIRE(0 == state.instance_count());
  116. }
  117. TEST_CASE("WistdFunctionTests::SwapTest", "[wistd]")
  118. {
  119. object_counter_state state;
  120. {
  121. wistd::function<int()> first;
  122. wistd::function<int()> second;
  123. first.swap(second);
  124. REQUIRE_FALSE(first != nullptr);
  125. REQUIRE_FALSE(second != nullptr);
  126. first = [counter = object_counter{ state }]()
  127. {
  128. return counter.state->copy_count;
  129. };
  130. first.swap(second);
  131. REQUIRE_FALSE(first != nullptr);
  132. REQUIRE(second != nullptr);
  133. REQUIRE(0 == second());
  134. first.swap(second);
  135. REQUIRE(first != nullptr);
  136. REQUIRE_FALSE(second != nullptr);
  137. REQUIRE(0 == first());
  138. second = [counter = object_counter{ state }]()
  139. {
  140. return counter.state->copy_count;
  141. };
  142. first.swap(second);
  143. REQUIRE(first != nullptr);
  144. REQUIRE(second != nullptr);
  145. REQUIRE(0 == first());
  146. }
  147. REQUIRE(0 == state.instance_count());
  148. }
  149. // MSVC's optimizer has had issues with wistd::function in the past when forwarding wistd::function objects to a
  150. // function that accepts the arguments by value. This test exercises the workaround that we have in place. Note
  151. // that this of course requires building with optimizations enabled
  152. void ForwardingTest(wistd::function<int()> getValue, wistd::function<int(int)> negate, wistd::function<int(int, int)> add)
  153. {
  154. // Previously, this would cause a runtime crash
  155. REQUIRE(Add(GetValue(), Negate(8)) == add(getValue(), negate(8)));
  156. }
  157. template <typename... Args>
  158. void CallForwardingTest(Args&&... args)
  159. {
  160. ForwardingTest(wistd::forward<Args>(args)...);
  161. }
  162. TEST_CASE("WistdFunctionTests::OptimizationRegressionTest", "[wistd]")
  163. {
  164. CallForwardingTest(
  165. wistd::function<int()>(GetValue),
  166. wistd::function<int(int)>(Negate),
  167. wistd::function<int(int, int)>(Add));
  168. }