sigh.cpp 11 KB

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