| Index: cc/scheduler/begin_frame_observer_map_unittest.cc
|
| diff --git a/cc/scheduler/begin_frame_observer_map_unittest.cc b/cc/scheduler/begin_frame_observer_map_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..45a4c9cb564c7703a99e27315efe15ecda6e8e1d
|
| --- /dev/null
|
| +++ b/cc/scheduler/begin_frame_observer_map_unittest.cc
|
| @@ -0,0 +1,431 @@
|
| +// Copyright 2011 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 "cc/scheduler/begin_frame_observer_map.h"
|
| +
|
| +#include <algorithm>
|
| +
|
| +#include "base/basictypes.h"
|
| +#include "base/gtest_prod_util.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +// We use a macro here so that we get good line number information from gtest.
|
| +#define EXPECT_EMPTY(obmap) \
|
| + EXPECT_FALSE(obmap.HasObservers()); \
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) \
|
| + NOTREACHED(); \
|
| + for (auto it = obmap.cbegin(); it != obmap.cend(); it++) \
|
| + NOTREACHED(); \
|
| + EXPECT_EQ(GetConstIterators(&obmap), 0U); \
|
| + EXPECT_EQ(GetIterators(&obmap), 0U);
|
| +
|
| +namespace cc {
|
| +
|
| +// This has to be in the same name space as BeginFrameObserverMap so it is
|
| +// correctly
|
| +// friended.
|
| +class BeginFrameObserverMapTest : public ::testing::Test {
|
| + public:
|
| + template <class ObserverType, class ObserverDataType>
|
| + size_t GetIterators(
|
| + BeginFrameObserverMap<ObserverType, ObserverDataType>* obmap) {
|
| + return obmap->iterators_;
|
| + }
|
| +
|
| + template <class ObserverType, class ObserverDataType>
|
| + size_t GetConstIterators(
|
| + BeginFrameObserverMap<ObserverType, ObserverDataType>* obmap) {
|
| + return obmap->const_iterators_;
|
| + }
|
| +};
|
| +
|
| +namespace {
|
| +
|
| +class TestObserver {
|
| + public:
|
| + int observe_;
|
| +
|
| + TestObserver() : observe_(0) {}
|
| + void Observe() { observe_++; }
|
| + int GetObserve() const { return observe_; }
|
| +};
|
| +
|
| +struct TestObserverData {
|
| + TestObserverData() : data(0) {}
|
| +
|
| + size_t data;
|
| +};
|
| +
|
| +TEST_F(BeginFrameObserverMapTest, Types) {
|
| + ::testing::StaticAssertTypeEq<
|
| + BeginFrameObserverMap<TestObserver,
|
| + TestObserverData>::const_iterator::value_type,
|
| + std::pair<TestObserver* const, TestObserverData*>>();
|
| +}
|
| +
|
| +TEST_F(BeginFrameObserverMapTest, MapInitiallyEmpty) {
|
| + BeginFrameObserverMap<TestObserver, TestObserverData> obmap;
|
| + EXPECT_EMPTY(obmap);
|
| +}
|
| +
|
| +TEST_F(BeginFrameObserverMapTest, SingleObserver) {
|
| + size_t data_value1 = __LINE__;
|
| + size_t data_value2 = __LINE__;
|
| + BeginFrameObserverMap<TestObserver, TestObserverData> obmap;
|
| + TestObserver obs1;
|
| +
|
| + // Observer not added yet
|
| + EXPECT_FALSE(obmap.HasObserver(&obs1));
|
| + EXPECT_EQ(obmap[&obs1], nullptr);
|
| +
|
| + // Add the observer
|
| + obmap.AddObserver(&obs1);
|
| + EXPECT_TRUE(obmap.HasObserver(&obs1));
|
| + EXPECT_TRUE(obmap.HasObservers());
|
| + EXPECT_EQ(obmap[&obs1]->data, 0U);
|
| +
|
| + // Normal iterator
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) {
|
| + EXPECT_EQ(GetIterators(&obmap), 1U);
|
| + EXPECT_EQ(GetConstIterators(&obmap), 0U);
|
| + EXPECT_EQ(&obs1, it->first);
|
| + it->second->data = data_value1;
|
| + }
|
| + EXPECT_EQ(GetIterators(&obmap), 0U);
|
| + EXPECT_EQ(obmap[&obs1]->data, data_value1);
|
| + // const iterator
|
| + for (auto it = obmap.cbegin(); it != obmap.cend(); it++) {
|
| + EXPECT_EQ(GetIterators(&obmap), 0U);
|
| + EXPECT_EQ(GetConstIterators(&obmap), 1U);
|
| + EXPECT_EQ(&obs1, it->first);
|
| + EXPECT_EQ(it->second->data, data_value1);
|
| + }
|
| + EXPECT_EQ(GetConstIterators(&obmap), 0U);
|
| + // Nested iterators
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) {
|
| + for (auto jt = obmap.begin(); jt != obmap.end(); jt++) {
|
| + EXPECT_EQ(GetIterators(&obmap), 2U);
|
| + EXPECT_EQ(GetConstIterators(&obmap), 0U);
|
| + EXPECT_EQ(&obs1, it->first);
|
| + it->second->data = data_value2;
|
| + }
|
| + EXPECT_EQ(GetIterators(&obmap), 1U);
|
| + }
|
| + EXPECT_EQ(GetIterators(&obmap), 0U);
|
| + EXPECT_EQ(obmap[&obs1]->data, data_value2);
|
| + // Nested const iterator
|
| + for (auto it = obmap.cbegin(); it != obmap.cend(); it++) {
|
| + for (auto jt = obmap.cbegin(); jt != obmap.cend(); jt++) {
|
| + EXPECT_EQ(GetIterators(&obmap), 0U);
|
| + EXPECT_EQ(GetConstIterators(&obmap), 2U);
|
| + EXPECT_EQ(&obs1, jt->first);
|
| + EXPECT_EQ(jt->second->data, data_value2);
|
| + }
|
| + EXPECT_EQ(GetConstIterators(&obmap), 1U);
|
| + }
|
| + EXPECT_EQ(GetConstIterators(&obmap), 0U);
|
| +
|
| + // Remove the observer
|
| + obmap.RemoveObserver(&obs1);
|
| + EXPECT_EMPTY(obmap);
|
| +}
|
| +
|
| +TEST_F(BeginFrameObserverMapTest, TwoObservers) {
|
| + size_t data_value1 = __LINE__;
|
| + size_t data_value2 = __LINE__;
|
| + size_t data_value3 = __LINE__;
|
| + BeginFrameObserverMap<TestObserver, TestObserverData> obmap;
|
| + TestObserver obs1;
|
| + TestObserver obs2;
|
| +
|
| + obmap.AddObserver(&obs1);
|
| + EXPECT_TRUE(obmap.HasObserver(&obs1));
|
| + obmap.AddObserver(&obs2);
|
| + EXPECT_TRUE(obmap.HasObserver(&obs2));
|
| +
|
| + EXPECT_TRUE(obmap.HasObservers());
|
| + // Normal iterator
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) {
|
| + EXPECT_EQ(GetIterators(&obmap), 1U);
|
| + EXPECT_EQ(GetConstIterators(&obmap), 0U);
|
| + EXPECT_EQ(it->second->data, 0U);
|
| + it->second->data = data_value1;
|
| + }
|
| + EXPECT_EQ(GetIterators(&obmap), 0U);
|
| + // const iterator
|
| + for (auto it = obmap.cbegin(); it != obmap.cend(); it++) {
|
| + EXPECT_EQ(GetIterators(&obmap), 0U);
|
| + EXPECT_EQ(GetConstIterators(&obmap), 1U);
|
| + EXPECT_EQ(it->second->data, data_value1);
|
| + }
|
| + EXPECT_EQ(GetConstIterators(&obmap), 0U);
|
| + // operator[]
|
| + EXPECT_EQ(obmap[&obs1]->data, data_value1);
|
| + EXPECT_EQ(obmap[&obs2]->data, data_value1);
|
| +
|
| + // Nested iterators
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) {
|
| + for (auto jt = obmap.begin(); jt != obmap.end(); jt++) {
|
| + EXPECT_EQ(GetIterators(&obmap), 2U);
|
| + EXPECT_EQ(GetConstIterators(&obmap), 0U);
|
| + it->second->data = data_value2;
|
| + }
|
| + EXPECT_EQ(GetIterators(&obmap), 1U);
|
| + }
|
| + EXPECT_EQ(GetIterators(&obmap), 0U);
|
| + // Nested const iterator
|
| + for (auto it = obmap.cbegin(); it != obmap.cend(); it++) {
|
| + for (auto jt = obmap.cbegin(); jt != obmap.cend(); jt++) {
|
| + EXPECT_EQ(GetIterators(&obmap), 0U);
|
| + EXPECT_EQ(GetConstIterators(&obmap), 2U);
|
| + EXPECT_EQ(jt->second->data, data_value2);
|
| + }
|
| + EXPECT_EQ(GetConstIterators(&obmap), 1U);
|
| + }
|
| + EXPECT_EQ(GetConstIterators(&obmap), 0U);
|
| +
|
| + // Remove a single observer
|
| + obmap.RemoveObserver(&obs2);
|
| +
|
| + // Repeat the above
|
| + EXPECT_TRUE(obmap.HasObservers());
|
| + // Normal iterator
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) {
|
| + EXPECT_EQ(it->second->data, data_value2);
|
| + it->second->data = data_value3;
|
| + }
|
| + // const iterator
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) {
|
| + EXPECT_EQ(it->second->data, data_value3);
|
| + }
|
| + // operator[]
|
| + EXPECT_EQ(obmap[&obs1]->data, data_value3);
|
| + EXPECT_EQ(obmap[&obs2], nullptr);
|
| +
|
| + // Remove the other observer
|
| + obmap.RemoveObserver(&obs1);
|
| + EXPECT_EMPTY(obmap);
|
| +}
|
| +
|
| +TEST_F(BeginFrameObserverMapTest, AddWhileIterating) {
|
| + size_t data_value1 = __LINE__;
|
| + BeginFrameObserverMap<TestObserver, TestObserverData> obmap;
|
| + TestObserver obs1;
|
| + TestObserver obs2;
|
| + TestObserver obs3;
|
| + obmap.AddObserver(&obs1);
|
| + obmap.AddObserver(&obs3);
|
| +
|
| + obmap[&obs1]->data = data_value1;
|
| + obmap[&obs3]->data = data_value1;
|
| +
|
| + int i = 1;
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++, i++) {
|
| + // Calling add twice while iterating should be safe
|
| + obmap.AddObserver(&obs2);
|
| + // Should be able to access the data right after adding.
|
| + EXPECT_TRUE(obmap.HasObserver(&obs2));
|
| + obmap[&obs2]->data = i;
|
| + }
|
| + EXPECT_TRUE(obmap.HasObservers());
|
| +
|
| + EXPECT_EQ(obmap[&obs1]->data, data_value1);
|
| + EXPECT_EQ(obmap[&obs2]->data, 2U);
|
| + EXPECT_EQ(obmap[&obs3]->data, data_value1);
|
| +}
|
| +
|
| +TEST_F(BeginFrameObserverMapTest, RemoveOneWhileIterating) {
|
| + size_t data_value1 = __LINE__;
|
| + BeginFrameObserverMap<TestObserver, TestObserverData> obmap;
|
| + TestObserver obs1;
|
| + TestObserver obs2;
|
| + TestObserver obs3;
|
| + obmap.AddObserver(&obs1);
|
| + obmap.AddObserver(&obs2);
|
| + obmap.AddObserver(&obs3);
|
| +
|
| + obmap[&obs1]->data = data_value1;
|
| + obmap[&obs2]->data = data_value1;
|
| + obmap[&obs3]->data = data_value1;
|
| +
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) {
|
| + obmap.RemoveObserver(&obs2);
|
| + // Observer doesn't go away until the iteration is finished...
|
| + EXPECT_TRUE(obmap.HasObserver(&obs2));
|
| + }
|
| + EXPECT_FALSE(obmap.HasObserver(&obs2));
|
| + EXPECT_TRUE(obmap.HasObservers());
|
| +
|
| + EXPECT_EQ(obmap[&obs1]->data, data_value1);
|
| + EXPECT_EQ(obmap[&obs2], nullptr);
|
| + EXPECT_EQ(obmap[&obs3]->data, data_value1);
|
| +}
|
| +
|
| +TEST_F(BeginFrameObserverMapTest, NestedRemoveOneWhileIterating) {
|
| + size_t data_value1 = __LINE__;
|
| + BeginFrameObserverMap<TestObserver, TestObserverData> obmap;
|
| + TestObserver obs1;
|
| + TestObserver obs2;
|
| + TestObserver obs3;
|
| + obmap.AddObserver(&obs1);
|
| + obmap.AddObserver(&obs2);
|
| + obmap.AddObserver(&obs3);
|
| +
|
| + obmap[&obs1]->data = data_value1;
|
| + obmap[&obs2]->data = data_value1;
|
| + obmap[&obs3]->data = data_value1;
|
| +
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) {
|
| + for (auto jt = obmap.begin(); jt != obmap.end(); jt++) {
|
| + obmap.RemoveObserver(&obs2);
|
| + }
|
| + }
|
| + EXPECT_TRUE(obmap.HasObservers());
|
| +
|
| + EXPECT_EQ(obmap[&obs1]->data, data_value1);
|
| + EXPECT_EQ(obmap[&obs2], nullptr);
|
| + EXPECT_EQ(obmap[&obs3]->data, data_value1);
|
| +}
|
| +
|
| +TEST_F(BeginFrameObserverMapTest, RemoveAllWhileIterating) {
|
| + BeginFrameObserverMap<TestObserver, TestObserverData> obmap;
|
| + TestObserver obs1;
|
| + TestObserver obs2;
|
| + TestObserver obs3;
|
| + obmap.AddObserver(&obs1);
|
| + obmap.AddObserver(&obs2);
|
| +
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) {
|
| + obmap.RemoveObserver(it->first);
|
| + }
|
| + EXPECT_EMPTY(obmap);
|
| +}
|
| +
|
| +TEST_F(BeginFrameObserverMapTest, NestedRemoveAllWhileIterating) {
|
| + BeginFrameObserverMap<TestObserver, TestObserverData> obmap;
|
| + TestObserver obs1;
|
| + TestObserver obs2;
|
| + TestObserver obs3;
|
| + obmap.AddObserver(&obs1);
|
| + obmap.AddObserver(&obs2);
|
| +
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) {
|
| + for (auto jt = obmap.begin(); jt != obmap.end(); jt++) {
|
| + obmap.RemoveObserver(jt->first);
|
| + }
|
| + }
|
| + EXPECT_EMPTY(obmap);
|
| +}
|
| +
|
| +TEST_F(BeginFrameObserverMapTest, AttemptToRemoveWhileConstIterating) {
|
| + BeginFrameObserverMap<TestObserver, TestObserverData> obmap;
|
| + TestObserver obs1;
|
| + TestObserver obs2;
|
| + obmap.AddObserver(&obs1);
|
| + obmap.AddObserver(&obs2);
|
| +
|
| + EXPECT_DEATH({
|
| + for (auto it = obmap.cbegin(); it != obmap.cend(); it++) {
|
| + obmap.RemoveObserver(const_cast<TestObserver*>(it->first));
|
| + }
|
| + }, "");
|
| +
|
| + const BeginFrameObserverMap<TestObserver, TestObserverData>* cobmap = &obmap;
|
| + EXPECT_DEATH({
|
| + for (auto it = cobmap->begin(); it != cobmap->end(); it++) {
|
| + obmap.RemoveObserver(const_cast<TestObserver*>(it->first));
|
| + }
|
| + }, "");
|
| +}
|
| +
|
| +TEST_F(BeginFrameObserverMapTest, AttemptToAddWhileConstIterating) {
|
| + BeginFrameObserverMap<TestObserver, TestObserverData> obmap;
|
| + TestObserver obs1;
|
| + TestObserver obs2;
|
| + TestObserver obs3;
|
| + obmap.AddObserver(&obs1);
|
| + obmap.AddObserver(&obs2);
|
| +
|
| + EXPECT_DEATH({
|
| + for (auto it = obmap.cbegin(); it != obmap.cend(); it++) {
|
| + obmap.AddObserver(&obs3);
|
| + }
|
| + }, "");
|
| +
|
| + const BeginFrameObserverMap<TestObserver, TestObserverData>* cobmap = &obmap;
|
| + EXPECT_DEATH({
|
| + for (auto it = cobmap->begin(); it != cobmap->end(); it++) {
|
| + obmap.AddObserver(&obs3);
|
| + }
|
| + }, "");
|
| +}
|
| +
|
| +struct TestObserverOwner {
|
| + TestObserverOwner() : ob1(), ob2(), obmap() {}
|
| +
|
| + TestObserver ob1;
|
| + TestObserver ob2;
|
| + BeginFrameObserverMap<TestObserver, TestObserverData> obmap;
|
| +
|
| + void Notify() {
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) {
|
| + it->first->Observe();
|
| + }
|
| + }
|
| +
|
| + int LargestObserver() const {
|
| + int largest = 0;
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) {
|
| + largest = std::max(largest, it->first->GetObserve());
|
| + }
|
| + return largest;
|
| + }
|
| + size_t LargestData() const {
|
| + size_t largest1 = 0;
|
| + size_t largest2 = 0;
|
| + for (auto it = obmap.begin(); it != obmap.end(); it++) {
|
| + largest1 = std::max(largest1, it->second->data);
|
| + largest2 = std::max(largest2, obmap[it->first]->data);
|
| + }
|
| + DCHECK_EQ(largest1, largest2);
|
| + return largest1;
|
| + }
|
| +};
|
| +
|
| +TEST_F(BeginFrameObserverMapTest, ObserverOwner) {
|
| + TestObserverOwner owner;
|
| +
|
| + owner.Notify();
|
| + EXPECT_EQ(owner.LargestObserver(), 0);
|
| + EXPECT_EQ(owner.LargestData(), 0U);
|
| +
|
| + owner.obmap.AddObserver(&owner.ob1);
|
| + owner.Notify();
|
| + EXPECT_EQ(owner.LargestObserver(), 1);
|
| + EXPECT_EQ(owner.LargestData(), 0U);
|
| +
|
| + owner.obmap[&owner.ob1]->data = 2;
|
| + EXPECT_EQ(owner.LargestObserver(), 1);
|
| + EXPECT_EQ(owner.LargestData(), 2U);
|
| +
|
| + owner.obmap.AddObserver(&owner.ob2);
|
| + EXPECT_EQ(owner.LargestObserver(), 1);
|
| + EXPECT_EQ(owner.LargestData(), 2U);
|
| + owner.Notify();
|
| + owner.Notify();
|
| + EXPECT_EQ(owner.LargestObserver(), 3);
|
| + EXPECT_EQ(owner.LargestData(), 2U);
|
| +
|
| + owner.obmap[&owner.ob2]->data = 5;
|
| + EXPECT_EQ(owner.LargestObserver(), 3);
|
| + EXPECT_EQ(owner.LargestData(), 5U);
|
| +
|
| + owner.obmap.RemoveObserver(&owner.ob1);
|
| + EXPECT_EQ(owner.LargestObserver(), 2);
|
| + EXPECT_EQ(owner.LargestData(), 5U);
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace cc
|
|
|