| Index: mojo/public/cpp/bindings/tests/pointer_deque_unittest.cc
|
| diff --git a/mojo/public/cpp/bindings/tests/pointer_deque_unittest.cc b/mojo/public/cpp/bindings/tests/pointer_deque_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f8eb98a52703e24eb1476a89458f2589f7395854
|
| --- /dev/null
|
| +++ b/mojo/public/cpp/bindings/tests/pointer_deque_unittest.cc
|
| @@ -0,0 +1,322 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "mojo/public/cpp/bindings/lib/pointer_deque.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace mojo {
|
| +namespace internal {
|
| +
|
| +template <typename T, bool owned>
|
| +class PointerDequeAccessor {
|
| + public:
|
| + explicit PointerDequeAccessor(PointerDeque<T, owned>* deque)
|
| + : deque_(deque) {}
|
| +
|
| + size_t front() { return deque_->front_; }
|
| +
|
| + size_t back() { return deque_->back_; }
|
| +
|
| + std::vector<typename PointerDeque<T, owned>::ElementType>& buffer() {
|
| + return deque_->buffer_;
|
| + }
|
| +
|
| + private:
|
| + PointerDeque<T, owned>* deque_;
|
| +};
|
| +
|
| +} // namespace internal
|
| +
|
| +namespace test {
|
| +namespace {
|
| +
|
| +using mojo::internal::PointerDeque;
|
| +using mojo::internal::PointerDequeAccessor;
|
| +
|
| +struct Element {
|
| + explicit Element(int32_t in_value) : value(in_value) {}
|
| + int32_t value = 0;
|
| +};
|
| +
|
| +struct RawPointerCase {
|
| + static constexpr bool kOwned = false;
|
| +
|
| + struct ElementWrapper {
|
| + explicit ElementWrapper(int32_t value) : element_(value) {}
|
| + Element* ToPointer() { return &element_; }
|
| +
|
| + private:
|
| + Element element_;
|
| + DISALLOW_COPY_AND_ASSIGN(ElementWrapper);
|
| + };
|
| +
|
| + using Deque = PointerDeque<Element, kOwned>;
|
| + using Accessor = PointerDequeAccessor<Element, kOwned>;
|
| +};
|
| +
|
| +struct OwnedPointerCase {
|
| + static constexpr bool kOwned = true;
|
| +
|
| + struct ElementWrapper {
|
| + explicit ElementWrapper(int32_t value)
|
| + : element_(base::MakeUnique<Element>(value)) {}
|
| + std::unique_ptr<Element> ToPointer() { return std::move(element_); }
|
| +
|
| + private:
|
| + std::unique_ptr<Element> element_;
|
| + DISALLOW_COPY_AND_ASSIGN(ElementWrapper);
|
| + };
|
| +
|
| + using Deque = PointerDeque<Element, kOwned>;
|
| + using Accessor = PointerDequeAccessor<Element, kOwned>;
|
| +};
|
| +
|
| +template <typename T>
|
| +class PointerDequeTest : public ::testing::Test {
|
| + public:
|
| +};
|
| +
|
| +using CaseList = ::testing::Types<RawPointerCase, OwnedPointerCase>;
|
| +
|
| +TYPED_TEST_CASE(PointerDequeTest, CaseList);
|
| +
|
| +TYPED_TEST(PointerDequeTest, PushPop) {
|
| + using ElementWrapper = typename TypeParam::ElementWrapper;
|
| +
|
| + typename TypeParam::Deque deque(2);
|
| + EXPECT_TRUE(deque.empty());
|
| +
|
| + ElementWrapper e0(123);
|
| + deque.push_front(e0.ToPointer());
|
| + EXPECT_FALSE(deque.empty());
|
| +
|
| + EXPECT_EQ(123, deque.front()->value);
|
| + EXPECT_EQ(123, deque.back()->value);
|
| +
|
| + ElementWrapper e1(456);
|
| + deque.push_back(e1.ToPointer());
|
| +
|
| + EXPECT_EQ(123, deque.front()->value);
|
| + EXPECT_EQ(456, deque.back()->value);
|
| +
|
| + ElementWrapper e2(789);
|
| + deque.push_front(e2.ToPointer());
|
| +
|
| + EXPECT_EQ(789, deque.front()->value);
|
| + EXPECT_EQ(456, deque.back()->value);
|
| +
|
| + deque.pop_back();
|
| + EXPECT_EQ(789, deque.front()->value);
|
| + EXPECT_EQ(123, deque.back()->value);
|
| +
|
| + deque.pop_front();
|
| + EXPECT_EQ(123, deque.front()->value);
|
| + EXPECT_EQ(123, deque.back()->value);
|
| +
|
| + deque.pop_front();
|
| + EXPECT_TRUE(deque.empty());
|
| +}
|
| +
|
| +TYPED_TEST(PointerDequeTest, Clear) {
|
| + using ElementWrapper = typename TypeParam::ElementWrapper;
|
| +
|
| + typename TypeParam::Deque deque;
|
| + EXPECT_TRUE(deque.empty());
|
| +
|
| + deque.clear();
|
| + EXPECT_TRUE(deque.empty());
|
| +
|
| + ElementWrapper e0(123);
|
| + deque.push_front(e0.ToPointer());
|
| + ElementWrapper e1(456);
|
| + deque.push_back(e1.ToPointer());
|
| + ElementWrapper e2(789);
|
| + deque.push_front(e2.ToPointer());
|
| +
|
| + deque.clear();
|
| +
|
| + EXPECT_TRUE(deque.empty());
|
| +}
|
| +
|
| +TYPED_TEST(PointerDequeTest, Move) {
|
| + using ElementWrapper = typename TypeParam::ElementWrapper;
|
| +
|
| + {
|
| + typename TypeParam::Deque deque;
|
| + ElementWrapper e0(123);
|
| + deque.push_back(e0.ToPointer());
|
| + ElementWrapper e1(456);
|
| + deque.push_back(e1.ToPointer());
|
| + ElementWrapper e2(789);
|
| + deque.push_back(e2.ToPointer());
|
| +
|
| + typename TypeParam::Deque deque2(std::move(deque));
|
| +
|
| + EXPECT_TRUE(deque.empty());
|
| +
|
| + EXPECT_EQ(123, deque2.front()->value);
|
| + deque2.pop_front();
|
| + EXPECT_EQ(456, deque2.front()->value);
|
| + deque2.pop_front();
|
| + EXPECT_EQ(789, deque2.front()->value);
|
| +
|
| + // |deque| is still in valid state and could be reused.
|
| + ElementWrapper e4(321);
|
| + deque.push_back(e4.ToPointer());
|
| + EXPECT_EQ(321, deque.front()->value);
|
| + EXPECT_EQ(321, deque.back()->value);
|
| + }
|
| +
|
| + {
|
| + typename TypeParam::Deque deque;
|
| + ElementWrapper e0(123);
|
| + deque.push_back(e0.ToPointer());
|
| + ElementWrapper e1(456);
|
| + deque.push_back(e1.ToPointer());
|
| + ElementWrapper e2(789);
|
| + deque.push_back(e2.ToPointer());
|
| +
|
| + typename TypeParam::Deque deque2;
|
| + deque2 = std::move(deque);
|
| +
|
| + EXPECT_TRUE(deque.empty());
|
| +
|
| + EXPECT_EQ(123, deque2.front()->value);
|
| + deque2.pop_front();
|
| + EXPECT_EQ(456, deque2.front()->value);
|
| + deque2.pop_front();
|
| + EXPECT_EQ(789, deque2.front()->value);
|
| +
|
| + // |deque| is still in valid state and could be reused.
|
| + ElementWrapper e4(321);
|
| + deque.push_back(e4.ToPointer());
|
| + EXPECT_EQ(321, deque.front()->value);
|
| + EXPECT_EQ(321, deque.back()->value);
|
| + }
|
| +}
|
| +
|
| +// Constructs a deque with a fully occupied ring buffer.
|
| +// |front_index| is the position of the front element in the ring buffer.
|
| +// |values| stores the values from front to back.
|
| +template <typename Deque, typename ElementWrapper>
|
| +void ConstructFullDeque(
|
| + const std::vector<int32_t>& values,
|
| + size_t front_index,
|
| + Deque* deque,
|
| + std::vector<std::unique_ptr<ElementWrapper>>* wrappers) {
|
| + DCHECK_LT(front_index, values.size());
|
| + *deque = Deque(values.size());
|
| +
|
| + // Push some temp elements to make sure the desired front element starts at
|
| + // |front_index|.
|
| + std::vector<std::unique_ptr<ElementWrapper>> temp_storage;
|
| + for (size_t i = 0; i < front_index; ++i) {
|
| + temp_storage.emplace_back(base::MakeUnique<ElementWrapper>(0));
|
| + deque->push_back(temp_storage.back()->ToPointer());
|
| + }
|
| +
|
| + wrappers->emplace_back(base::MakeUnique<ElementWrapper>(values[0]));
|
| + deque->push_back(wrappers->back()->ToPointer());
|
| +
|
| + for (size_t i = 0; i < front_index; ++i)
|
| + deque->pop_front();
|
| +
|
| + for (size_t i = 1; i < values.size(); ++i) {
|
| + wrappers->emplace_back(base::MakeUnique<ElementWrapper>(values[i]));
|
| + deque->push_back(wrappers->back()->ToPointer());
|
| + }
|
| +}
|
| +
|
| +template <typename Accessor, typename Deque>
|
| +void VerifyDequeInternalState(Deque* deque,
|
| + size_t expected_front,
|
| + size_t expected_back,
|
| + const std::vector<int32_t>& expected_values,
|
| + size_t expected_ring_buffer_size) {
|
| + Accessor accessor(deque);
|
| +
|
| + EXPECT_EQ(expected_front, accessor.front());
|
| + EXPECT_EQ(expected_back, accessor.back());
|
| + EXPECT_EQ(expected_ring_buffer_size, accessor.buffer().size());
|
| +
|
| + size_t index = expected_front;
|
| + for (size_t i = 0; i < expected_values.size(); ++i) {
|
| + EXPECT_EQ(expected_values[i], accessor.buffer()[index]->value);
|
| + index++;
|
| + if (index == accessor.buffer().size())
|
| + index = 0;
|
| + }
|
| +}
|
| +
|
| +TYPED_TEST(PointerDequeTest, ExpandWhiteBox) {
|
| + using Deque = typename TypeParam::Deque;
|
| + using ElementWrapper = typename TypeParam::ElementWrapper;
|
| + using Accessor = typename TypeParam::Accessor;
|
| +
|
| + // Test ConstructFullDeque() and VerifyDequeInternalState().
|
| + {
|
| + Deque deque;
|
| + std::vector<std::unique_ptr<ElementWrapper>> wrappers;
|
| + ConstructFullDeque({1, 2, 3}, 0, &deque, &wrappers);
|
| + VerifyDequeInternalState<Accessor>(&deque, 0, 2, {1, 2, 3}, 3);
|
| +
|
| + Deque deque1;
|
| + std::vector<std::unique_ptr<ElementWrapper>> wrappers1;
|
| + ConstructFullDeque({1, 2, 3}, 1, &deque1, &wrappers1);
|
| + VerifyDequeInternalState<Accessor>(&deque1, 1, 0, {1, 2, 3}, 3);
|
| + }
|
| +
|
| + // Test that ring buffer [1(front), 2, 3(back)] becomes
|
| + // [1(front), 2, 3, 4(back), _, _] after push_back(4).
|
| + {
|
| + Deque deque;
|
| + std::vector<std::unique_ptr<ElementWrapper>> wrappers;
|
| + ConstructFullDeque({1, 2, 3}, 0, &deque, &wrappers);
|
| +
|
| + ElementWrapper e(4);
|
| + deque.push_back(e.ToPointer());
|
| + VerifyDequeInternalState<Accessor>(&deque, 0, 3, {1, 2, 3, 4}, 6);
|
| + }
|
| +
|
| + // Test that ring buffer [1(front), 2, 3(back)] becomes
|
| + // [1, 2, 3(back), _, _, 4(front)] after push_front(4).
|
| + {
|
| + Deque deque;
|
| + std::vector<std::unique_ptr<ElementWrapper>> wrappers;
|
| + ConstructFullDeque({1, 2, 3}, 0, &deque, &wrappers);
|
| +
|
| + ElementWrapper e(4);
|
| + deque.push_front(e.ToPointer());
|
| + VerifyDequeInternalState<Accessor>(&deque, 5, 2, {4, 1, 2, 3}, 6);
|
| + }
|
| +
|
| + // Test that ring buffer [3(back), 1(front), 2] becomes
|
| + // [_, 1(front), 2, 3, 4(back), _] after push_back(4).
|
| + {
|
| + Deque deque;
|
| + std::vector<std::unique_ptr<ElementWrapper>> wrappers;
|
| + ConstructFullDeque({1, 2, 3}, 1, &deque, &wrappers);
|
| +
|
| + ElementWrapper e(4);
|
| + deque.push_back(e.ToPointer());
|
| + VerifyDequeInternalState<Accessor>(&deque, 1, 4, {1, 2, 3, 4}, 6);
|
| + }
|
| +
|
| + // Test that ring buffer [2, 3(back), 1(front)] becomes
|
| + // [2, 3, 4(back), _, _, 1(front)] after push_back(4).
|
| + {
|
| + Deque deque;
|
| + std::vector<std::unique_ptr<ElementWrapper>> wrappers;
|
| + ConstructFullDeque({1, 2, 3}, 2, &deque, &wrappers);
|
| +
|
| + ElementWrapper e(4);
|
| + deque.push_back(e.ToPointer());
|
| + VerifyDequeInternalState<Accessor>(&deque, 5, 2, {1, 2, 3, 4}, 6);
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace test
|
| +} // namespace mojo
|
|
|