/** * @file tests/unit/test_thread_safe.cpp * @brief Tests for thread-safe utility types. */ // test includes #include "../tests_common.h" // standard includes #include #include // local includes #include "src/thread_safe.h" static_assert(!std::is_convertible_v>); /** * @brief Const event inspection observes state transitions without consuming the pending value. */ TEST(ThreadSafeEvent, ConstPeekPreservesPendingValuesAcrossStateChanges) { safe::event_t event; const auto &view = event; EXPECT_FALSE(view.peek()); event.raise(42); EXPECT_TRUE(view.peek()); EXPECT_TRUE(view.peek()); EXPECT_EQ(event.try_pop(), 42); EXPECT_FALSE(view.peek()); event.raise(7); event.stop(); EXPECT_FALSE(view.peek()); event.reset(); EXPECT_FALSE(view.peek()); event.raise(9); EXPECT_TRUE(view.peek()); } /** * @brief Mail cleanup removes an expired post while preserving an active post's owner. */ TEST(ThreadSafeMail, CleanupPreservesLivePostsAndRemovesExpiredPosts) { safe::mail_raw_t mailbox; const auto live = std::make_shared(7); mailbox.id_to_post.try_emplace("live", live); mailbox.id_to_post.try_emplace("expired", std::weak_ptr {}); mailbox.cleanup(); EXPECT_EQ(mailbox.id_to_post.size(), 1); EXPECT_EQ(mailbox.id_to_post.at("live").lock(), live); mailbox.cleanup(); EXPECT_EQ(mailbox.id_to_post.size(), 1); } /** * @brief Repeated lookups reuse each live mailbox channel and preserve queued values. */ TEST(ThreadSafeMail, ReusesExistingEventAndQueueForDuplicateIdentifiers) { const auto mailbox = std::make_shared(); const auto event = mailbox->event("event"); event->raise(0); const auto same_event = mailbox->event("event"); EXPECT_EQ(same_event, event); EXPECT_EQ(same_event->pop(), 0); const auto queue = mailbox->queue("queue"); ASSERT_TRUE(queue->raise(7)); const auto same_queue = mailbox->queue("queue"); EXPECT_EQ(same_queue, queue); EXPECT_EQ(same_queue->pop(), 7); EXPECT_EQ(mailbox->id_to_post.size(), 2); } TEST(ThreadSafeQueue, RejectsNewestItemAtCapacity) { safe::queue_t queue {1, safe::queue_t::overflow_policy_e::reject}; ASSERT_TRUE(queue.raise(1)); EXPECT_FALSE(queue.raise(2)); const auto value = queue.pop(); ASSERT_TRUE(value); EXPECT_EQ(*value, 1); } TEST(ThreadSafeQueue, DropsQueuedItemsByDefaultAtCapacity) { safe::queue_t queue {2}; ASSERT_TRUE(queue.raise(1)); ASSERT_TRUE(queue.raise(2)); ASSERT_TRUE(queue.raise(3)); const auto value = queue.pop(); ASSERT_TRUE(value); EXPECT_EQ(*value, 3); } TEST(ThreadSafeQueue, RejectsItemsAfterStop) { safe::queue_t queue; queue.stop(); EXPECT_FALSE(queue.raise(1)); }