Changeset View
Changeset View
Standalone View
Standalone View
src/tests/event-emitter-test.cpp
| Show First 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | SECTION("Handler should be disconnected once watchable is destroyed") { | ||||
| guard.reset(); | guard.reset(); | ||||
| thread.join(); | thread.join(); | ||||
| REQUIRE(counter == 1); | REQUIRE(counter == 1); | ||||
| REQUIRE(counter2 == 1); | REQUIRE(counter2 == 1); | ||||
| } | } | ||||
| SECTION("Expired listeners should be removed from internal list") { | |||||
| auto guard = boost::asio::make_work_guard(ioContext.get_executor()); | |||||
| auto thread = std::thread([&] { ioContext.run(); }); | |||||
| std::vector<int> results; | |||||
| { | |||||
| auto w = ee.watchable(); | |||||
| w.after<ReceivingPresenceEvent>( | |||||
| [&](auto) { | |||||
| results.push_back(1); | |||||
| }); | |||||
| } | |||||
| // w is destroyed, listener expired | |||||
| // Emit several events to trigger cleanup of expired listener | |||||
| // via sendToListeners -> erase-remove | |||||
| for (int i = 0; i < 5; ++i) { | |||||
| ee.emit(ReceivingPresenceEvent{}); | |||||
| } | |||||
| std::this_thread::sleep_for(std::chrono::milliseconds{100}); | |||||
| // Now register a new listener - if erase-remove works, the old | |||||
| // expired listener was removed and no stale references remain | |||||
| int newCounter = 0; | |||||
| { | |||||
| auto w2 = ee.watchable(); | |||||
| w2.after<ReceivingPresenceEvent>( | |||||
| [&](auto) { | |||||
| ++newCounter; | |||||
| }); | |||||
| ee.emit(ReceivingPresenceEvent{}); | |||||
| ee.emit(ReceivingPresenceEvent{}); | |||||
| std::this_thread::sleep_for(std::chrono::milliseconds{100}); | |||||
| } | |||||
| guard.reset(); | |||||
| thread.join(); | |||||
| REQUIRE(results.empty()); | |||||
| REQUIRE(newCounter == 2); | |||||
| } | |||||
| SECTION("Many expired listeners should be cleaned without issue") { | |||||
| auto guard = boost::asio::make_work_guard(ioContext.get_executor()); | |||||
| auto thread = std::thread([&] { ioContext.run(); }); | |||||
| // Create and destroy many watchables to build up expired listeners | |||||
| for (int i = 0; i < 50; ++i) { | |||||
| auto w = ee.watchable(); | |||||
| std::atomic<int> unused{0}; | |||||
| w.after<ReceivingPresenceEvent>( | |||||
| [&unused](auto) { | |||||
| ++unused; | |||||
| }); | |||||
| } | |||||
| // All watchables destroyed, all listeners expired | |||||
| // Emit events to trigger cleanup via erase-remove | |||||
| for (int i = 0; i < 10; ++i) { | |||||
| ee.emit(ReceivingPresenceEvent{}); | |||||
| } | |||||
| std::this_thread::sleep_for(std::chrono::milliseconds{100}); | |||||
| // Verify emitter still works after cleanup | |||||
| int aliveCounter = 0; | |||||
| { | |||||
| auto w = ee.watchable(); | |||||
| w.after<ReceivingPresenceEvent>( | |||||
| [&](auto) { | |||||
| ++aliveCounter; | |||||
| }); | |||||
| ee.emit(ReceivingPresenceEvent{}); | |||||
| std::this_thread::sleep_for(std::chrono::milliseconds{100}); | |||||
| } | |||||
| guard.reset(); | |||||
| thread.join(); | |||||
| REQUIRE(aliveCounter == 1); | |||||
| } | |||||
| } | } | ||||