Roll skia to r1241.
[chromium-blink-merge.git] / base / observer_list_unittest.cc
blobd313367b3068752c3b7b36033ff584f0b4adf984
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/memory/ref_counted.h"
11 #include "base/message_loop.h"
12 #include "base/threading/platform_thread.h"
13 #include "testing/gtest/include/gtest/gtest.h"
15 using base::PlatformThread;
16 using base::Time;
18 namespace {
20 class Foo {
21 public:
22 virtual void Observe(int x) = 0;
23 virtual ~Foo() {}
26 class Adder : public Foo {
27 public:
28 explicit Adder(int scaler) : total(0), scaler_(scaler) {}
29 virtual void Observe(int x) {
30 total += x * scaler_;
32 virtual ~Adder() { }
33 int total;
34 private:
35 int scaler_;
38 class Disrupter : public Foo {
39 public:
40 Disrupter(ObserverList<Foo>* list, Foo* doomed)
41 : list_(list), doomed_(doomed) { }
42 virtual ~Disrupter() { }
43 virtual void Observe(int x) {
44 list_->RemoveObserver(doomed_);
46 private:
47 ObserverList<Foo>* list_;
48 Foo* doomed_;
51 class ThreadSafeDisrupter : public Foo {
52 public:
53 ThreadSafeDisrupter(ObserverListThreadSafe<Foo>* list, Foo* doomed)
54 : list_(list), doomed_(doomed) { }
55 virtual ~ThreadSafeDisrupter() { }
56 virtual void Observe(int x) {
57 list_->RemoveObserver(doomed_);
59 private:
60 ObserverListThreadSafe<Foo>* list_;
61 Foo* doomed_;
64 class AddInObserve : public Foo {
65 public:
66 explicit AddInObserve(ObserverList<Foo>* observer_list)
67 : added(false),
68 observer_list(observer_list),
69 adder(1) {
71 virtual void Observe(int x) {
72 if (!added) {
73 added = true;
74 observer_list->AddObserver(&adder);
78 bool added;
79 ObserverList<Foo>* observer_list;
80 Adder adder;
84 class ObserverListThreadSafeTest : public testing::Test {
87 static const int kThreadRunTime = 2000; // ms to run the multi-threaded test.
89 // A thread for use in the ThreadSafeObserver test
90 // which will add and remove itself from the notification
91 // list repeatedly.
92 class AddRemoveThread : public PlatformThread::Delegate,
93 public Foo {
94 public:
95 AddRemoveThread(ObserverListThreadSafe<Foo>* list, bool notify)
96 : list_(list),
97 in_list_(false),
98 start_(Time::Now()),
99 count_observes_(0),
100 count_addtask_(0),
101 do_notifies_(notify) {
102 factory_ = new ScopedRunnableMethodFactory<AddRemoveThread>(this);
105 virtual ~AddRemoveThread() {
106 delete factory_;
109 void ThreadMain() {
110 loop_ = new MessageLoop(); // Fire up a message loop.
111 loop_->PostTask(
112 FROM_HERE, factory_->NewRunnableMethod(&AddRemoveThread::AddTask));
113 loop_->Run();
114 //LOG(ERROR) << "Loop 0x" << std::hex << loop_ << " done. " <<
115 // count_observes_ << ", " << count_addtask_;
116 delete loop_;
117 loop_ = reinterpret_cast<MessageLoop*>(0xdeadbeef);
118 delete this;
121 // This task just keeps posting to itself in an attempt
122 // to race with the notifier.
123 void AddTask() {
124 count_addtask_++;
126 if ((Time::Now() - start_).InMilliseconds() > kThreadRunTime) {
127 VLOG(1) << "DONE!";
128 return;
131 if (!in_list_) {
132 list_->AddObserver(this);
133 in_list_ = true;
136 if (do_notifies_) {
137 list_->Notify(&Foo::Observe, 10);
140 loop_->PostDelayedTask(FROM_HERE,
141 factory_->NewRunnableMethod(&AddRemoveThread::AddTask), 0);
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 ScopedRunnableMethodFactory<AddRemoveThread>* factory_;
176 TEST(ObserverListTest, BasicTest) {
177 ObserverList<Foo> observer_list;
178 Adder a(1), b(-1), c(1), d(-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 FOR_EACH_OBSERVER(Foo, observer_list, Observe(10));
192 EXPECT_EQ(a.total, 20);
193 EXPECT_EQ(b.total, -20);
194 EXPECT_EQ(c.total, 0);
195 EXPECT_EQ(d.total, -10);
198 TEST(ObserverListThreadSafeTest, BasicTest) {
199 MessageLoop loop;
201 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
202 new ObserverListThreadSafe<Foo>);
203 Adder a(1);
204 Adder b(-1);
205 Adder c(1);
206 Adder d(-1);
207 ThreadSafeDisrupter evil(observer_list.get(), &c);
209 observer_list->AddObserver(&a);
210 observer_list->AddObserver(&b);
212 observer_list->Notify(&Foo::Observe, 10);
213 loop.RunAllPending();
215 observer_list->AddObserver(&evil);
216 observer_list->AddObserver(&c);
217 observer_list->AddObserver(&d);
219 observer_list->Notify(&Foo::Observe, 10);
220 loop.RunAllPending();
222 EXPECT_EQ(a.total, 20);
223 EXPECT_EQ(b.total, -20);
224 EXPECT_EQ(c.total, 0);
225 EXPECT_EQ(d.total, -10);
228 class FooRemover : public Foo {
229 public:
230 explicit FooRemover(ObserverListThreadSafe<Foo>* list) : list_(list) {}
231 virtual ~FooRemover() {}
233 void AddFooToRemove(Foo* foo) {
234 foos_.push_back(foo);
237 virtual void Observe(int x) {
238 std::vector<Foo*> tmp;
239 tmp.swap(foos_);
240 for (std::vector<Foo*>::iterator it = tmp.begin();
241 it != tmp.end(); ++it) {
242 list_->RemoveObserver(*it);
246 private:
247 const scoped_refptr<ObserverListThreadSafe<Foo> > list_;
248 std::vector<Foo*> foos_;
251 TEST(ObserverListThreadSafeTest, RemoveMultipleObservers) {
252 MessageLoop loop;
253 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
254 new ObserverListThreadSafe<Foo>);
256 FooRemover a(observer_list);
257 Adder b(1);
259 observer_list->AddObserver(&a);
260 observer_list->AddObserver(&b);
262 a.AddFooToRemove(&a);
263 a.AddFooToRemove(&b);
265 observer_list->Notify(&Foo::Observe, 1);
266 loop.RunAllPending();
269 // A test driver for a multi-threaded notification loop. Runs a number
270 // of observer threads, each of which constantly adds/removes itself
271 // from the observer list. Optionally, if cross_thread_notifies is set
272 // to true, the observer threads will also trigger notifications to
273 // all observers.
274 static void ThreadSafeObserverHarness(int num_threads,
275 bool cross_thread_notifies) {
276 MessageLoop loop;
278 const int kMaxThreads = 15;
279 num_threads = num_threads > kMaxThreads ? kMaxThreads : num_threads;
281 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
282 new ObserverListThreadSafe<Foo>);
283 Adder a(1);
284 Adder b(-1);
285 Adder c(1);
286 Adder d(-1);
288 observer_list->AddObserver(&a);
289 observer_list->AddObserver(&b);
291 AddRemoveThread* threaded_observer[kMaxThreads];
292 base::PlatformThreadHandle threads[kMaxThreads];
293 for (int index = 0; index < num_threads; index++) {
294 threaded_observer[index] = new AddRemoveThread(observer_list.get(), false);
295 EXPECT_TRUE(PlatformThread::Create(0,
296 threaded_observer[index], &threads[index]));
299 Time start = Time::Now();
300 while (true) {
301 if ((Time::Now() - start).InMilliseconds() > kThreadRunTime)
302 break;
304 observer_list->Notify(&Foo::Observe, 10);
306 loop.RunAllPending();
309 for (int index = 0; index < num_threads; index++) {
310 threaded_observer[index]->Quit();
311 PlatformThread::Join(threads[index]);
315 TEST(ObserverListThreadSafeTest, CrossThreadObserver) {
316 // Use 7 observer threads. Notifications only come from
317 // the main thread.
318 ThreadSafeObserverHarness(7, false);
321 TEST(ObserverListThreadSafeTest, CrossThreadNotifications) {
322 // Use 3 observer threads. Notifications will fire from
323 // the main thread and all 3 observer threads.
324 ThreadSafeObserverHarness(3, true);
327 TEST(ObserverListTest, Existing) {
328 ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY);
329 Adder a(1);
330 AddInObserve b(&observer_list);
332 observer_list.AddObserver(&a);
333 observer_list.AddObserver(&b);
335 FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
337 EXPECT_TRUE(b.added);
338 // B's adder should not have been notified because it was added during
339 // notificaiton.
340 EXPECT_EQ(0, b.adder.total);
342 // Notify again to make sure b's adder is notified.
343 FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
344 EXPECT_EQ(1, b.adder.total);
347 class AddInClearObserve : public Foo {
348 public:
349 explicit AddInClearObserve(ObserverList<Foo>* list)
350 : list_(list), added_(false), adder_(1) {}
352 virtual void Observe(int /* x */) {
353 list_->Clear();
354 list_->AddObserver(&adder_);
355 added_ = true;
358 bool added() const { return added_; }
359 const Adder& adder() const { return adder_; }
361 private:
362 ObserverList<Foo>* const list_;
364 bool added_;
365 Adder adder_;
368 TEST(ObserverListTest, ClearNotifyAll) {
369 ObserverList<Foo> observer_list;
370 AddInClearObserve a(&observer_list);
372 observer_list.AddObserver(&a);
374 FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
375 EXPECT_TRUE(a.added());
376 EXPECT_EQ(1, a.adder().total)
377 << "Adder should observe once and have sum of 1.";
380 TEST(ObserverListTest, ClearNotifyExistingOnly) {
381 ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY);
382 AddInClearObserve a(&observer_list);
384 observer_list.AddObserver(&a);
386 FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
387 EXPECT_TRUE(a.added());
388 EXPECT_EQ(0, a.adder().total)
389 << "Adder should not observe, so sum should still be 0.";
392 } // namespace