#include "gtest/gtest.h" #include "gmock/gmock.h" #include "testutil.h" #include "piblockingdequeue.h" using ::testing::Return; using ::testing::Eq; using ::testing::Matcher; class MockConditionVar: public PIConditionVariable { public: bool isWaitCalled = false; bool isWaitForCalled = false; bool isTrueCondition = false; int timeout = -1; void wait(PIMutex& lk) override { isWaitCalled = true; } void wait(PIMutex& lk, const std::function& condition) override { isWaitCalled = true; lk.lock(); isTrueCondition = condition(); lk.unlock(); } bool waitFor(PIMutex& lk, int timeoutMs) override { isWaitForCalled = true; timeout = timeoutMs; return false; } bool waitFor(PIMutex& lk, int timeoutMs, const std::function& condition) override { isWaitForCalled = true; lk.lock(); isTrueCondition = condition(); timeout = timeoutMs; lk.unlock(); return isTrueCondition; } }; template class MockDeque { public: MOCK_METHOD1_T(push_back, void(T&&)); MOCK_METHOD1_T(push_back, void(const T&)); MOCK_METHOD0(size, size_t()); MOCK_METHOD0_T(front, T()); MOCK_METHOD0(pop_front, void()); }; template class PIBlockingDequeuePrepare: public PIBlockingDequeue { public: typedef PIBlockingDequeue SuperClass; PIBlockingDequeuePrepare(size_t capacity = SIZE_MAX): SuperClass(capacity) { } template explicit PIBlockingDequeuePrepare(const Iterable& other): SuperClass(other) { } MockConditionVar* getCondVarAdd() { return this->cond_var_add; } MockConditionVar* getCondVarRem() { return this->cond_var_rem; } MockDeque& getQueue() { return this->data_queue; } }; TEST(BlockingDequeueUnitTest, put_is_block_when_capacity_reach) { size_t capacity = 0; PIBlockingDequeuePrepare dequeue(capacity); dequeue.put(11); ASSERT_TRUE(dequeue.getCondVarRem()->isWaitCalled); ASSERT_FALSE(dequeue.getCondVarRem()->isTrueCondition); } TEST(BlockingDequeueUnitTest, offer2_timedout_is_false_when_capacity_reach) { size_t capacity = 0; int timeout = 11; PIBlockingDequeuePrepare dequeue(capacity); ASSERT_FALSE(dequeue.offer(11, timeout)); } TEST(BlockingDequeueUnitTest, offer2_timedout_is_block_when_capacity_reach) { size_t capacity = 0; int timeout = 11; PIBlockingDequeuePrepare dequeue(capacity); dequeue.offer(11, timeout); EXPECT_TRUE(dequeue.getCondVarRem()->isWaitForCalled); EXPECT_EQ(timeout, dequeue.getCondVarRem()->timeout); ASSERT_FALSE(dequeue.getCondVarRem()->isTrueCondition); } TEST(BlockingDequeueUnitTest, offer1_is_true) { size_t capacity = 1; PIBlockingDequeuePrepare dequeue(capacity); EXPECT_CALL(dequeue.getQueue(), size()) .WillOnce(Return(capacity - 1)); ASSERT_TRUE(dequeue.offer(10)); } TEST(BlockingDequeueUnitTest, offer1_is_pop) { size_t capacity = 1; int val = 10; PIBlockingDequeuePrepare dequeue(capacity); EXPECT_CALL(dequeue.getQueue(), size()) .WillRepeatedly(Return(capacity - 1)); EXPECT_CALL(dequeue.getQueue(), push_back(Matcher( Eq(val)) )).Times(1); dequeue.offer(val); } TEST(BlockingDequeueUnitTest, offer1_is_false_when_capacity_reach) { size_t capacity = 1; PIBlockingDequeuePrepare dequeue(capacity); EXPECT_CALL(dequeue.getQueue(), size()) .WillOnce(Return(capacity + 1)); ASSERT_FALSE(dequeue.offer(10)); } TEST(BlockingDequeueUnitTest, offer1_is_not_pop_when_capacity_reach) { size_t capacity = 1; PIBlockingDequeuePrepare dequeue(capacity); EXPECT_CALL(dequeue.getQueue(), size()) .WillRepeatedly(Return(capacity + 1)); EXPECT_CALL(dequeue.getQueue(), front()).Times(0); EXPECT_CALL(dequeue.getQueue(), pop_front()).Times(0); dequeue.offer(10); } // TODO change take_is_block_when_empty to prevent segfault TEST(DISABLED_BlockingDequeueUnitTest, take_is_block_when_empty) { size_t capacity = 1; PIBlockingDequeuePrepare dequeue(capacity); // May cause segfault because take front of empty queue dequeue.take(); EXPECT_TRUE(dequeue.getCondVarAdd()->isWaitCalled); ASSERT_FALSE(dequeue.getCondVarAdd()->isTrueCondition); } TEST(BlockingDequeueUnitTest, take_is_not_block_when_not_empty) { size_t capacity = 1; PIBlockingDequeuePrepare dequeue(capacity); dequeue.offer(111); dequeue.take(); EXPECT_TRUE(dequeue.getCondVarAdd()->isWaitCalled); ASSERT_TRUE(dequeue.getCondVarAdd()->isTrueCondition); } TEST(BlockingDequeueUnitTest, take_is_value_eq_to_offer_value) { size_t capacity = 1; PIBlockingDequeuePrepare dequeue(capacity); dequeue.offer(111); ASSERT_EQ(dequeue.take(), 111); } TEST(BlockingDequeueUnitTest, take_is_last) { size_t capacity = 10; PIBlockingDequeuePrepare dequeue(capacity); EXPECT_TRUE(dequeue.offer(111)); EXPECT_TRUE(dequeue.offer(222)); ASSERT_EQ(dequeue.take(), 111); ASSERT_EQ(dequeue.take(), 222); } TEST(BlockingDequeueUnitTest, poll_is_not_block_when_empty) { size_t capacity = 1; bool isOk; PIBlockingDequeuePrepare dequeue(capacity); dequeue.poll(111, &isOk); EXPECT_FALSE(dequeue.getCondVarAdd()->isWaitForCalled); } TEST(BlockingDequeueUnitTest, poll_is_default_value_when_empty) { size_t capacity = 1; bool isOk; PIBlockingDequeuePrepare dequeue(capacity); ASSERT_EQ(dequeue.poll(111, &isOk), 111); } TEST(BlockingDequeueUnitTest, poll_is_offer_value_when_not_empty) { size_t capacity = 1; bool isOk; PIBlockingDequeuePrepare dequeue(capacity); dequeue.offer(111); ASSERT_EQ(dequeue.poll(-1, &isOk), 111); } TEST(BlockingDequeueUnitTest, poll_timeouted_is_block_when_empty) { size_t capacity = 1; int timeout = 11; PIBlockingDequeuePrepare dequeue(capacity); dequeue.poll(timeout, 111); EXPECT_TRUE(dequeue.getCondVarAdd()->isWaitForCalled); EXPECT_EQ(timeout, dequeue.getCondVarAdd()->timeout); ASSERT_FALSE(dequeue.getCondVarAdd()->isTrueCondition); } TEST(BlockingDequeueUnitTest, poll_timeouted_is_default_value_when_empty) { size_t capacity = 1; int timeout = 11; PIBlockingDequeuePrepare dequeue(capacity); ASSERT_EQ(dequeue.poll(timeout, 111), 111); } TEST(BlockingDequeueUnitTest, poll_timeouted_is_not_block_when_not_empty) { size_t capacity = 1; int timeout = 11; PIBlockingDequeuePrepare dequeue(capacity); dequeue.offer(111); dequeue.poll(timeout, -1); EXPECT_TRUE(dequeue.getCondVarAdd()->isWaitForCalled); ASSERT_TRUE(dequeue.getCondVarAdd()->isTrueCondition); } TEST(BlockingDequeueUnitTest, poll_timeouted_is_offer_value_when_not_empty) { size_t capacity = 1; int timeout = 11; PIBlockingDequeuePrepare dequeue(capacity); dequeue.offer(111); ASSERT_EQ(dequeue.poll(timeout, -1), 111); } TEST(BlockingDequeueUnitTest, poll_timeouted_is_last) { size_t capacity = 10; PIBlockingDequeuePrepare dequeue(capacity); dequeue.offer(111); dequeue.offer(222); ASSERT_EQ(dequeue.poll(10, -1), 111); ASSERT_EQ(dequeue.poll(10, -1), 222); } TEST(BlockingDequeueUnitTest, capacity_is_eq_constructor_capacity) { size_t capacity = 10; PIBlockingDequeuePrepare dequeue(capacity); ASSERT_EQ(dequeue.capacity(), capacity); } TEST(BlockingDequeueUnitTest, remainingCapacity_is_dif_of_capacity_and_size) { size_t capacity = 2; PIBlockingDequeuePrepare dequeue(capacity); ASSERT_EQ(dequeue.remainingCapacity(), capacity); dequeue.offer(111); ASSERT_EQ(dequeue.remainingCapacity(), capacity - 1); } TEST(BlockingDequeueUnitTest, remainingCapacity_is_zero_when_capacity_reach) { size_t capacity = 1; PIBlockingDequeuePrepare dequeue(capacity); dequeue.offer(111); dequeue.offer(111); ASSERT_EQ(dequeue.remainingCapacity(), 0); } TEST(BlockingDequeueUnitTest, size_is_eq_to_num_of_elements) { size_t capacity = 1; PIBlockingDequeuePrepare dequeue(capacity); ASSERT_EQ(dequeue.size(), 0); dequeue.offer(111); ASSERT_EQ(dequeue.size(), 1); } TEST(BlockingDequeueUnitTest, size_is_eq_to_capacity_when_capacity_reach) { size_t capacity = 1; PIBlockingDequeuePrepare dequeue(capacity); dequeue.offer(111); dequeue.offer(111); ASSERT_EQ(dequeue.size(), capacity); } TEST(BlockingDequeueUnitTest, drainTo_is_elements_moved) { size_t capacity = 10; std::deque refDeque; for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10); PIBlockingDequeuePrepare blockingDequeue(refDeque); PIBlockingDequeuePrepare::QueueType deque; blockingDequeue.drainTo(deque); ASSERT_EQ(blockingDequeue.size(), 0); // FIXME // ASSERT_TRUE(deque == refDeque); } TEST(BlockingDequeueUnitTest, drainTo_is_ret_eq_to_size_when_all_moved) { size_t capacity = 10; std::deque refDeque; for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10); PIBlockingDequeuePrepare blockingDequeue(refDeque); PIBlockingDequeuePrepare::QueueType deque; ASSERT_EQ(blockingDequeue.drainTo(deque), refDeque.size()); } TEST(BlockingDequeueUnitTest, drainTo_is_ret_eq_to_maxCount) { size_t capacity = 10; std::deque refDeque; for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10); PIBlockingDequeuePrepare blockingDequeue(refDeque); PIBlockingDequeuePrepare::QueueType deque; ASSERT_EQ(blockingDequeue.drainTo(deque, refDeque.size() - 1), refDeque.size() - 1); }