#include #include #include #include "log_level.hpp" #include "message_queue.hpp" #include "thread_test_utils.hpp" namespace app::tests { using namespace app; void testPushAndPop() { MessageQueue queue; queue.push({logger::LogLevel::info(), "Hello"}); auto message = queue.pop(); assert(message.has_value()); assert(message->level == logger::LogLevel::info()); assert(message->message == "Hello"); } void testFifoOrder() { MessageQueue queue; queue.push({logger::LogLevel::debug(), "first"}); queue.push({logger::LogLevel::info(), "second"}); queue.push({logger::LogLevel::error(), "third"}); assert(queue.pop()->message == "first"); assert(queue.pop()->message == "second"); assert(queue.pop()->message == "third"); } void testPopWaitsForMessage() { MessageQueue queue; bool received = false; std::thread worker([&]() { auto message = queue.pop(); assert(message.has_value()); assert(message->level == logger::LogLevel::error()); assert(message->message == "Delayed"); received = true; }); // Даём потоку worker возможность дойти до queue.pop() // и заблокироваться в ожидании сообщения. std::this_thread::sleep_for(std::chrono::milliseconds(100)); assert(!received); // Добавляем сообщение и тем самым разблокируем worker. queue.push({logger::LogLevel::error(), "Delayed"}); // Ожидаем полного завершения потока worker. worker.join(); assert(received); } void testConcurrentPushAndPop() { MessageQueue queue; constexpr std::size_t threadCount = 8; constexpr std::size_t messagesPerThread = 1000; std::vector producers; for (std::size_t i = 0; i < threadCount; ++i) { producers.emplace_back( helpers::createProducer(queue, i, messagesPerThread)); } const auto expectedMessages = threadCount * messagesPerThread; for (std::size_t i = 0; i < expectedMessages; ++i) { auto message = queue.pop(); assert(message.has_value()); assert(!message->message.empty()); } for (auto &producer : producers) { producer.join(); } assert(queue.empty()); } void testStopReturnsNullopt() { MessageQueue queue; queue.stop(); auto message = queue.pop(); assert(!message.has_value()); } void testStopReturnsRemainingMessages() { MessageQueue queue; queue.push({logger::LogLevel::info(), "first"}); queue.push({logger::LogLevel::error(), "second"}); queue.stop(); auto first = queue.pop(); auto second = queue.pop(); auto third = queue.pop(); assert(first.has_value()); assert(first->message == "first"); assert(second.has_value()); assert(second->message == "second"); assert(!third.has_value()); } void runTests() { testPushAndPop(); testFifoOrder(); testPopWaitsForMessage(); testConcurrentPushAndPop(); testStopReturnsNullopt(); testStopReturnsRemainingMessages(); } } // namespace app::tests int main() { app::tests::runTests(); return 0; }