#include #include #include #include "Consumer.hpp" #include "UnixIpcBridge.hpp" // QSignalSpy needs a QCoreApplication to dispatch queued signals static int argc_ = 0; static QCoreApplication app_(argc_, nullptr); TEST(ConsumerThreadTest, ReceivesSingleValue) { const std::string sock = "/tmp/test_ct_single.sock"; ConsumerThread consumer(sock); // QSignalSpy records every emission of the given signal QSignalSpy spy(&consumer, &ConsumerThread::valueReceived); consumer.start(); UnixIpcBridge bridge(sock); bridge.send(42); // spy.wait() pumps the event loop for up to 1s until a signal arrives spy.wait(1000); consumer.stop(); ASSERT_EQ(spy.count(), 1); EXPECT_EQ(spy.at(0).at(0).toInt(), 42); } TEST(ConsumerThreadTest, ReceivesMultipleValues) { const std::string sock = "/tmp/test_ct_multi.sock"; ConsumerThread consumer(sock); QSignalSpy spy(&consumer, &ConsumerThread::valueReceived); consumer.start(); constexpr int kMessages = 5; for (int i = 0; i < kMessages; ++i) { UnixIpcBridge bridge(sock); bridge.send(i * 10); // Small delay so the consumer can re-enter accept() between sends std::this_thread::sleep_for(std::chrono::milliseconds(10)); } // Wait until all signals arrive (or timeout after 5s) for (int attempt = 0; spy.count() < kMessages && attempt < 50; ++attempt) { spy.wait(100); } consumer.stop(); ASSERT_EQ(spy.count(), kMessages); for (int i = 0; i < kMessages; ++i) { EXPECT_EQ(spy.at(i).at(0).toInt(), i * 10); } } TEST(ConsumerThreadTest, ReceivesNegativeAndZero) { // Zero { const std::string sock = "/tmp/test_ct_zero.sock"; ConsumerThread consumer(sock); QSignalSpy spy(&consumer, &ConsumerThread::valueReceived); consumer.start(); UnixIpcBridge bridge(sock); bridge.send(0); spy.wait(1000); consumer.stop(); ASSERT_EQ(spy.count(), 1); EXPECT_EQ(spy.at(0).at(0).toInt(), 0); } // Negative { const std::string sock = "/tmp/test_ct_neg.sock"; ConsumerThread consumer(sock); QSignalSpy spy(&consumer, &ConsumerThread::valueReceived); consumer.start(); UnixIpcBridge bridge(sock); bridge.send(-999); spy.wait(1000); consumer.stop(); ASSERT_EQ(spy.count(), 1); EXPECT_EQ(spy.at(0).at(0).toInt(), -999); } } TEST(ConsumerThreadTest, StopsCleanlyWithoutDeadlock) { const std::string sock = "/tmp/test_ct_stop.sock"; ConsumerThread consumer(sock); consumer.start(); // stop() must return without hanging, even with no connections consumer.stop(); } TEST(ConsumerThreadTest, StopsCleanlyWhenNeverStarted) { const std::string sock = "/tmp/test_ct_nostart.sock"; ConsumerThread consumer(sock); // stop() on a consumer that was never started must not crash consumer.stop(); }