OLD | NEW |
(Empty) | |
| 1 // Copyright 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "cc/scheduler/begin_frame_observer_map.h" |
| 6 |
| 7 #include <algorithm> |
| 8 |
| 9 #include "base/basictypes.h" |
| 10 #include "base/gtest_prod_util.h" |
| 11 #include "testing/gmock/include/gmock/gmock.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 |
| 14 // We use a macro here so that we get good line number information from gtest. |
| 15 #define EXPECT_EMPTY(obmap) \ |
| 16 EXPECT_FALSE(obmap.HasObservers()); \ |
| 17 for (auto it = obmap.begin(); it != obmap.end(); it++) \ |
| 18 NOTREACHED(); \ |
| 19 for (auto it = obmap.cbegin(); it != obmap.cend(); it++) \ |
| 20 NOTREACHED(); \ |
| 21 EXPECT_EQ(GetConstIterators(&obmap), 0U); \ |
| 22 EXPECT_EQ(GetIterators(&obmap), 0U); |
| 23 |
| 24 namespace cc { |
| 25 |
| 26 // This has to be in the same name space as BeginFrameObserverMap so it is |
| 27 // correctly |
| 28 // friended. |
| 29 class BeginFrameObserverMapTest : public ::testing::Test { |
| 30 public: |
| 31 template <class ObserverType, class ObserverDataType> |
| 32 size_t GetIterators( |
| 33 BeginFrameObserverMap<ObserverType, ObserverDataType>* obmap) { |
| 34 return obmap->iterators_; |
| 35 } |
| 36 |
| 37 template <class ObserverType, class ObserverDataType> |
| 38 size_t GetConstIterators( |
| 39 BeginFrameObserverMap<ObserverType, ObserverDataType>* obmap) { |
| 40 return obmap->const_iterators_; |
| 41 } |
| 42 }; |
| 43 |
| 44 namespace { |
| 45 |
| 46 class TestObserver { |
| 47 public: |
| 48 int observe_; |
| 49 |
| 50 TestObserver() : observe_(0) {} |
| 51 void Observe() { observe_++; } |
| 52 int GetObserve() const { return observe_; } |
| 53 }; |
| 54 |
| 55 struct TestObserverData { |
| 56 TestObserverData() : data(0) {} |
| 57 |
| 58 size_t data; |
| 59 }; |
| 60 |
| 61 TEST_F(BeginFrameObserverMapTest, Types) { |
| 62 ::testing::StaticAssertTypeEq< |
| 63 BeginFrameObserverMap<TestObserver, |
| 64 TestObserverData>::const_iterator::value_type, |
| 65 std::pair<TestObserver* const, TestObserverData*>>(); |
| 66 } |
| 67 |
| 68 TEST_F(BeginFrameObserverMapTest, MapInitiallyEmpty) { |
| 69 BeginFrameObserverMap<TestObserver, TestObserverData> obmap; |
| 70 EXPECT_EMPTY(obmap); |
| 71 } |
| 72 |
| 73 TEST_F(BeginFrameObserverMapTest, SingleObserver) { |
| 74 size_t data_value1 = __LINE__; |
| 75 size_t data_value2 = __LINE__; |
| 76 BeginFrameObserverMap<TestObserver, TestObserverData> obmap; |
| 77 TestObserver obs1; |
| 78 |
| 79 // Observer not added yet |
| 80 EXPECT_FALSE(obmap.HasObserver(&obs1)); |
| 81 EXPECT_EQ(obmap[&obs1], nullptr); |
| 82 |
| 83 // Add the observer |
| 84 obmap.AddObserver(&obs1); |
| 85 EXPECT_TRUE(obmap.HasObserver(&obs1)); |
| 86 EXPECT_TRUE(obmap.HasObservers()); |
| 87 EXPECT_EQ(obmap[&obs1]->data, 0U); |
| 88 |
| 89 // Normal iterator |
| 90 for (auto it = obmap.begin(); it != obmap.end(); it++) { |
| 91 EXPECT_EQ(GetIterators(&obmap), 1U); |
| 92 EXPECT_EQ(GetConstIterators(&obmap), 0U); |
| 93 EXPECT_EQ(&obs1, it->first); |
| 94 it->second->data = data_value1; |
| 95 } |
| 96 EXPECT_EQ(GetIterators(&obmap), 0U); |
| 97 EXPECT_EQ(obmap[&obs1]->data, data_value1); |
| 98 // const iterator |
| 99 for (auto it = obmap.cbegin(); it != obmap.cend(); it++) { |
| 100 EXPECT_EQ(GetIterators(&obmap), 0U); |
| 101 EXPECT_EQ(GetConstIterators(&obmap), 1U); |
| 102 EXPECT_EQ(&obs1, it->first); |
| 103 EXPECT_EQ(it->second->data, data_value1); |
| 104 } |
| 105 EXPECT_EQ(GetConstIterators(&obmap), 0U); |
| 106 // Nested iterators |
| 107 for (auto it = obmap.begin(); it != obmap.end(); it++) { |
| 108 for (auto jt = obmap.begin(); jt != obmap.end(); jt++) { |
| 109 EXPECT_EQ(GetIterators(&obmap), 2U); |
| 110 EXPECT_EQ(GetConstIterators(&obmap), 0U); |
| 111 EXPECT_EQ(&obs1, it->first); |
| 112 it->second->data = data_value2; |
| 113 } |
| 114 EXPECT_EQ(GetIterators(&obmap), 1U); |
| 115 } |
| 116 EXPECT_EQ(GetIterators(&obmap), 0U); |
| 117 EXPECT_EQ(obmap[&obs1]->data, data_value2); |
| 118 // Nested const iterator |
| 119 for (auto it = obmap.cbegin(); it != obmap.cend(); it++) { |
| 120 for (auto jt = obmap.cbegin(); jt != obmap.cend(); jt++) { |
| 121 EXPECT_EQ(GetIterators(&obmap), 0U); |
| 122 EXPECT_EQ(GetConstIterators(&obmap), 2U); |
| 123 EXPECT_EQ(&obs1, jt->first); |
| 124 EXPECT_EQ(jt->second->data, data_value2); |
| 125 } |
| 126 EXPECT_EQ(GetConstIterators(&obmap), 1U); |
| 127 } |
| 128 EXPECT_EQ(GetConstIterators(&obmap), 0U); |
| 129 |
| 130 // Remove the observer |
| 131 obmap.RemoveObserver(&obs1); |
| 132 EXPECT_EMPTY(obmap); |
| 133 } |
| 134 |
| 135 TEST_F(BeginFrameObserverMapTest, TwoObservers) { |
| 136 size_t data_value1 = __LINE__; |
| 137 size_t data_value2 = __LINE__; |
| 138 size_t data_value3 = __LINE__; |
| 139 BeginFrameObserverMap<TestObserver, TestObserverData> obmap; |
| 140 TestObserver obs1; |
| 141 TestObserver obs2; |
| 142 |
| 143 obmap.AddObserver(&obs1); |
| 144 EXPECT_TRUE(obmap.HasObserver(&obs1)); |
| 145 obmap.AddObserver(&obs2); |
| 146 EXPECT_TRUE(obmap.HasObserver(&obs2)); |
| 147 |
| 148 EXPECT_TRUE(obmap.HasObservers()); |
| 149 // Normal iterator |
| 150 for (auto it = obmap.begin(); it != obmap.end(); it++) { |
| 151 EXPECT_EQ(GetIterators(&obmap), 1U); |
| 152 EXPECT_EQ(GetConstIterators(&obmap), 0U); |
| 153 EXPECT_EQ(it->second->data, 0U); |
| 154 it->second->data = data_value1; |
| 155 } |
| 156 EXPECT_EQ(GetIterators(&obmap), 0U); |
| 157 // const iterator |
| 158 for (auto it = obmap.cbegin(); it != obmap.cend(); it++) { |
| 159 EXPECT_EQ(GetIterators(&obmap), 0U); |
| 160 EXPECT_EQ(GetConstIterators(&obmap), 1U); |
| 161 EXPECT_EQ(it->second->data, data_value1); |
| 162 } |
| 163 EXPECT_EQ(GetConstIterators(&obmap), 0U); |
| 164 // operator[] |
| 165 EXPECT_EQ(obmap[&obs1]->data, data_value1); |
| 166 EXPECT_EQ(obmap[&obs2]->data, data_value1); |
| 167 |
| 168 // Nested iterators |
| 169 for (auto it = obmap.begin(); it != obmap.end(); it++) { |
| 170 for (auto jt = obmap.begin(); jt != obmap.end(); jt++) { |
| 171 EXPECT_EQ(GetIterators(&obmap), 2U); |
| 172 EXPECT_EQ(GetConstIterators(&obmap), 0U); |
| 173 it->second->data = data_value2; |
| 174 } |
| 175 EXPECT_EQ(GetIterators(&obmap), 1U); |
| 176 } |
| 177 EXPECT_EQ(GetIterators(&obmap), 0U); |
| 178 // Nested const iterator |
| 179 for (auto it = obmap.cbegin(); it != obmap.cend(); it++) { |
| 180 for (auto jt = obmap.cbegin(); jt != obmap.cend(); jt++) { |
| 181 EXPECT_EQ(GetIterators(&obmap), 0U); |
| 182 EXPECT_EQ(GetConstIterators(&obmap), 2U); |
| 183 EXPECT_EQ(jt->second->data, data_value2); |
| 184 } |
| 185 EXPECT_EQ(GetConstIterators(&obmap), 1U); |
| 186 } |
| 187 EXPECT_EQ(GetConstIterators(&obmap), 0U); |
| 188 |
| 189 // Remove a single observer |
| 190 obmap.RemoveObserver(&obs2); |
| 191 |
| 192 // Repeat the above |
| 193 EXPECT_TRUE(obmap.HasObservers()); |
| 194 // Normal iterator |
| 195 for (auto it = obmap.begin(); it != obmap.end(); it++) { |
| 196 EXPECT_EQ(it->second->data, data_value2); |
| 197 it->second->data = data_value3; |
| 198 } |
| 199 // const iterator |
| 200 for (auto it = obmap.begin(); it != obmap.end(); it++) { |
| 201 EXPECT_EQ(it->second->data, data_value3); |
| 202 } |
| 203 // operator[] |
| 204 EXPECT_EQ(obmap[&obs1]->data, data_value3); |
| 205 EXPECT_EQ(obmap[&obs2], nullptr); |
| 206 |
| 207 // Remove the other observer |
| 208 obmap.RemoveObserver(&obs1); |
| 209 EXPECT_EMPTY(obmap); |
| 210 } |
| 211 |
| 212 TEST_F(BeginFrameObserverMapTest, AddWhileIterating) { |
| 213 size_t data_value1 = __LINE__; |
| 214 BeginFrameObserverMap<TestObserver, TestObserverData> obmap; |
| 215 TestObserver obs1; |
| 216 TestObserver obs2; |
| 217 TestObserver obs3; |
| 218 obmap.AddObserver(&obs1); |
| 219 obmap.AddObserver(&obs3); |
| 220 |
| 221 obmap[&obs1]->data = data_value1; |
| 222 obmap[&obs3]->data = data_value1; |
| 223 |
| 224 int i = 1; |
| 225 for (auto it = obmap.begin(); it != obmap.end(); it++, i++) { |
| 226 // Calling add twice while iterating should be safe |
| 227 obmap.AddObserver(&obs2); |
| 228 // Should be able to access the data right after adding. |
| 229 EXPECT_TRUE(obmap.HasObserver(&obs2)); |
| 230 obmap[&obs2]->data = i; |
| 231 } |
| 232 EXPECT_TRUE(obmap.HasObservers()); |
| 233 |
| 234 EXPECT_EQ(obmap[&obs1]->data, data_value1); |
| 235 EXPECT_EQ(obmap[&obs2]->data, 2U); |
| 236 EXPECT_EQ(obmap[&obs3]->data, data_value1); |
| 237 } |
| 238 |
| 239 TEST_F(BeginFrameObserverMapTest, RemoveOneWhileIterating) { |
| 240 size_t data_value1 = __LINE__; |
| 241 BeginFrameObserverMap<TestObserver, TestObserverData> obmap; |
| 242 TestObserver obs1; |
| 243 TestObserver obs2; |
| 244 TestObserver obs3; |
| 245 obmap.AddObserver(&obs1); |
| 246 obmap.AddObserver(&obs2); |
| 247 obmap.AddObserver(&obs3); |
| 248 |
| 249 obmap[&obs1]->data = data_value1; |
| 250 obmap[&obs2]->data = data_value1; |
| 251 obmap[&obs3]->data = data_value1; |
| 252 |
| 253 for (auto it = obmap.begin(); it != obmap.end(); it++) { |
| 254 obmap.RemoveObserver(&obs2); |
| 255 // Observer doesn't go away until the iteration is finished... |
| 256 EXPECT_TRUE(obmap.HasObserver(&obs2)); |
| 257 } |
| 258 EXPECT_FALSE(obmap.HasObserver(&obs2)); |
| 259 EXPECT_TRUE(obmap.HasObservers()); |
| 260 |
| 261 EXPECT_EQ(obmap[&obs1]->data, data_value1); |
| 262 EXPECT_EQ(obmap[&obs2], nullptr); |
| 263 EXPECT_EQ(obmap[&obs3]->data, data_value1); |
| 264 } |
| 265 |
| 266 TEST_F(BeginFrameObserverMapTest, NestedRemoveOneWhileIterating) { |
| 267 size_t data_value1 = __LINE__; |
| 268 BeginFrameObserverMap<TestObserver, TestObserverData> obmap; |
| 269 TestObserver obs1; |
| 270 TestObserver obs2; |
| 271 TestObserver obs3; |
| 272 obmap.AddObserver(&obs1); |
| 273 obmap.AddObserver(&obs2); |
| 274 obmap.AddObserver(&obs3); |
| 275 |
| 276 obmap[&obs1]->data = data_value1; |
| 277 obmap[&obs2]->data = data_value1; |
| 278 obmap[&obs3]->data = data_value1; |
| 279 |
| 280 for (auto it = obmap.begin(); it != obmap.end(); it++) { |
| 281 for (auto jt = obmap.begin(); jt != obmap.end(); jt++) { |
| 282 obmap.RemoveObserver(&obs2); |
| 283 } |
| 284 } |
| 285 EXPECT_TRUE(obmap.HasObservers()); |
| 286 |
| 287 EXPECT_EQ(obmap[&obs1]->data, data_value1); |
| 288 EXPECT_EQ(obmap[&obs2], nullptr); |
| 289 EXPECT_EQ(obmap[&obs3]->data, data_value1); |
| 290 } |
| 291 |
| 292 TEST_F(BeginFrameObserverMapTest, RemoveAllWhileIterating) { |
| 293 BeginFrameObserverMap<TestObserver, TestObserverData> obmap; |
| 294 TestObserver obs1; |
| 295 TestObserver obs2; |
| 296 TestObserver obs3; |
| 297 obmap.AddObserver(&obs1); |
| 298 obmap.AddObserver(&obs2); |
| 299 |
| 300 for (auto it = obmap.begin(); it != obmap.end(); it++) { |
| 301 obmap.RemoveObserver(it->first); |
| 302 } |
| 303 EXPECT_EMPTY(obmap); |
| 304 } |
| 305 |
| 306 TEST_F(BeginFrameObserverMapTest, NestedRemoveAllWhileIterating) { |
| 307 BeginFrameObserverMap<TestObserver, TestObserverData> obmap; |
| 308 TestObserver obs1; |
| 309 TestObserver obs2; |
| 310 TestObserver obs3; |
| 311 obmap.AddObserver(&obs1); |
| 312 obmap.AddObserver(&obs2); |
| 313 |
| 314 for (auto it = obmap.begin(); it != obmap.end(); it++) { |
| 315 for (auto jt = obmap.begin(); jt != obmap.end(); jt++) { |
| 316 obmap.RemoveObserver(jt->first); |
| 317 } |
| 318 } |
| 319 EXPECT_EMPTY(obmap); |
| 320 } |
| 321 |
| 322 TEST_F(BeginFrameObserverMapTest, AttemptToRemoveWhileConstIterating) { |
| 323 BeginFrameObserverMap<TestObserver, TestObserverData> obmap; |
| 324 TestObserver obs1; |
| 325 TestObserver obs2; |
| 326 obmap.AddObserver(&obs1); |
| 327 obmap.AddObserver(&obs2); |
| 328 |
| 329 EXPECT_DEATH({ |
| 330 for (auto it = obmap.cbegin(); it != obmap.cend(); it++) { |
| 331 obmap.RemoveObserver(const_cast<TestObserver*>(it->first)); |
| 332 } |
| 333 }, ""); |
| 334 |
| 335 const BeginFrameObserverMap<TestObserver, TestObserverData>* cobmap = &obmap; |
| 336 EXPECT_DEATH({ |
| 337 for (auto it = cobmap->begin(); it != cobmap->end(); it++) { |
| 338 obmap.RemoveObserver(const_cast<TestObserver*>(it->first)); |
| 339 } |
| 340 }, ""); |
| 341 } |
| 342 |
| 343 TEST_F(BeginFrameObserverMapTest, AttemptToAddWhileConstIterating) { |
| 344 BeginFrameObserverMap<TestObserver, TestObserverData> obmap; |
| 345 TestObserver obs1; |
| 346 TestObserver obs2; |
| 347 TestObserver obs3; |
| 348 obmap.AddObserver(&obs1); |
| 349 obmap.AddObserver(&obs2); |
| 350 |
| 351 EXPECT_DEATH({ |
| 352 for (auto it = obmap.cbegin(); it != obmap.cend(); it++) { |
| 353 obmap.AddObserver(&obs3); |
| 354 } |
| 355 }, ""); |
| 356 |
| 357 const BeginFrameObserverMap<TestObserver, TestObserverData>* cobmap = &obmap; |
| 358 EXPECT_DEATH({ |
| 359 for (auto it = cobmap->begin(); it != cobmap->end(); it++) { |
| 360 obmap.AddObserver(&obs3); |
| 361 } |
| 362 }, ""); |
| 363 } |
| 364 |
| 365 struct TestObserverOwner { |
| 366 TestObserverOwner() : ob1(), ob2(), obmap() {} |
| 367 |
| 368 TestObserver ob1; |
| 369 TestObserver ob2; |
| 370 BeginFrameObserverMap<TestObserver, TestObserverData> obmap; |
| 371 |
| 372 void Notify() { |
| 373 for (auto it = obmap.begin(); it != obmap.end(); it++) { |
| 374 it->first->Observe(); |
| 375 } |
| 376 } |
| 377 |
| 378 int LargestObserver() const { |
| 379 int largest = 0; |
| 380 for (auto it = obmap.begin(); it != obmap.end(); it++) { |
| 381 largest = std::max(largest, it->first->GetObserve()); |
| 382 } |
| 383 return largest; |
| 384 } |
| 385 size_t LargestData() const { |
| 386 size_t largest1 = 0; |
| 387 size_t largest2 = 0; |
| 388 for (auto it = obmap.begin(); it != obmap.end(); it++) { |
| 389 largest1 = std::max(largest1, it->second->data); |
| 390 largest2 = std::max(largest2, obmap[it->first]->data); |
| 391 } |
| 392 DCHECK_EQ(largest1, largest2); |
| 393 return largest1; |
| 394 } |
| 395 }; |
| 396 |
| 397 TEST_F(BeginFrameObserverMapTest, ObserverOwner) { |
| 398 TestObserverOwner owner; |
| 399 |
| 400 owner.Notify(); |
| 401 EXPECT_EQ(owner.LargestObserver(), 0); |
| 402 EXPECT_EQ(owner.LargestData(), 0U); |
| 403 |
| 404 owner.obmap.AddObserver(&owner.ob1); |
| 405 owner.Notify(); |
| 406 EXPECT_EQ(owner.LargestObserver(), 1); |
| 407 EXPECT_EQ(owner.LargestData(), 0U); |
| 408 |
| 409 owner.obmap[&owner.ob1]->data = 2; |
| 410 EXPECT_EQ(owner.LargestObserver(), 1); |
| 411 EXPECT_EQ(owner.LargestData(), 2U); |
| 412 |
| 413 owner.obmap.AddObserver(&owner.ob2); |
| 414 EXPECT_EQ(owner.LargestObserver(), 1); |
| 415 EXPECT_EQ(owner.LargestData(), 2U); |
| 416 owner.Notify(); |
| 417 owner.Notify(); |
| 418 EXPECT_EQ(owner.LargestObserver(), 3); |
| 419 EXPECT_EQ(owner.LargestData(), 2U); |
| 420 |
| 421 owner.obmap[&owner.ob2]->data = 5; |
| 422 EXPECT_EQ(owner.LargestObserver(), 3); |
| 423 EXPECT_EQ(owner.LargestData(), 5U); |
| 424 |
| 425 owner.obmap.RemoveObserver(&owner.ob1); |
| 426 EXPECT_EQ(owner.LargestObserver(), 2); |
| 427 EXPECT_EQ(owner.LargestData(), 5U); |
| 428 } |
| 429 |
| 430 } // namespace |
| 431 } // namespace cc |
OLD | NEW |