WebKit roll 98705:98715
[chromium-blink-merge.git] / base / observer_list_unittest.cc
blob34cc4857b83d13d2fec26cdc62f2eda456c76f0e
1 // Copyright (c) 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.
5 #include "base/observer_list.h"
6 #include "base/observer_list_threadsafe.h"
8 #include <vector>
10 #include "base/compiler_specific.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/message_loop.h"
13 #include "base/threading/platform_thread.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 using base::PlatformThread;
17 using base::Time;
19 namespace {
21 class Foo {
22 public:
23 virtual void Observe(int x) = 0;
24 virtual ~Foo() {}
27 class Adder : public Foo {
28 public:
29 explicit Adder(int scaler) : total(0), scaler_(scaler) {}
30 virtual void Observe(int x) {
31 total += x * scaler_;
33 virtual ~Adder() { }
34 int total;
35 private:
36 int scaler_;
39 class Disrupter : public Foo {
40 public:
41 Disrupter(ObserverList<Foo>* list, Foo* doomed)
42 : list_(list), doomed_(doomed) { }
43 virtual ~Disrupter() { }
44 virtual void Observe(int x) {
45 list_->RemoveObserver(doomed_);
47 private:
48 ObserverList<Foo>* list_;
49 Foo* doomed_;
52 class ThreadSafeDisrupter : public Foo {
53 public:
54 ThreadSafeDisrupter(ObserverListThreadSafe<Foo>* list, Foo* doomed)
55 : list_(list), doomed_(doomed) { }
56 virtual ~ThreadSafeDisrupter() { }
57 virtual void Observe(int x) {
58 list_->RemoveObserver(doomed_);
60 private:
61 ObserverListThreadSafe<Foo>* list_;
62 Foo* doomed_;
65 template <typename ObserverListType>
66 class AddInObserve : public Foo {
67 public:
68 explicit AddInObserve(ObserverListType* observer_list)
69 : added(false),
70 observer_list(observer_list),
71 adder(1) {
73 virtual void Observe(int x) {
74 if (!added) {
75 added = true;
76 observer_list->AddObserver(&adder);
80 bool added;
81 ObserverListType* observer_list;
82 Adder adder;
86 static const int kThreadRunTime = 2000; // ms to run the multi-threaded test.
88 // A thread for use in the ThreadSafeObserver test
89 // which will add and remove itself from the notification
90 // list repeatedly.
91 class AddRemoveThread : public PlatformThread::Delegate,
92 public Foo {
93 public:
94 AddRemoveThread(ObserverListThreadSafe<Foo>* list, bool notify)
95 : list_(list),
96 in_list_(false),
97 start_(Time::Now()),
98 count_observes_(0),
99 count_addtask_(0),
100 do_notifies_(notify),
101 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
104 virtual ~AddRemoveThread() {
107 void ThreadMain() {
108 loop_ = new MessageLoop(); // Fire up a message loop.
109 loop_->PostTask(
110 FROM_HERE,
111 base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
112 loop_->Run();
113 //LOG(ERROR) << "Loop 0x" << std::hex << loop_ << " done. " <<
114 // count_observes_ << ", " << count_addtask_;
115 delete loop_;
116 loop_ = reinterpret_cast<MessageLoop*>(0xdeadbeef);
117 delete this;
120 // This task just keeps posting to itself in an attempt
121 // to race with the notifier.
122 void AddTask() {
123 count_addtask_++;
125 if ((Time::Now() - start_).InMilliseconds() > kThreadRunTime) {
126 VLOG(1) << "DONE!";
127 return;
130 if (!in_list_) {
131 list_->AddObserver(this);
132 in_list_ = true;
135 if (do_notifies_) {
136 list_->Notify(&Foo::Observe, 10);
139 loop_->PostTask(
140 FROM_HERE,
141 base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
144 void Quit() {
145 loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
148 virtual void Observe(int x) {
149 count_observes_++;
151 // If we're getting called after we removed ourselves from
152 // the list, that is very bad!
153 DCHECK(in_list_);
155 // This callback should fire on the appropriate thread
156 EXPECT_EQ(loop_, MessageLoop::current());
158 list_->RemoveObserver(this);
159 in_list_ = false;
162 private:
163 ObserverListThreadSafe<Foo>* list_;
164 MessageLoop* loop_;
165 bool in_list_; // Are we currently registered for notifications.
166 // in_list_ is only used on |this| thread.
167 Time start_; // The time we started the test.
169 int count_observes_; // Number of times we observed.
170 int count_addtask_; // Number of times thread AddTask was called
171 bool do_notifies_; // Whether these threads should do notifications.
173 base::WeakPtrFactory<AddRemoveThread> weak_factory_;
176 TEST(ObserverListTest, BasicTest) {
177 ObserverList<Foo> observer_list;
178 Adder a(1), b(-1), c(1), d(-1), e(-1);
179 Disrupter evil(&observer_list, &c);
181 observer_list.AddObserver(&a);
182 observer_list.AddObserver(&b);
184 FOR_EACH_OBSERVER(Foo, observer_list, Observe(10));
186 observer_list.AddObserver(&evil);
187 observer_list.AddObserver(&c);
188 observer_list.AddObserver(&d);
190 // Removing an observer not in the list should do nothing.
191 observer_list.RemoveObserver(&e);
193 FOR_EACH_OBSERVER(Foo, observer_list, Observe(10));
195 EXPECT_EQ(a.total, 20);
196 EXPECT_EQ(b.total, -20);
197 EXPECT_EQ(c.total, 0);
198 EXPECT_EQ(d.total, -10);
199 EXPECT_EQ(e.total, 0);
202 TEST(ObserverListThreadSafeTest, BasicTest) {
203 MessageLoop loop;
205 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
206 new ObserverListThreadSafe<Foo>);
207 Adder a(1);
208 Adder b(-1);
209 Adder c(1);
210 Adder d(-1);
211 ThreadSafeDisrupter evil(observer_list.get(), &c);
213 observer_list->AddObserver(&a);
214 observer_list->AddObserver(&b);
216 observer_list->Notify(&Foo::Observe, 10);
217 loop.RunAllPending();
219 observer_list->AddObserver(&evil);
220 observer_list->AddObserver(&c);
221 observer_list->AddObserver(&d);
223 observer_list->Notify(&Foo::Observe, 10);
224 loop.RunAllPending();
226 EXPECT_EQ(a.total, 20);
227 EXPECT_EQ(b.total, -20);
228 EXPECT_EQ(c.total, 0);
229 EXPECT_EQ(d.total, -10);
232 TEST(ObserverListThreadSafeTest, RemoveObserver) {
233 MessageLoop loop;
235 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
236 new ObserverListThreadSafe<Foo>);
237 Adder a(1), b(1);
239 // Should do nothing.
240 observer_list->RemoveObserver(&a);
241 observer_list->RemoveObserver(&b);
243 observer_list->Notify(&Foo::Observe, 10);
244 loop.RunAllPending();
246 EXPECT_EQ(a.total, 0);
247 EXPECT_EQ(b.total, 0);
249 observer_list->AddObserver(&a);
251 // Should also do nothing.
252 observer_list->RemoveObserver(&b);
254 observer_list->Notify(&Foo::Observe, 10);
255 loop.RunAllPending();
257 EXPECT_EQ(a.total, 10);
258 EXPECT_EQ(b.total, 0);
261 class FooRemover : public Foo {
262 public:
263 explicit FooRemover(ObserverListThreadSafe<Foo>* list) : list_(list) {}
264 virtual ~FooRemover() {}
266 void AddFooToRemove(Foo* foo) {
267 foos_.push_back(foo);
270 virtual void Observe(int x) {
271 std::vector<Foo*> tmp;
272 tmp.swap(foos_);
273 for (std::vector<Foo*>::iterator it = tmp.begin();
274 it != tmp.end(); ++it) {
275 list_->RemoveObserver(*it);
279 private:
280 const scoped_refptr<ObserverListThreadSafe<Foo> > list_;
281 std::vector<Foo*> foos_;
284 TEST(ObserverListThreadSafeTest, RemoveMultipleObservers) {
285 MessageLoop loop;
286 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
287 new ObserverListThreadSafe<Foo>);
289 FooRemover a(observer_list);
290 Adder b(1);
292 observer_list->AddObserver(&a);
293 observer_list->AddObserver(&b);
295 a.AddFooToRemove(&a);
296 a.AddFooToRemove(&b);
298 observer_list->Notify(&Foo::Observe, 1);
299 loop.RunAllPending();
302 // A test driver for a multi-threaded notification loop. Runs a number
303 // of observer threads, each of which constantly adds/removes itself
304 // from the observer list. Optionally, if cross_thread_notifies is set
305 // to true, the observer threads will also trigger notifications to
306 // all observers.
307 static void ThreadSafeObserverHarness(int num_threads,
308 bool cross_thread_notifies) {
309 MessageLoop loop;
311 const int kMaxThreads = 15;
312 num_threads = num_threads > kMaxThreads ? kMaxThreads : num_threads;
314 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
315 new ObserverListThreadSafe<Foo>);
316 Adder a(1);
317 Adder b(-1);
318 Adder c(1);
319 Adder d(-1);
321 observer_list->AddObserver(&a);
322 observer_list->AddObserver(&b);
324 AddRemoveThread* threaded_observer[kMaxThreads];
325 base::PlatformThreadHandle threads[kMaxThreads];
326 for (int index = 0; index < num_threads; index++) {
327 threaded_observer[index] = new AddRemoveThread(observer_list.get(), false);
328 EXPECT_TRUE(PlatformThread::Create(0,
329 threaded_observer[index], &threads[index]));
332 Time start = Time::Now();
333 while (true) {
334 if ((Time::Now() - start).InMilliseconds() > kThreadRunTime)
335 break;
337 observer_list->Notify(&Foo::Observe, 10);
339 loop.RunAllPending();
342 for (int index = 0; index < num_threads; index++) {
343 threaded_observer[index]->Quit();
344 PlatformThread::Join(threads[index]);
348 TEST(ObserverListThreadSafeTest, CrossThreadObserver) {
349 // Use 7 observer threads. Notifications only come from
350 // the main thread.
351 ThreadSafeObserverHarness(7, false);
354 TEST(ObserverListThreadSafeTest, CrossThreadNotifications) {
355 // Use 3 observer threads. Notifications will fire from
356 // the main thread and all 3 observer threads.
357 ThreadSafeObserverHarness(3, true);
360 TEST(ObserverListThreadSafeTest, OutlivesMessageLoop) {
361 MessageLoop* loop = new MessageLoop;
362 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
363 new ObserverListThreadSafe<Foo>);
365 Adder a(1);
366 observer_list->AddObserver(&a);
367 delete loop;
368 // Test passes if we don't crash here.
369 observer_list->Notify(&Foo::Observe, 1);
372 TEST(ObserverListTest, Existing) {
373 ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY);
374 Adder a(1);
375 AddInObserve<ObserverList<Foo> > b(&observer_list);
377 observer_list.AddObserver(&a);
378 observer_list.AddObserver(&b);
380 FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
382 EXPECT_TRUE(b.added);
383 // B's adder should not have been notified because it was added during
384 // notificaiton.
385 EXPECT_EQ(0, b.adder.total);
387 // Notify again to make sure b's adder is notified.
388 FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
389 EXPECT_EQ(1, b.adder.total);
392 // Same as above, but for ObserverListThreadSafe
393 TEST(ObserverListThreadSafeTest, Existing) {
394 MessageLoop loop;
395 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
396 new ObserverListThreadSafe<Foo>(ObserverList<Foo>::NOTIFY_EXISTING_ONLY));
397 Adder a(1);
398 AddInObserve<ObserverListThreadSafe<Foo> > b(observer_list.get());
400 observer_list->AddObserver(&a);
401 observer_list->AddObserver(&b);
403 observer_list->Notify(&Foo::Observe, 1);
404 loop.RunAllPending();
406 EXPECT_TRUE(b.added);
407 // B's adder should not have been notified because it was added during
408 // notificaiton.
409 EXPECT_EQ(0, b.adder.total);
411 // Notify again to make sure b's adder is notified.
412 observer_list->Notify(&Foo::Observe, 1);
413 loop.RunAllPending();
414 EXPECT_EQ(1, b.adder.total);
417 class AddInClearObserve : public Foo {
418 public:
419 explicit AddInClearObserve(ObserverList<Foo>* list)
420 : list_(list), added_(false), adder_(1) {}
422 virtual void Observe(int /* x */) {
423 list_->Clear();
424 list_->AddObserver(&adder_);
425 added_ = true;
428 bool added() const { return added_; }
429 const Adder& adder() const { return adder_; }
431 private:
432 ObserverList<Foo>* const list_;
434 bool added_;
435 Adder adder_;
438 TEST(ObserverListTest, ClearNotifyAll) {
439 ObserverList<Foo> observer_list;
440 AddInClearObserve a(&observer_list);
442 observer_list.AddObserver(&a);
444 FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
445 EXPECT_TRUE(a.added());
446 EXPECT_EQ(1, a.adder().total)
447 << "Adder should observe once and have sum of 1.";
450 TEST(ObserverListTest, ClearNotifyExistingOnly) {
451 ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY);
452 AddInClearObserve a(&observer_list);
454 observer_list.AddObserver(&a);
456 FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
457 EXPECT_TRUE(a.added());
458 EXPECT_EQ(0, a.adder().total)
459 << "Adder should not observe, so sum should still be 0.";
462 class ListDestructor : public Foo {
463 public:
464 explicit ListDestructor(ObserverList<Foo>* list) : list_(list) {}
465 virtual void Observe(int x) {
466 delete list_;
468 virtual ~ListDestructor() { }
469 int total;
470 private:
471 ObserverList<Foo>* list_;
475 TEST(ObserverListTest, IteratorOutlivesList) {
476 ObserverList<Foo>* observer_list = new ObserverList<Foo>;
477 ListDestructor a(observer_list);
478 observer_list->AddObserver(&a);
480 FOR_EACH_OBSERVER(Foo, *observer_list, Observe(0));
481 // If this test fails, there'll be Valgrind errors when this function goes out
482 // of scope.
485 } // namespace