sigh.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. #include <memory>
  2. #include <utility>
  3. #include <gtest/gtest.h>
  4. #include <common/linter.hpp>
  5. #include <entt/signal/sigh.hpp>
  6. struct sigh_listener {
  7. static void f(int &v) {
  8. ++v;
  9. }
  10. [[nodiscard]] bool g(int) {
  11. val = !val;
  12. return true;
  13. }
  14. [[nodiscard]] bool h(const int &) {
  15. return val;
  16. }
  17. // useless definition just because msvc does weird things if both are empty
  18. void i() {
  19. val = true && val;
  20. }
  21. bool val{false};
  22. };
  23. struct const_nonconst_noexcept {
  24. void f() {
  25. ++cnt;
  26. }
  27. void g() noexcept {
  28. ++cnt;
  29. }
  30. void h() const {
  31. ++cnt;
  32. }
  33. void i() const noexcept {
  34. ++cnt;
  35. }
  36. mutable int cnt{0};
  37. };
  38. void connect_and_auto_disconnect(entt::sigh<void(int &)> &sigh, const int &) {
  39. entt::sink sink{sigh};
  40. sink.connect<sigh_listener::f>();
  41. sink.disconnect<&connect_and_auto_disconnect>(sigh);
  42. }
  43. TEST(SigH, Lifetime) {
  44. using signal = entt::sigh<void(void)>;
  45. ASSERT_NO_THROW(signal{});
  46. signal src{}, other{};
  47. ASSERT_NO_THROW(signal{src});
  48. ASSERT_NO_THROW(signal{std::move(other)});
  49. other = {};
  50. ASSERT_NO_THROW(src = other);
  51. ASSERT_NO_THROW(src = std::move(other));
  52. ASSERT_NO_THROW(delete new signal{});
  53. }
  54. TEST(SigH, Clear) {
  55. entt::sigh<void(int &)> sigh;
  56. entt::sink sink{sigh};
  57. sink.connect<&sigh_listener::f>();
  58. ASSERT_FALSE(sink.empty());
  59. ASSERT_FALSE(sigh.empty());
  60. sink.disconnect(static_cast<const void *>(nullptr));
  61. ASSERT_FALSE(sink.empty());
  62. ASSERT_FALSE(sigh.empty());
  63. sink.disconnect();
  64. ASSERT_TRUE(sink.empty());
  65. ASSERT_TRUE(sigh.empty());
  66. }
  67. TEST(SigH, Swap) {
  68. entt::sigh<void(int &)> sigh1;
  69. entt::sigh<void(int &)> sigh2;
  70. entt::sink sink1{sigh1};
  71. const entt::sink sink2{sigh2};
  72. sink1.connect<&sigh_listener::f>();
  73. ASSERT_FALSE(sink1.empty());
  74. ASSERT_TRUE(sink2.empty());
  75. ASSERT_FALSE(sigh1.empty());
  76. ASSERT_TRUE(sigh2.empty());
  77. sigh1.swap(sigh2);
  78. ASSERT_TRUE(sink1.empty());
  79. ASSERT_FALSE(sink2.empty());
  80. ASSERT_TRUE(sigh1.empty());
  81. ASSERT_FALSE(sigh2.empty());
  82. }
  83. TEST(SigH, Functions) {
  84. entt::sigh<void(int &)> sigh;
  85. entt::sink sink{sigh};
  86. int v = 0;
  87. sink.connect<&sigh_listener::f>();
  88. sigh.publish(v);
  89. ASSERT_FALSE(sigh.empty());
  90. ASSERT_EQ(sigh.size(), 1u);
  91. ASSERT_EQ(v, 1);
  92. v = 0;
  93. sink.disconnect<&sigh_listener::f>();
  94. sigh.publish(v);
  95. ASSERT_TRUE(sigh.empty());
  96. ASSERT_EQ(sigh.size(), 0u);
  97. ASSERT_EQ(v, 0);
  98. }
  99. TEST(SigH, FunctionsWithPayload) {
  100. entt::sigh<void()> sigh;
  101. entt::sink sink{sigh};
  102. int v = 0;
  103. sink.connect<&sigh_listener::f>(v);
  104. sigh.publish();
  105. ASSERT_FALSE(sigh.empty());
  106. ASSERT_EQ(sigh.size(), 1u);
  107. ASSERT_EQ(v, 1);
  108. v = 0;
  109. sink.disconnect<&sigh_listener::f>(v);
  110. sigh.publish();
  111. ASSERT_TRUE(sigh.empty());
  112. ASSERT_EQ(sigh.size(), 0u);
  113. ASSERT_EQ(v, 0);
  114. sink.connect<&sigh_listener::f>(v);
  115. sink.disconnect(&v);
  116. sigh.publish();
  117. ASSERT_EQ(v, 0);
  118. }
  119. TEST(SigH, Members) {
  120. sigh_listener l1, l2;
  121. entt::sigh<bool(int)> sigh;
  122. entt::sink sink{sigh};
  123. sink.connect<&sigh_listener::g>(l1);
  124. sigh.publish(3);
  125. ASSERT_TRUE(l1.val);
  126. ASSERT_FALSE(sigh.empty());
  127. ASSERT_EQ(sigh.size(), 1u);
  128. sink.disconnect<&sigh_listener::g>(l1);
  129. sigh.publish(3);
  130. ASSERT_TRUE(l1.val);
  131. ASSERT_TRUE(sigh.empty());
  132. ASSERT_EQ(sigh.size(), 0u);
  133. sink.connect<&sigh_listener::g>(&l1);
  134. sink.connect<&sigh_listener::h>(l2);
  135. ASSERT_FALSE(sigh.empty());
  136. ASSERT_EQ(sigh.size(), 2u);
  137. sink.disconnect(static_cast<const void *>(nullptr));
  138. ASSERT_FALSE(sigh.empty());
  139. ASSERT_EQ(sigh.size(), 2u);
  140. sink.disconnect(&l1);
  141. ASSERT_FALSE(sigh.empty());
  142. ASSERT_EQ(sigh.size(), 1u);
  143. }
  144. TEST(SigH, Collector) {
  145. sigh_listener listener;
  146. entt::sigh<bool(int)> sigh;
  147. entt::sink sink{sigh};
  148. int cnt = 0;
  149. sink.connect<&sigh_listener::g>(&listener);
  150. sink.connect<&sigh_listener::h>(listener);
  151. auto no_return = [&listener, &cnt](bool value) {
  152. ASSERT_TRUE(value);
  153. listener.val = true;
  154. ++cnt;
  155. };
  156. listener.val = true;
  157. sigh.collect(std::move(no_return), 3);
  158. ASSERT_FALSE(sigh.empty());
  159. ASSERT_EQ(cnt, 2);
  160. auto bool_return = [&cnt](bool value) {
  161. // gtest and its macro hell are sometimes really annoying...
  162. [](auto v) { ASSERT_TRUE(v); }(value);
  163. ++cnt;
  164. return true;
  165. };
  166. cnt = 0;
  167. sigh.collect(std::move(bool_return), 3);
  168. ASSERT_EQ(cnt, 1);
  169. }
  170. TEST(SigH, CollectorVoid) {
  171. sigh_listener listener;
  172. entt::sigh<void(int)> sigh;
  173. entt::sink sink{sigh};
  174. int cnt = 0;
  175. sink.connect<&sigh_listener::g>(&listener);
  176. sink.connect<&sigh_listener::h>(listener);
  177. sigh.collect([&cnt]() { ++cnt; }, 3);
  178. ASSERT_FALSE(sigh.empty());
  179. ASSERT_EQ(cnt, 2);
  180. cnt = 0;
  181. sigh.collect([&cnt]() { ++cnt; return true; }, 3);
  182. ASSERT_EQ(cnt, 1);
  183. }
  184. TEST(SigH, Connection) {
  185. entt::sigh<void(int &)> sigh;
  186. entt::sink sink{sigh};
  187. int v = 0;
  188. auto conn = sink.connect<&sigh_listener::f>();
  189. sigh.publish(v);
  190. ASSERT_FALSE(sigh.empty());
  191. ASSERT_TRUE(conn);
  192. ASSERT_EQ(v, 1);
  193. v = 0;
  194. conn.release();
  195. sigh.publish(v);
  196. ASSERT_TRUE(sigh.empty());
  197. ASSERT_FALSE(conn);
  198. ASSERT_EQ(0, v);
  199. }
  200. TEST(SigH, ScopedConnection) {
  201. sigh_listener listener;
  202. entt::sigh<void(int)> sigh;
  203. entt::sink sink{sigh};
  204. {
  205. ASSERT_FALSE(listener.val);
  206. const entt::scoped_connection conn = sink.connect<&sigh_listener::g>(listener);
  207. sigh.publish(1);
  208. ASSERT_FALSE(sigh.empty());
  209. ASSERT_TRUE(listener.val);
  210. ASSERT_TRUE(conn);
  211. }
  212. sigh.publish(1);
  213. ASSERT_TRUE(sigh.empty());
  214. ASSERT_TRUE(listener.val);
  215. }
  216. TEST(SigH, ScopedConnectionMove) {
  217. sigh_listener listener;
  218. entt::sigh<void(int)> sigh;
  219. entt::sink sink{sigh};
  220. entt::scoped_connection outer{sink.connect<&sigh_listener::g>(listener)};
  221. ASSERT_FALSE(sigh.empty());
  222. ASSERT_TRUE(outer);
  223. {
  224. const entt::scoped_connection inner{std::move(outer)};
  225. test::is_initialized(outer);
  226. ASSERT_FALSE(listener.val);
  227. ASSERT_FALSE(outer);
  228. ASSERT_TRUE(inner);
  229. sigh.publish(1);
  230. ASSERT_TRUE(listener.val);
  231. }
  232. ASSERT_TRUE(sigh.empty());
  233. outer = sink.connect<&sigh_listener::g>(listener);
  234. ASSERT_FALSE(sigh.empty());
  235. ASSERT_TRUE(outer);
  236. {
  237. entt::scoped_connection inner{};
  238. ASSERT_TRUE(listener.val);
  239. ASSERT_TRUE(outer);
  240. ASSERT_FALSE(inner);
  241. inner = std::move(outer);
  242. test::is_initialized(outer);
  243. ASSERT_FALSE(outer);
  244. ASSERT_TRUE(inner);
  245. sigh.publish(1);
  246. ASSERT_FALSE(listener.val);
  247. }
  248. ASSERT_TRUE(sigh.empty());
  249. }
  250. TEST(SigH, ScopedConnectionConstructorsAndOperators) {
  251. sigh_listener listener;
  252. entt::sigh<void(int)> sigh;
  253. entt::sink sink{sigh};
  254. {
  255. entt::scoped_connection inner{};
  256. ASSERT_TRUE(sigh.empty());
  257. ASSERT_FALSE(listener.val);
  258. ASSERT_FALSE(inner);
  259. inner = sink.connect<&sigh_listener::g>(listener);
  260. sigh.publish(1);
  261. ASSERT_FALSE(sigh.empty());
  262. ASSERT_TRUE(listener.val);
  263. ASSERT_TRUE(inner);
  264. inner.release();
  265. ASSERT_TRUE(sigh.empty());
  266. ASSERT_FALSE(inner);
  267. auto basic = sink.connect<&sigh_listener::g>(listener);
  268. inner = std::as_const(basic);
  269. sigh.publish(1);
  270. ASSERT_FALSE(sigh.empty());
  271. ASSERT_FALSE(listener.val);
  272. ASSERT_TRUE(inner);
  273. }
  274. sigh.publish(1);
  275. ASSERT_TRUE(sigh.empty());
  276. ASSERT_FALSE(listener.val);
  277. }
  278. TEST(SigH, ConstNonConstNoExcept) {
  279. entt::sigh<void()> sigh;
  280. entt::sink sink{sigh};
  281. const_nonconst_noexcept functor;
  282. const const_nonconst_noexcept cfunctor;
  283. sink.connect<&const_nonconst_noexcept::f>(functor);
  284. sink.connect<&const_nonconst_noexcept::g>(&functor);
  285. sink.connect<&const_nonconst_noexcept::h>(cfunctor);
  286. sink.connect<&const_nonconst_noexcept::i>(&cfunctor);
  287. sigh.publish();
  288. ASSERT_EQ(functor.cnt, 2);
  289. ASSERT_EQ(cfunctor.cnt, 2);
  290. sink.disconnect<&const_nonconst_noexcept::f>(functor);
  291. sink.disconnect<&const_nonconst_noexcept::g>(&functor);
  292. sink.disconnect<&const_nonconst_noexcept::h>(cfunctor);
  293. sink.disconnect<&const_nonconst_noexcept::i>(&cfunctor);
  294. sigh.publish();
  295. ASSERT_EQ(functor.cnt, 2);
  296. ASSERT_EQ(cfunctor.cnt, 2);
  297. }
  298. TEST(SigH, UnboundDataMember) {
  299. sigh_listener listener;
  300. entt::sigh<bool &(sigh_listener &)> sigh;
  301. entt::sink sink{sigh};
  302. ASSERT_FALSE(listener.val);
  303. sink.connect<&sigh_listener::val>();
  304. sigh.collect([](bool &value) { value = !value; }, listener);
  305. ASSERT_TRUE(listener.val);
  306. }
  307. TEST(SigH, UnboundMemberFunction) {
  308. sigh_listener listener;
  309. entt::sigh<void(sigh_listener *, int)> sigh;
  310. entt::sink sink{sigh};
  311. ASSERT_FALSE(listener.val);
  312. sink.connect<&sigh_listener::g>();
  313. sigh.publish(&listener, 1);
  314. ASSERT_TRUE(listener.val);
  315. }
  316. TEST(SigH, ConnectAndAutoDisconnect) {
  317. sigh_listener listener;
  318. entt::sigh<void(int &)> sigh;
  319. entt::sink sink{sigh};
  320. int v = 0;
  321. sink.connect<&sigh_listener::g>(listener);
  322. sink.connect<&connect_and_auto_disconnect>(sigh);
  323. ASSERT_FALSE(listener.val);
  324. ASSERT_EQ(sigh.size(), 2u);
  325. ASSERT_EQ(v, 0);
  326. sigh.publish(v);
  327. ASSERT_TRUE(listener.val);
  328. ASSERT_EQ(sigh.size(), 2u);
  329. ASSERT_EQ(v, 0);
  330. sigh.publish(v);
  331. ASSERT_FALSE(listener.val);
  332. ASSERT_EQ(sigh.size(), 2u);
  333. ASSERT_EQ(v, 1);
  334. }
  335. TEST(SigH, CustomAllocator) {
  336. const std::allocator<void (*)(int)> allocator;
  337. entt::sigh<void(int), std::allocator<void (*)(int)>> sigh{allocator};
  338. ASSERT_EQ(sigh.get_allocator(), allocator);
  339. ASSERT_FALSE(sigh.get_allocator() != allocator);
  340. ASSERT_TRUE(sigh.empty());
  341. entt::sink sink{sigh};
  342. sigh_listener listener;
  343. sink.template connect<&sigh_listener::g>(listener);
  344. decltype(sigh) copy{sigh, allocator};
  345. sink.disconnect(&listener);
  346. ASSERT_TRUE(sigh.empty());
  347. ASSERT_FALSE(copy.empty());
  348. sigh = copy;
  349. ASSERT_FALSE(sigh.empty());
  350. ASSERT_FALSE(copy.empty());
  351. decltype(sigh) move{std::move(copy), allocator};
  352. test::is_initialized(copy);
  353. ASSERT_TRUE(copy.empty());
  354. ASSERT_FALSE(move.empty());
  355. sink = entt::sink{move};
  356. sink.disconnect(&listener);
  357. ASSERT_TRUE(copy.empty());
  358. ASSERT_TRUE(move.empty());
  359. sink.template connect<&sigh_listener::g>(listener);
  360. copy.swap(move);
  361. ASSERT_FALSE(copy.empty());
  362. ASSERT_TRUE(move.empty());
  363. sink = entt::sink{copy};
  364. sink.disconnect();
  365. ASSERT_TRUE(copy.empty());
  366. ASSERT_TRUE(move.empty());
  367. }