| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- #include <memory>
- #include <utility>
- #include <gtest/gtest.h>
- #include <entt/signal/sigh.hpp>
- #include "../../common/linter.hpp"
- struct sigh_listener {
- static void f(int &iv) {
- ++iv;
- }
- [[nodiscard]] bool g(int) {
- val = !val;
- return true;
- }
- [[nodiscard]] bool h(const int &) const {
- return val;
- }
- // useless definition just because msvc does weird things if both are empty
- void i() {
- val = val && val;
- }
- bool val{false};
- };
- struct const_nonconst_noexcept {
- void f() {
- ++cnt;
- }
- void g() noexcept {
- ++cnt;
- }
- void h() const {
- ++cnt;
- }
- void i() const noexcept {
- ++cnt;
- }
- mutable int cnt{0};
- };
- void connect_and_auto_disconnect(entt::sigh<void(int &)> &sigh, const int &) {
- entt::sink sink{sigh};
- sink.connect<sigh_listener::f>();
- sink.disconnect<&connect_and_auto_disconnect>(sigh);
- }
- TEST(SigH, Lifetime) {
- using signal = entt::sigh<void(void)>;
- ASSERT_NO_THROW(signal{});
- signal src{};
- signal other{};
- ASSERT_NO_THROW(signal{src});
- ASSERT_NO_THROW(signal{std::move(other)});
- other = {};
- ASSERT_NO_THROW(src = other);
- ASSERT_NO_THROW(src = std::move(other));
- ASSERT_NO_THROW(delete new signal{});
- }
- TEST(SigH, Disconnect) {
- sigh_listener listener;
- entt::sigh<void(int &)> sigh;
- entt::sink sink{sigh};
- sink.connect<&sigh_listener::f>();
- ASSERT_FALSE(sink.empty());
- ASSERT_FALSE(sigh.empty());
- sink.disconnect<&sigh_listener::f>();
- ASSERT_TRUE(sink.empty());
- ASSERT_TRUE(sigh.empty());
- sink.connect<&sigh_listener::g>(listener);
- ASSERT_FALSE(sink.empty());
- ASSERT_FALSE(sigh.empty());
- sink.disconnect<&sigh_listener::g>(listener);
- ASSERT_TRUE(sink.empty());
- ASSERT_TRUE(sigh.empty());
- sink.connect<&sigh_listener::g>(listener);
- ASSERT_FALSE(sink.empty());
- ASSERT_FALSE(sigh.empty());
- sink.disconnect(&listener);
- ASSERT_TRUE(sink.empty());
- ASSERT_TRUE(sigh.empty());
- sink.connect<&sigh_listener::f>();
- ASSERT_FALSE(sink.empty());
- ASSERT_FALSE(sigh.empty());
- sink.disconnect();
- ASSERT_TRUE(sink.empty());
- ASSERT_TRUE(sigh.empty());
- }
- TEST(SigH, Swap) {
- entt::sigh<void(int &)> sigh1;
- entt::sigh<void(int &)> sigh2;
- entt::sink sink1{sigh1};
- const entt::sink sink2{sigh2};
- sink1.connect<&sigh_listener::f>();
- ASSERT_FALSE(sink1.empty());
- ASSERT_TRUE(sink2.empty());
- ASSERT_FALSE(sigh1.empty());
- ASSERT_TRUE(sigh2.empty());
- sigh1.swap(sigh2);
- ASSERT_TRUE(sink1.empty());
- ASSERT_FALSE(sink2.empty());
- ASSERT_TRUE(sigh1.empty());
- ASSERT_FALSE(sigh2.empty());
- }
- TEST(SigH, Functions) {
- entt::sigh<void(int &)> sigh;
- entt::sink sink{sigh};
- int value = 0;
- sink.connect<&sigh_listener::f>();
- sigh.publish(value);
- ASSERT_FALSE(sigh.empty());
- ASSERT_EQ(sigh.size(), 1u);
- ASSERT_EQ(value, 1);
- value = 0;
- sink.disconnect<&sigh_listener::f>();
- sigh.publish(value);
- ASSERT_TRUE(sigh.empty());
- ASSERT_EQ(sigh.size(), 0u);
- ASSERT_EQ(value, 0);
- }
- TEST(SigH, FunctionsWithPayload) {
- entt::sigh<void()> sigh;
- entt::sink sink{sigh};
- int value = 0;
- sink.connect<&sigh_listener::f>(value);
- sigh.publish();
- ASSERT_FALSE(sigh.empty());
- ASSERT_EQ(sigh.size(), 1u);
- ASSERT_EQ(value, 1);
- value = 0;
- sink.disconnect<&sigh_listener::f>(value);
- sigh.publish();
- ASSERT_TRUE(sigh.empty());
- ASSERT_EQ(sigh.size(), 0u);
- ASSERT_EQ(value, 0);
- sink.connect<&sigh_listener::f>(value);
- sink.disconnect(&value);
- sigh.publish();
- ASSERT_EQ(value, 0);
- }
- TEST(SigH, Members) {
- sigh_listener l1;
- sigh_listener l2;
- entt::sigh<bool(int)> sigh;
- entt::sink sink{sigh};
- sink.connect<&sigh_listener::g>(l1);
- sigh.publish(3);
- ASSERT_TRUE(l1.val);
- ASSERT_FALSE(sigh.empty());
- ASSERT_EQ(sigh.size(), 1u);
- sink.disconnect<&sigh_listener::g>(l1);
- sigh.publish(3);
- ASSERT_TRUE(l1.val);
- ASSERT_TRUE(sigh.empty());
- ASSERT_EQ(sigh.size(), 0u);
- sink.connect<&sigh_listener::g>(&l1);
- sink.connect<&sigh_listener::h>(l2);
- ASSERT_FALSE(sigh.empty());
- ASSERT_EQ(sigh.size(), 2u);
- sink.disconnect(&l1);
- ASSERT_FALSE(sigh.empty());
- ASSERT_EQ(sigh.size(), 1u);
- }
- TEST(SigH, Collector) {
- sigh_listener listener;
- entt::sigh<bool(int)> sigh;
- entt::sink sink{sigh};
- int cnt = 0;
- sink.connect<&sigh_listener::g>(&listener);
- sink.connect<&sigh_listener::h>(listener);
- auto no_return = [&listener, &cnt](bool value) {
- ASSERT_TRUE(value);
- listener.val = true;
- ++cnt;
- };
- listener.val = true;
- sigh.collect(std::move(no_return), 3);
- ASSERT_FALSE(sigh.empty());
- ASSERT_EQ(cnt, 2);
- auto bool_return = [&cnt](bool value) {
- // gtest and its macro hell are sometimes really annoying...
- [](auto curr) { ASSERT_TRUE(curr); }(value);
- ++cnt;
- return true;
- };
- cnt = 0;
- sigh.collect(std::move(bool_return), 3);
- ASSERT_EQ(cnt, 1);
- }
- TEST(SigH, CollectorVoid) {
- sigh_listener listener;
- entt::sigh<void(int)> sigh;
- entt::sink sink{sigh};
- int cnt = 0;
- sink.connect<&sigh_listener::g>(&listener);
- sink.connect<&sigh_listener::h>(listener);
- sigh.collect([&cnt]() { ++cnt; }, 3);
- ASSERT_FALSE(sigh.empty());
- ASSERT_EQ(cnt, 2);
- cnt = 0;
- sigh.collect([&cnt]() { ++cnt; return true; }, 3);
- ASSERT_EQ(cnt, 1);
- }
- TEST(SigH, Connection) {
- entt::sigh<void(int &)> sigh;
- entt::sink sink{sigh};
- int value = 0;
- auto conn = sink.connect<&sigh_listener::f>();
- sigh.publish(value);
- ASSERT_FALSE(sigh.empty());
- ASSERT_TRUE(conn);
- ASSERT_EQ(value, 1);
- value = 0;
- conn.release();
- sigh.publish(value);
- ASSERT_TRUE(sigh.empty());
- ASSERT_FALSE(conn);
- ASSERT_EQ(0, value);
- }
- TEST(SigH, ScopedConnection) {
- sigh_listener listener;
- entt::sigh<void(int)> sigh;
- entt::sink sink{sigh};
- {
- ASSERT_FALSE(listener.val);
- const entt::scoped_connection conn = sink.connect<&sigh_listener::g>(listener);
- sigh.publish(1);
- ASSERT_FALSE(sigh.empty());
- ASSERT_TRUE(listener.val);
- ASSERT_TRUE(conn);
- }
- sigh.publish(1);
- ASSERT_TRUE(sigh.empty());
- ASSERT_TRUE(listener.val);
- }
- TEST(SigH, ScopedConnectionMove) {
- sigh_listener listener;
- entt::sigh<void(int)> sigh;
- entt::sink sink{sigh};
- entt::scoped_connection outer{sink.connect<&sigh_listener::g>(listener)};
- ASSERT_FALSE(sigh.empty());
- ASSERT_TRUE(outer);
- {
- const entt::scoped_connection inner{std::move(outer)};
- test::is_initialized(outer);
- ASSERT_FALSE(listener.val);
- ASSERT_FALSE(outer);
- ASSERT_TRUE(inner);
- sigh.publish(1);
- ASSERT_TRUE(listener.val);
- }
- ASSERT_TRUE(sigh.empty());
- outer = sink.connect<&sigh_listener::g>(listener);
- ASSERT_FALSE(sigh.empty());
- ASSERT_TRUE(outer);
- {
- entt::scoped_connection inner{};
- ASSERT_TRUE(listener.val);
- ASSERT_TRUE(outer);
- ASSERT_FALSE(inner);
- inner = std::move(outer);
- test::is_initialized(outer);
- ASSERT_FALSE(outer);
- ASSERT_TRUE(inner);
- sigh.publish(1);
- ASSERT_FALSE(listener.val);
- }
- ASSERT_TRUE(sigh.empty());
- }
- TEST(SigH, ScopedConnectionConstructorsAndOperators) {
- sigh_listener listener;
- entt::sigh<void(int)> sigh;
- entt::sink sink{sigh};
- {
- entt::scoped_connection inner{};
- ASSERT_TRUE(sigh.empty());
- ASSERT_FALSE(listener.val);
- ASSERT_FALSE(inner);
- inner = sink.connect<&sigh_listener::g>(listener);
- sigh.publish(1);
- ASSERT_FALSE(sigh.empty());
- ASSERT_TRUE(listener.val);
- ASSERT_TRUE(inner);
- inner.release();
- ASSERT_TRUE(sigh.empty());
- ASSERT_FALSE(inner);
- auto basic = sink.connect<&sigh_listener::g>(listener);
- inner = std::as_const(basic);
- sigh.publish(1);
- ASSERT_FALSE(sigh.empty());
- ASSERT_FALSE(listener.val);
- ASSERT_TRUE(inner);
- }
- sigh.publish(1);
- ASSERT_TRUE(sigh.empty());
- ASSERT_FALSE(listener.val);
- }
- TEST(SigH, ConstNonConstNoExcept) {
- entt::sigh<void()> sigh;
- entt::sink sink{sigh};
- const_nonconst_noexcept functor;
- const const_nonconst_noexcept cfunctor;
- sink.connect<&const_nonconst_noexcept::f>(functor);
- sink.connect<&const_nonconst_noexcept::g>(&functor);
- sink.connect<&const_nonconst_noexcept::h>(cfunctor);
- sink.connect<&const_nonconst_noexcept::i>(&cfunctor);
- sigh.publish();
- ASSERT_EQ(functor.cnt, 2);
- ASSERT_EQ(cfunctor.cnt, 2);
- sink.disconnect<&const_nonconst_noexcept::f>(functor);
- sink.disconnect<&const_nonconst_noexcept::g>(&functor);
- sink.disconnect<&const_nonconst_noexcept::h>(cfunctor);
- sink.disconnect<&const_nonconst_noexcept::i>(&cfunctor);
- sigh.publish();
- ASSERT_EQ(functor.cnt, 2);
- ASSERT_EQ(cfunctor.cnt, 2);
- }
- TEST(SigH, UnboundDataMember) {
- sigh_listener listener;
- entt::sigh<bool &(sigh_listener &)> sigh;
- entt::sink sink{sigh};
- ASSERT_FALSE(listener.val);
- sink.connect<&sigh_listener::val>();
- sigh.collect([](bool &value) { value = !value; }, listener);
- ASSERT_TRUE(listener.val);
- }
- TEST(SigH, UnboundMemberFunction) {
- sigh_listener listener;
- entt::sigh<void(sigh_listener *, int)> sigh;
- entt::sink sink{sigh};
- ASSERT_FALSE(listener.val);
- sink.connect<&sigh_listener::g>();
- sigh.publish(&listener, 1);
- ASSERT_TRUE(listener.val);
- }
- TEST(SigH, ConnectAndAutoDisconnect) {
- sigh_listener listener;
- entt::sigh<void(int &)> sigh;
- entt::sink sink{sigh};
- int value = 0;
- sink.connect<&sigh_listener::g>(listener);
- sink.connect<&connect_and_auto_disconnect>(sigh);
- ASSERT_FALSE(listener.val);
- ASSERT_EQ(sigh.size(), 2u);
- ASSERT_EQ(value, 0);
- sigh.publish(value);
- ASSERT_TRUE(listener.val);
- ASSERT_EQ(sigh.size(), 2u);
- ASSERT_EQ(value, 0);
- sigh.publish(value);
- ASSERT_FALSE(listener.val);
- ASSERT_EQ(sigh.size(), 2u);
- ASSERT_EQ(value, 1);
- }
- TEST(SigH, CustomAllocator) {
- const std::allocator<void (*)(int)> allocator;
- entt::sigh<void(int), std::allocator<void (*)(int)>> sigh{allocator};
- ASSERT_EQ(sigh.get_allocator(), allocator);
- ASSERT_FALSE(sigh.get_allocator() != allocator);
- ASSERT_TRUE(sigh.empty());
- entt::sink sink{sigh};
- sigh_listener listener;
- sink.template connect<&sigh_listener::g>(listener);
- decltype(sigh) copy{sigh, allocator};
- sink.disconnect(&listener);
- ASSERT_TRUE(sigh.empty());
- ASSERT_FALSE(copy.empty());
- sigh = copy;
- ASSERT_FALSE(sigh.empty());
- ASSERT_FALSE(copy.empty());
- decltype(sigh) move{std::move(copy), allocator};
- test::is_initialized(copy);
- ASSERT_TRUE(copy.empty());
- ASSERT_FALSE(move.empty());
- sink = entt::sink{move};
- sink.disconnect(&listener);
- ASSERT_TRUE(copy.empty());
- ASSERT_TRUE(move.empty());
- sink.template connect<&sigh_listener::g>(listener);
- copy.swap(move);
- ASSERT_FALSE(copy.empty());
- ASSERT_TRUE(move.empty());
- sink = entt::sink{copy};
- sink.disconnect();
- ASSERT_TRUE(copy.empty());
- ASSERT_TRUE(move.empty());
- }
|