blob: 83be2b1f0baac56d3ae3b9a9a0a9dafc2135d881 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 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.
initial.commitd7cae122008-07-26 21:49:384
5#include "base/logging.h"
6#include "base/message_loop.h"
[email protected]b16ef312008-08-19 18:36:237#include "base/platform_thread.h"
initial.commitd7cae122008-07-26 21:49:388#include "base/ref_counted.h"
[email protected]b16ef312008-08-19 18:36:239#include "base/thread.h"
initial.commitd7cae122008-07-26 21:49:3810#include "testing/gtest/include/gtest/gtest.h"
11
[email protected]295039bd2008-08-15 04:32:5712#if defined(OS_WIN)
13#include "base/message_pump_win.h"
[email protected]b16ef312008-08-19 18:36:2314#include "base/scoped_handle.h"
[email protected]295039bd2008-08-15 04:32:5715#endif
16
[email protected]4d9bdfaf2008-08-26 05:53:5717using base::Thread;
[email protected]e1acf6f2008-10-27 20:43:3318using base::Time;
19using base::TimeDelta;
[email protected]4d9bdfaf2008-08-26 05:53:5720
21// TODO(darin): Platform-specific MessageLoop tests should be grouped together
22// to avoid chopping this file up with so many #ifdefs.
[email protected]b16ef312008-08-19 18:36:2323
initial.commitd7cae122008-07-26 21:49:3824namespace {
25
[email protected]4d9bdfaf2008-08-26 05:53:5726class MessageLoopTest : public testing::Test {};
initial.commitd7cae122008-07-26 21:49:3827
28class Foo : public base::RefCounted<Foo> {
29 public:
30 Foo() : test_count_(0) {
31 }
32
33 void Test0() {
34 ++test_count_;
35 }
36
37 void Test1ConstRef(const std::string& a) {
38 ++test_count_;
39 result_.append(a);
40 }
41
42 void Test1Ptr(std::string* a) {
43 ++test_count_;
44 result_.append(*a);
45 }
46
47 void Test1Int(int a) {
48 test_count_ += a;
49 }
50
51 void Test2Ptr(std::string* a, std::string* b) {
52 ++test_count_;
53 result_.append(*a);
54 result_.append(*b);
55 }
56
57 void Test2Mixed(const std::string& a, std::string* b) {
58 ++test_count_;
59 result_.append(a);
60 result_.append(*b);
61 }
62
63 int test_count() const { return test_count_; }
64 const std::string& result() const { return result_; }
65
66 private:
67 int test_count_;
68 std::string result_;
69};
70
71class QuitMsgLoop : public base::RefCounted<QuitMsgLoop> {
72 public:
73 void QuitNow() {
74 MessageLoop::current()->Quit();
75 }
76};
77
[email protected]4d9bdfaf2008-08-26 05:53:5778void RunTest_PostTask(MessageLoop::Type message_loop_type) {
79 MessageLoop loop(message_loop_type);
initial.commitd7cae122008-07-26 21:49:3880
initial.commitd7cae122008-07-26 21:49:3881 // Add tests to message loop
82 scoped_refptr<Foo> foo = new Foo();
83 std::string a("a"), b("b"), c("c"), d("d");
84 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
85 foo.get(), &Foo::Test0));
86 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
87 foo.get(), &Foo::Test1ConstRef, a));
88 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
89 foo.get(), &Foo::Test1Ptr, &b));
90 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
91 foo.get(), &Foo::Test1Int, 100));
92 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
93 foo.get(), &Foo::Test2Ptr, &a, &c));
94 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
95 foo.get(), &Foo::Test2Mixed, a, &d));
96
97 // After all tests, post a message that will shut down the message loop
98 scoped_refptr<QuitMsgLoop> quit = new QuitMsgLoop();
99 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
100 quit.get(), &QuitMsgLoop::QuitNow));
101
102 // Now kick things off
103 MessageLoop::current()->Run();
104
105 EXPECT_EQ(foo->test_count(), 105);
106 EXPECT_EQ(foo->result(), "abacad");
107}
108
[email protected]4d9bdfaf2008-08-26 05:53:57109void RunTest_PostTask_SEH(MessageLoop::Type message_loop_type) {
110 MessageLoop loop(message_loop_type);
111
initial.commitd7cae122008-07-26 21:49:38112 // Add tests to message loop
113 scoped_refptr<Foo> foo = new Foo();
114 std::string a("a"), b("b"), c("c"), d("d");
115 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
116 foo.get(), &Foo::Test0));
117 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
118 foo.get(), &Foo::Test1ConstRef, a));
119 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
120 foo.get(), &Foo::Test1Ptr, &b));
121 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
122 foo.get(), &Foo::Test1Int, 100));
123 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
124 foo.get(), &Foo::Test2Ptr, &a, &c));
125 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
126 foo.get(), &Foo::Test2Mixed, a, &d));
127
128 // After all tests, post a message that will shut down the message loop
129 scoped_refptr<QuitMsgLoop> quit = new QuitMsgLoop();
130 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
131 quit.get(), &QuitMsgLoop::QuitNow));
132
133 // Now kick things off with the SEH block active.
134 MessageLoop::current()->set_exception_restoration(true);
135 MessageLoop::current()->Run();
136 MessageLoop::current()->set_exception_restoration(false);
137
138 EXPECT_EQ(foo->test_count(), 105);
139 EXPECT_EQ(foo->result(), "abacad");
140}
141
[email protected]752578562008-09-07 08:08:29142// This class runs slowly to simulate a large amount of work being done.
143class SlowTask : public Task {
144 public:
145 SlowTask(int pause_ms, int* quit_counter)
146 : pause_ms_(pause_ms), quit_counter_(quit_counter) {
147 }
148 virtual void Run() {
149 PlatformThread::Sleep(pause_ms_);
150 if (--(*quit_counter_) == 0)
151 MessageLoop::current()->Quit();
152 }
153 private:
154 int pause_ms_;
155 int* quit_counter_;
156};
157
158// This class records the time when Run was called in a Time object, which is
159// useful for building a variety of MessageLoop tests.
160class RecordRunTimeTask : public SlowTask {
161 public:
162 RecordRunTimeTask(Time* run_time, int* quit_counter)
163 : SlowTask(10, quit_counter), run_time_(run_time) {
164 }
165 virtual void Run() {
166 *run_time_ = Time::Now();
167 // Cause our Run function to take some time to execute. As a result we can
168 // count on subsequent RecordRunTimeTask objects running at a future time,
169 // without worry about the resolution of our system clock being an issue.
170 SlowTask::Run();
171 }
172 private:
173 Time* run_time_;
174};
175
176void RunTest_PostDelayedTask_Basic(MessageLoop::Type message_loop_type) {
177 MessageLoop loop(message_loop_type);
178
179 // Test that PostDelayedTask results in a delayed task.
180
181 const int kDelayMS = 100;
182
183 int num_tasks = 1;
184 Time run_time;
185
186 loop.PostDelayedTask(
187 FROM_HERE, new RecordRunTimeTask(&run_time, &num_tasks), kDelayMS);
188
189 Time time_before_run = Time::Now();
190 loop.Run();
191 Time time_after_run = Time::Now();
192
193 EXPECT_EQ(0, num_tasks);
194 EXPECT_LT(kDelayMS, (time_after_run - time_before_run).InMilliseconds());
195}
196
197void RunTest_PostDelayedTask_InDelayOrder(MessageLoop::Type message_loop_type) {
198 MessageLoop loop(message_loop_type);
199
200 // Test that two tasks with different delays run in the right order.
201
202 int num_tasks = 2;
203 Time run_time1, run_time2;
204
205 loop.PostDelayedTask(
206 FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks), 200);
207 // If we get a large pause in execution (due to a context switch) here, this
208 // test could fail.
209 loop.PostDelayedTask(
210 FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), 10);
211
212 loop.Run();
213 EXPECT_EQ(0, num_tasks);
214
215 EXPECT_TRUE(run_time2 < run_time1);
216}
217
218void RunTest_PostDelayedTask_InPostOrder(MessageLoop::Type message_loop_type) {
219 MessageLoop loop(message_loop_type);
220
221 // Test that two tasks with the same delay run in the order in which they
222 // were posted.
223 //
224 // NOTE: This is actually an approximate test since the API only takes a
225 // "delay" parameter, so we are not exactly simulating two tasks that get
226 // posted at the exact same time. It would be nice if the API allowed us to
227 // specify the desired run time.
228
229 const int kDelayMS = 100;
230
231 int num_tasks = 2;
232 Time run_time1, run_time2;
233
234 loop.PostDelayedTask(
235 FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks), kDelayMS);
236 loop.PostDelayedTask(
237 FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), kDelayMS);
238
239 loop.Run();
240 EXPECT_EQ(0, num_tasks);
241
242 EXPECT_TRUE(run_time1 < run_time2);
243}
244
[email protected]32cda29d2008-10-09 23:58:43245void RunTest_PostDelayedTask_InPostOrder_2(
246 MessageLoop::Type message_loop_type) {
[email protected]752578562008-09-07 08:08:29247 MessageLoop loop(message_loop_type);
248
249 // Test that a delayed task still runs after a normal tasks even if the
250 // normal tasks take a long time to run.
251
252 const int kPauseMS = 50;
253
254 int num_tasks = 2;
255 Time run_time;
256
257 loop.PostTask(
258 FROM_HERE, new SlowTask(kPauseMS, &num_tasks));
259 loop.PostDelayedTask(
260 FROM_HERE, new RecordRunTimeTask(&run_time, &num_tasks), 10);
261
262 Time time_before_run = Time::Now();
263 loop.Run();
264 Time time_after_run = Time::Now();
265
266 EXPECT_EQ(0, num_tasks);
267
268 EXPECT_LT(kPauseMS, (time_after_run - time_before_run).InMilliseconds());
269}
270
[email protected]32cda29d2008-10-09 23:58:43271void RunTest_PostDelayedTask_InPostOrder_3(
272 MessageLoop::Type message_loop_type) {
[email protected]752578562008-09-07 08:08:29273 MessageLoop loop(message_loop_type);
274
275 // Test that a delayed task still runs after a pile of normal tasks. The key
276 // difference between this test and the previous one is that here we return
277 // the MessageLoop a lot so we give the MessageLoop plenty of opportunities
278 // to maybe run the delayed task. It should know not to do so until the
279 // delayed task's delay has passed.
280
281 int num_tasks = 11;
282 Time run_time1, run_time2;
283
284 // Clutter the ML with tasks.
285 for (int i = 1; i < num_tasks; ++i)
286 loop.PostTask(FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks));
287
288 loop.PostDelayedTask(
289 FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), 1);
290
291 loop.Run();
292 EXPECT_EQ(0, num_tasks);
293
294 EXPECT_TRUE(run_time2 > run_time1);
295}
296
[email protected]72deacd2008-09-23 19:19:20297void RunTest_PostDelayedTask_SharedTimer(MessageLoop::Type message_loop_type) {
298 MessageLoop loop(message_loop_type);
299
300 // Test that the interval of the timer, used to run the next delayed task, is
301 // set to a value corresponding to when the next delayed task should run.
302
303 // By setting num_tasks to 1, we ensure that the first task to run causes the
304 // run loop to exit.
305 int num_tasks = 1;
306 Time run_time1, run_time2;
307
308 loop.PostDelayedTask(
309 FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks), 1000000);
310 loop.PostDelayedTask(
311 FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), 10);
312
313 Time start_time = Time::Now();
314
315 loop.Run();
316 EXPECT_EQ(0, num_tasks);
317
318 // Ensure that we ran in far less time than the slower timer.
[email protected]4615f1982008-09-23 19:22:33319 TimeDelta total_time = Time::Now() - start_time;
320 EXPECT_GT(5000, total_time.InMilliseconds());
[email protected]32cda29d2008-10-09 23:58:43321
[email protected]72deacd2008-09-23 19:19:20322 // In case both timers somehow run at nearly the same time, sleep a little
323 // and then run all pending to force them both to have run. This is just
324 // encouraging flakiness if there is any.
325 PlatformThread::Sleep(100);
326 loop.RunAllPending();
327
328 EXPECT_TRUE(run_time1.is_null());
329 EXPECT_FALSE(run_time2.is_null());
330}
331
332#if defined(OS_WIN)
333
334class SubPumpTask : public Task {
335 public:
336 virtual void Run() {
337 MessageLoop::current()->SetNestableTasksAllowed(true);
338 MSG msg;
[email protected]32cda29d2008-10-09 23:58:43339 while (GetMessage(&msg, NULL, 0, 0)) {
[email protected]72deacd2008-09-23 19:19:20340 TranslateMessage(&msg);
341 DispatchMessage(&msg);
342 }
343 MessageLoop::current()->Quit();
344 }
345};
346
347class SubPumpQuitTask : public Task {
348 public:
349 SubPumpQuitTask() {
350 }
351 virtual void Run() {
352 PostQuitMessage(0);
353 }
354};
355
356void RunTest_PostDelayedTask_SharedTimer_SubPump() {
357 MessageLoop loop(MessageLoop::TYPE_UI);
358
359 // Test that the interval of the timer, used to run the next delayed task, is
360 // set to a value corresponding to when the next delayed task should run.
361
362 // By setting num_tasks to 1, we ensure that the first task to run causes the
363 // run loop to exit.
364 int num_tasks = 1;
365 Time run_time;
366
367 loop.PostTask(FROM_HERE, new SubPumpTask());
368
369 // This very delayed task should never run.
370 loop.PostDelayedTask(
371 FROM_HERE, new RecordRunTimeTask(&run_time, &num_tasks), 1000000);
372
373 // This slightly delayed task should run from within SubPumpTask::Run().
374 loop.PostDelayedTask(
375 FROM_HERE, new SubPumpQuitTask(), 10);
376
377 Time start_time = Time::Now();
378
379 loop.Run();
380 EXPECT_EQ(1, num_tasks);
381
382 // Ensure that we ran in far less time than the slower timer.
[email protected]4615f1982008-09-23 19:22:33383 TimeDelta total_time = Time::Now() - start_time;
384 EXPECT_GT(5000, total_time.InMilliseconds());
[email protected]72deacd2008-09-23 19:19:20385
386 // In case both timers somehow run at nearly the same time, sleep a little
387 // and then run all pending to force them both to have run. This is just
388 // encouraging flakiness if there is any.
389 PlatformThread::Sleep(100);
390 loop.RunAllPending();
391
392 EXPECT_TRUE(run_time.is_null());
393}
394
395#endif // defined(OS_WIN)
396
[email protected]001747c2008-09-10 00:37:07397class RecordDeletionTask : public Task {
398 public:
399 RecordDeletionTask(Task* post_on_delete, bool* was_deleted)
400 : post_on_delete_(post_on_delete), was_deleted_(was_deleted) {
401 }
402 ~RecordDeletionTask() {
403 *was_deleted_ = true;
404 if (post_on_delete_)
405 MessageLoop::current()->PostTask(FROM_HERE, post_on_delete_);
406 }
407 virtual void Run() {}
408 private:
409 Task* post_on_delete_;
410 bool* was_deleted_;
411};
412
413void RunTest_EnsureTaskDeletion(MessageLoop::Type message_loop_type) {
414 bool a_was_deleted = false;
415 bool b_was_deleted = false;
416 {
417 MessageLoop loop(message_loop_type);
418 loop.PostTask(
419 FROM_HERE, new RecordDeletionTask(NULL, &a_was_deleted));
420 loop.PostDelayedTask(
421 FROM_HERE, new RecordDeletionTask(NULL, &b_was_deleted), 1000);
422 }
423 EXPECT_TRUE(a_was_deleted);
424 EXPECT_TRUE(b_was_deleted);
425}
426
427void RunTest_EnsureTaskDeletion_Chain(MessageLoop::Type message_loop_type) {
428 bool a_was_deleted = false;
429 bool b_was_deleted = false;
430 bool c_was_deleted = false;
431 {
432 MessageLoop loop(message_loop_type);
433 RecordDeletionTask* a = new RecordDeletionTask(NULL, &a_was_deleted);
434 RecordDeletionTask* b = new RecordDeletionTask(a, &b_was_deleted);
435 RecordDeletionTask* c = new RecordDeletionTask(b, &c_was_deleted);
436 loop.PostTask(FROM_HERE, c);
437 }
438 EXPECT_TRUE(a_was_deleted);
439 EXPECT_TRUE(b_was_deleted);
440 EXPECT_TRUE(c_was_deleted);
441}
442
initial.commitd7cae122008-07-26 21:49:38443class NestingTest : public Task {
444 public:
445 explicit NestingTest(int* depth) : depth_(depth) {
446 }
447 void Run() {
448 if (*depth_ > 0) {
449 *depth_ -= 1;
450 MessageLoop::current()->PostTask(FROM_HERE, new NestingTest(depth_));
451
452 MessageLoop::current()->SetNestableTasksAllowed(true);
453 MessageLoop::current()->Run();
454 }
455 MessageLoop::current()->Quit();
456 }
457 private:
458 int* depth_;
459};
460
[email protected]b16ef312008-08-19 18:36:23461#if defined(OS_WIN)
462
initial.commitd7cae122008-07-26 21:49:38463LONG WINAPI BadExceptionHandler(EXCEPTION_POINTERS *ex_info) {
464 ADD_FAILURE() << "bad exception handler";
465 ::ExitProcess(ex_info->ExceptionRecord->ExceptionCode);
466 return EXCEPTION_EXECUTE_HANDLER;
467}
468
469// This task throws an SEH exception: initially write to an invalid address.
470// If the right SEH filter is installed, it will fix the error.
471class CrasherTask : public Task {
472 public:
473 // Ctor. If trash_SEH_handler is true, the task will override the unhandled
474 // exception handler with one sure to crash this test.
475 explicit CrasherTask(bool trash_SEH_handler)
476 : trash_SEH_handler_(trash_SEH_handler) {
477 }
478 void Run() {
[email protected]b16ef312008-08-19 18:36:23479 PlatformThread::Sleep(1);
initial.commitd7cae122008-07-26 21:49:38480 if (trash_SEH_handler_)
481 ::SetUnhandledExceptionFilter(&BadExceptionHandler);
482 // Generate a SEH fault. We do it in asm to make sure we know how to undo
483 // the damage.
[email protected]c88873922008-07-30 13:02:03484
485#if defined(_M_IX86)
486
initial.commitd7cae122008-07-26 21:49:38487 __asm {
488 mov eax, dword ptr [CrasherTask::bad_array_]
489 mov byte ptr [eax], 66
490 }
[email protected]c88873922008-07-30 13:02:03491
492#elif defined(_M_X64)
493
494 bad_array_[0] = 66;
495
[email protected]b16ef312008-08-19 18:36:23496#else
497#error "needs architecture support"
[email protected]c88873922008-07-30 13:02:03498#endif
499
initial.commitd7cae122008-07-26 21:49:38500 MessageLoop::current()->Quit();
501 }
502 // Points the bad array to a valid memory location.
503 static void FixError() {
504 bad_array_ = &valid_store_;
505 }
506
507 private:
508 bool trash_SEH_handler_;
509 static volatile char* bad_array_;
510 static char valid_store_;
511};
512
513volatile char* CrasherTask::bad_array_ = 0;
514char CrasherTask::valid_store_ = 0;
515
516// This SEH filter fixes the problem and retries execution. Fixing requires
517// that the last instruction: mov eax, [CrasherTask::bad_array_] to be retried
518// so we move the instruction pointer 5 bytes back.
519LONG WINAPI HandleCrasherTaskException(EXCEPTION_POINTERS *ex_info) {
520 if (ex_info->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
521 return EXCEPTION_EXECUTE_HANDLER;
522
523 CrasherTask::FixError();
[email protected]c88873922008-07-30 13:02:03524
525#if defined(_M_IX86)
526
initial.commitd7cae122008-07-26 21:49:38527 ex_info->ContextRecord->Eip -= 5;
[email protected]c88873922008-07-30 13:02:03528
529#elif defined(_M_X64)
530
531 ex_info->ContextRecord->Rip -= 5;
532
533#endif
534
initial.commitd7cae122008-07-26 21:49:38535 return EXCEPTION_CONTINUE_EXECUTION;
536}
537
[email protected]4d9bdfaf2008-08-26 05:53:57538void RunTest_Crasher(MessageLoop::Type message_loop_type) {
539 MessageLoop loop(message_loop_type);
[email protected]b16ef312008-08-19 18:36:23540
initial.commitd7cae122008-07-26 21:49:38541 if (::IsDebuggerPresent())
542 return;
543
544 LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
545 ::SetUnhandledExceptionFilter(&HandleCrasherTaskException);
546
547 MessageLoop::current()->PostTask(FROM_HERE, new CrasherTask(false));
548 MessageLoop::current()->set_exception_restoration(true);
549 MessageLoop::current()->Run();
550 MessageLoop::current()->set_exception_restoration(false);
551
552 ::SetUnhandledExceptionFilter(old_SEH_filter);
553}
554
[email protected]4d9bdfaf2008-08-26 05:53:57555void RunTest_CrasherNasty(MessageLoop::Type message_loop_type) {
556 MessageLoop loop(message_loop_type);
[email protected]32cda29d2008-10-09 23:58:43557
initial.commitd7cae122008-07-26 21:49:38558 if (::IsDebuggerPresent())
559 return;
560
561 LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
562 ::SetUnhandledExceptionFilter(&HandleCrasherTaskException);
563
564 MessageLoop::current()->PostTask(FROM_HERE, new CrasherTask(true));
565 MessageLoop::current()->set_exception_restoration(true);
566 MessageLoop::current()->Run();
567 MessageLoop::current()->set_exception_restoration(false);
568
569 ::SetUnhandledExceptionFilter(old_SEH_filter);
570}
571
[email protected]295039bd2008-08-15 04:32:57572#endif // defined(OS_WIN)
573
[email protected]4d9bdfaf2008-08-26 05:53:57574void RunTest_Nesting(MessageLoop::Type message_loop_type) {
575 MessageLoop loop(message_loop_type);
[email protected]c88873922008-07-30 13:02:03576
initial.commitd7cae122008-07-26 21:49:38577 int depth = 100;
578 MessageLoop::current()->PostTask(FROM_HERE, new NestingTest(&depth));
579 MessageLoop::current()->Run();
580 EXPECT_EQ(depth, 0);
581}
582
initial.commitd7cae122008-07-26 21:49:38583const wchar_t* const kMessageBoxTitle = L"MessageLoop Unit Test";
584
585enum TaskType {
586 MESSAGEBOX,
587 ENDDIALOG,
588 RECURSIVE,
589 TIMEDMESSAGELOOP,
590 QUITMESSAGELOOP,
591 ORDERERD,
592 PUMPS,
593};
594
595// Saves the order in which the tasks executed.
596struct TaskItem {
597 TaskItem(TaskType t, int c, bool s)
598 : type(t),
599 cookie(c),
600 start(s) {
601 }
602
603 TaskType type;
604 int cookie;
605 bool start;
606
607 bool operator == (const TaskItem& other) const {
608 return type == other.type && cookie == other.cookie && start == other.start;
609 }
610};
611
612typedef std::vector<TaskItem> TaskList;
613
614std::ostream& operator <<(std::ostream& os, TaskType type) {
615 switch (type) {
616 case MESSAGEBOX: os << "MESSAGEBOX"; break;
617 case ENDDIALOG: os << "ENDDIALOG"; break;
618 case RECURSIVE: os << "RECURSIVE"; break;
619 case TIMEDMESSAGELOOP: os << "TIMEDMESSAGELOOP"; break;
620 case QUITMESSAGELOOP: os << "QUITMESSAGELOOP"; break;
621 case ORDERERD: os << "ORDERERD"; break;
622 case PUMPS: os << "PUMPS"; break;
623 default:
624 NOTREACHED();
625 os << "Unknown TaskType";
626 break;
627 }
628 return os;
629}
630
631std::ostream& operator <<(std::ostream& os, const TaskItem& item) {
632 if (item.start)
633 return os << item.type << " " << item.cookie << " starts";
634 else
635 return os << item.type << " " << item.cookie << " ends";
636}
637
638// Saves the order the tasks ran.
639class OrderedTasks : public Task {
640 public:
641 OrderedTasks(TaskList* order, int cookie)
642 : order_(order),
643 type_(ORDERERD),
644 cookie_(cookie) {
645 }
646 OrderedTasks(TaskList* order, TaskType type, int cookie)
647 : order_(order),
648 type_(type),
649 cookie_(cookie) {
650 }
651
652 void RunStart() {
653 TaskItem item(type_, cookie_, true);
654 DLOG(INFO) << item;
655 order_->push_back(item);
656 }
657 void RunEnd() {
658 TaskItem item(type_, cookie_, false);
659 DLOG(INFO) << item;
660 order_->push_back(item);
661 }
662
663 virtual void Run() {
664 RunStart();
665 RunEnd();
666 }
667
668 protected:
669 TaskList* order() const {
670 return order_;
671 }
672
673 int cookie() const {
674 return cookie_;
675 }
676
677 private:
678 TaskList* order_;
679 TaskType type_;
680 int cookie_;
681};
682
[email protected]b16ef312008-08-19 18:36:23683#if defined(OS_WIN)
684
initial.commitd7cae122008-07-26 21:49:38685// MessageLoop implicitly start a "modal message loop". Modal dialog boxes,
686// common controls (like OpenFile) and StartDoc printing function can cause
687// implicit message loops.
688class MessageBoxTask : public OrderedTasks {
689 public:
690 MessageBoxTask(TaskList* order, int cookie, bool is_reentrant)
691 : OrderedTasks(order, MESSAGEBOX, cookie),
692 is_reentrant_(is_reentrant) {
693 }
694
695 virtual void Run() {
696 RunStart();
697 if (is_reentrant_)
698 MessageLoop::current()->SetNestableTasksAllowed(true);
699 MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK);
700 RunEnd();
701 }
702
703 private:
704 bool is_reentrant_;
705};
706
707// Will end the MessageBox.
708class EndDialogTask : public OrderedTasks {
709 public:
710 EndDialogTask(TaskList* order, int cookie)
711 : OrderedTasks(order, ENDDIALOG, cookie) {
712 }
713
714 virtual void Run() {
715 RunStart();
716 HWND window = GetActiveWindow();
717 if (window != NULL) {
718 EXPECT_NE(EndDialog(window, IDCONTINUE), 0);
719 // Cheap way to signal that the window wasn't found if RunEnd() isn't
720 // called.
721 RunEnd();
722 }
723 }
724};
725
[email protected]b16ef312008-08-19 18:36:23726#endif // defined(OS_WIN)
727
initial.commitd7cae122008-07-26 21:49:38728class RecursiveTask : public OrderedTasks {
729 public:
730 RecursiveTask(int depth, TaskList* order, int cookie, bool is_reentrant)
731 : OrderedTasks(order, RECURSIVE, cookie),
732 depth_(depth),
733 is_reentrant_(is_reentrant) {
734 }
735
736 virtual void Run() {
737 RunStart();
738 if (depth_ > 0) {
739 if (is_reentrant_)
740 MessageLoop::current()->SetNestableTasksAllowed(true);
741 MessageLoop::current()->PostTask(FROM_HERE,
742 new RecursiveTask(depth_ - 1, order(), cookie(), is_reentrant_));
743 }
744 RunEnd();
745 }
746
747 private:
748 int depth_;
749 bool is_reentrant_;
750};
751
752class QuitTask : public OrderedTasks {
753 public:
754 QuitTask(TaskList* order, int cookie)
755 : OrderedTasks(order, QUITMESSAGELOOP, cookie) {
756 }
757
758 virtual void Run() {
759 RunStart();
760 MessageLoop::current()->Quit();
761 RunEnd();
762 }
763};
764
[email protected]295039bd2008-08-15 04:32:57765#if defined(OS_WIN)
766
initial.commitd7cae122008-07-26 21:49:38767class Recursive2Tasks : public Task {
768 public:
769 Recursive2Tasks(MessageLoop* target,
770 HANDLE event,
771 bool expect_window,
772 TaskList* order,
773 bool is_reentrant)
774 : target_(target),
775 event_(event),
776 expect_window_(expect_window),
777 order_(order),
778 is_reentrant_(is_reentrant) {
779 }
780
781 virtual void Run() {
782 target_->PostTask(FROM_HERE,
783 new RecursiveTask(2, order_, 1, is_reentrant_));
784 target_->PostTask(FROM_HERE,
785 new MessageBoxTask(order_, 2, is_reentrant_));
786 target_->PostTask(FROM_HERE,
787 new RecursiveTask(2, order_, 3, is_reentrant_));
788 // The trick here is that for recursive task processing, this task will be
789 // ran _inside_ the MessageBox message loop, dismissing the MessageBox
790 // without a chance.
791 // For non-recursive task processing, this will be executed _after_ the
792 // MessageBox will have been dismissed by the code below, where
793 // expect_window_ is true.
794 target_->PostTask(FROM_HERE, new EndDialogTask(order_, 4));
795 target_->PostTask(FROM_HERE, new QuitTask(order_, 5));
796
797 // Enforce that every tasks are sent before starting to run the main thread
798 // message loop.
799 ASSERT_TRUE(SetEvent(event_));
800
801 // Poll for the MessageBox. Don't do this at home! At the speed we do it,
802 // you will never realize one MessageBox was shown.
803 for (; expect_window_;) {
804 HWND window = FindWindow(L"#32770", kMessageBoxTitle);
805 if (window) {
806 // Dismiss it.
807 for (;;) {
808 HWND button = FindWindowEx(window, NULL, L"Button", NULL);
809 if (button != NULL) {
810 EXPECT_TRUE(0 == SendMessage(button, WM_LBUTTONDOWN, 0, 0));
811 EXPECT_TRUE(0 == SendMessage(button, WM_LBUTTONUP, 0, 0));
812 break;
813 }
814 }
815 break;
816 }
817 }
818 }
819
820 private:
821 MessageLoop* target_;
822 HANDLE event_;
823 TaskList* order_;
824 bool expect_window_;
825 bool is_reentrant_;
826};
827
[email protected]295039bd2008-08-15 04:32:57828#endif // defined(OS_WIN)
829
[email protected]4d9bdfaf2008-08-26 05:53:57830void RunTest_RecursiveDenial1(MessageLoop::Type message_loop_type) {
831 MessageLoop loop(message_loop_type);
initial.commitd7cae122008-07-26 21:49:38832
initial.commitd7cae122008-07-26 21:49:38833 EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
834 TaskList order;
835 MessageLoop::current()->PostTask(FROM_HERE,
836 new RecursiveTask(2, &order, 1, false));
837 MessageLoop::current()->PostTask(FROM_HERE,
838 new RecursiveTask(2, &order, 2, false));
839 MessageLoop::current()->PostTask(FROM_HERE, new QuitTask(&order, 3));
840
841 MessageLoop::current()->Run();
842
843 // FIFO order.
[email protected]b16ef312008-08-19 18:36:23844 ASSERT_EQ(14U, order.size());
initial.commitd7cae122008-07-26 21:49:38845 EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
846 EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
847 EXPECT_EQ(order[ 2], TaskItem(RECURSIVE, 2, true));
848 EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 2, false));
849 EXPECT_EQ(order[ 4], TaskItem(QUITMESSAGELOOP, 3, true));
850 EXPECT_EQ(order[ 5], TaskItem(QUITMESSAGELOOP, 3, false));
851 EXPECT_EQ(order[ 6], TaskItem(RECURSIVE, 1, true));
852 EXPECT_EQ(order[ 7], TaskItem(RECURSIVE, 1, false));
853 EXPECT_EQ(order[ 8], TaskItem(RECURSIVE, 2, true));
854 EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 2, false));
855 EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, true));
856 EXPECT_EQ(order[11], TaskItem(RECURSIVE, 1, false));
857 EXPECT_EQ(order[12], TaskItem(RECURSIVE, 2, true));
858 EXPECT_EQ(order[13], TaskItem(RECURSIVE, 2, false));
859}
860
[email protected]4d9bdfaf2008-08-26 05:53:57861void RunTest_RecursiveSupport1(MessageLoop::Type message_loop_type) {
862 MessageLoop loop(message_loop_type);
[email protected]32cda29d2008-10-09 23:58:43863
initial.commitd7cae122008-07-26 21:49:38864 TaskList order;
865 MessageLoop::current()->PostTask(FROM_HERE,
866 new RecursiveTask(2, &order, 1, true));
867 MessageLoop::current()->PostTask(FROM_HERE,
868 new RecursiveTask(2, &order, 2, true));
869 MessageLoop::current()->PostTask(FROM_HERE,
870 new QuitTask(&order, 3));
871
872 MessageLoop::current()->Run();
873
874 // FIFO order.
[email protected]b16ef312008-08-19 18:36:23875 ASSERT_EQ(14U, order.size());
initial.commitd7cae122008-07-26 21:49:38876 EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
877 EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
878 EXPECT_EQ(order[ 2], TaskItem(RECURSIVE, 2, true));
879 EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 2, false));
880 EXPECT_EQ(order[ 4], TaskItem(QUITMESSAGELOOP, 3, true));
881 EXPECT_EQ(order[ 5], TaskItem(QUITMESSAGELOOP, 3, false));
882 EXPECT_EQ(order[ 6], TaskItem(RECURSIVE, 1, true));
883 EXPECT_EQ(order[ 7], TaskItem(RECURSIVE, 1, false));
884 EXPECT_EQ(order[ 8], TaskItem(RECURSIVE, 2, true));
885 EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 2, false));
886 EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, true));
887 EXPECT_EQ(order[11], TaskItem(RECURSIVE, 1, false));
888 EXPECT_EQ(order[12], TaskItem(RECURSIVE, 2, true));
889 EXPECT_EQ(order[13], TaskItem(RECURSIVE, 2, false));
890}
891
[email protected]295039bd2008-08-15 04:32:57892#if defined(OS_WIN)
893// TODO(darin): These tests need to be ported since they test critical
894// message loop functionality.
895
initial.commitd7cae122008-07-26 21:49:38896// A side effect of this test is the generation a beep. Sorry.
[email protected]4d9bdfaf2008-08-26 05:53:57897void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) {
898 MessageLoop loop(message_loop_type);
899
initial.commitd7cae122008-07-26 21:49:38900 Thread worker("RecursiveDenial2_worker");
[email protected]4d9bdfaf2008-08-26 05:53:57901 Thread::Options options;
902 options.message_loop_type = message_loop_type;
903 ASSERT_EQ(true, worker.StartWithOptions(options));
initial.commitd7cae122008-07-26 21:49:38904 TaskList order;
905 ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
906 worker.message_loop()->PostTask(FROM_HERE,
907 new Recursive2Tasks(MessageLoop::current(),
908 event,
909 true,
910 &order,
911 false));
912 // Let the other thread execute.
913 WaitForSingleObject(event, INFINITE);
914 MessageLoop::current()->Run();
915
916 ASSERT_EQ(order.size(), 17);
917 EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
918 EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
919 EXPECT_EQ(order[ 2], TaskItem(MESSAGEBOX, 2, true));
920 EXPECT_EQ(order[ 3], TaskItem(MESSAGEBOX, 2, false));
921 EXPECT_EQ(order[ 4], TaskItem(RECURSIVE, 3, true));
922 EXPECT_EQ(order[ 5], TaskItem(RECURSIVE, 3, false));
923 // When EndDialogTask is processed, the window is already dismissed, hence no
924 // "end" entry.
925 EXPECT_EQ(order[ 6], TaskItem(ENDDIALOG, 4, true));
926 EXPECT_EQ(order[ 7], TaskItem(QUITMESSAGELOOP, 5, true));
927 EXPECT_EQ(order[ 8], TaskItem(QUITMESSAGELOOP, 5, false));
928 EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 1, true));
929 EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, false));
930 EXPECT_EQ(order[11], TaskItem(RECURSIVE, 3, true));
931 EXPECT_EQ(order[12], TaskItem(RECURSIVE, 3, false));
932 EXPECT_EQ(order[13], TaskItem(RECURSIVE, 1, true));
933 EXPECT_EQ(order[14], TaskItem(RECURSIVE, 1, false));
934 EXPECT_EQ(order[15], TaskItem(RECURSIVE, 3, true));
935 EXPECT_EQ(order[16], TaskItem(RECURSIVE, 3, false));
936}
937
[email protected]4d9bdfaf2008-08-26 05:53:57938// A side effect of this test is the generation a beep. Sorry. This test also
939// needs to process windows messages on the current thread.
940void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) {
941 MessageLoop loop(message_loop_type);
942
initial.commitd7cae122008-07-26 21:49:38943 Thread worker("RecursiveSupport2_worker");
[email protected]4d9bdfaf2008-08-26 05:53:57944 Thread::Options options;
945 options.message_loop_type = message_loop_type;
946 ASSERT_EQ(true, worker.StartWithOptions(options));
initial.commitd7cae122008-07-26 21:49:38947 TaskList order;
948 ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
949 worker.message_loop()->PostTask(FROM_HERE,
950 new Recursive2Tasks(MessageLoop::current(),
951 event,
952 false,
953 &order,
954 true));
955 // Let the other thread execute.
956 WaitForSingleObject(event, INFINITE);
957 MessageLoop::current()->Run();
958
959 ASSERT_EQ(order.size(), 18);
960 EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
961 EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
962 EXPECT_EQ(order[ 2], TaskItem(MESSAGEBOX, 2, true));
963 // Note that this executes in the MessageBox modal loop.
964 EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 3, true));
965 EXPECT_EQ(order[ 4], TaskItem(RECURSIVE, 3, false));
966 EXPECT_EQ(order[ 5], TaskItem(ENDDIALOG, 4, true));
967 EXPECT_EQ(order[ 6], TaskItem(ENDDIALOG, 4, false));
968 EXPECT_EQ(order[ 7], TaskItem(MESSAGEBOX, 2, false));
969 /* The order can subtly change here. The reason is that when RecursiveTask(1)
970 is called in the main thread, if it is faster than getting to the
971 PostTask(FROM_HERE, QuitTask) execution, the order of task execution can
972 change. We don't care anyway that the order isn't correct.
973 EXPECT_EQ(order[ 8], TaskItem(QUITMESSAGELOOP, 5, true));
974 EXPECT_EQ(order[ 9], TaskItem(QUITMESSAGELOOP, 5, false));
975 EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, true));
976 EXPECT_EQ(order[11], TaskItem(RECURSIVE, 1, false));
977 */
978 EXPECT_EQ(order[12], TaskItem(RECURSIVE, 3, true));
979 EXPECT_EQ(order[13], TaskItem(RECURSIVE, 3, false));
980 EXPECT_EQ(order[14], TaskItem(RECURSIVE, 1, true));
981 EXPECT_EQ(order[15], TaskItem(RECURSIVE, 1, false));
982 EXPECT_EQ(order[16], TaskItem(RECURSIVE, 3, true));
983 EXPECT_EQ(order[17], TaskItem(RECURSIVE, 3, false));
984}
985
[email protected]295039bd2008-08-15 04:32:57986#endif // defined(OS_WIN)
987
initial.commitd7cae122008-07-26 21:49:38988class TaskThatPumps : public OrderedTasks {
989 public:
990 TaskThatPumps(TaskList* order, int cookie)
991 : OrderedTasks(order, PUMPS, cookie) {
992 }
993
994 virtual void Run() {
995 RunStart();
996 bool old_state = MessageLoop::current()->NestableTasksAllowed();
initial.commitd7cae122008-07-26 21:49:38997 MessageLoop::current()->SetNestableTasksAllowed(true);
[email protected]295039bd2008-08-15 04:32:57998 MessageLoop::current()->RunAllPending();
initial.commitd7cae122008-07-26 21:49:38999 MessageLoop::current()->SetNestableTasksAllowed(old_state);
1000 RunEnd();
1001 }
initial.commitd7cae122008-07-26 21:49:381002};
1003
initial.commitd7cae122008-07-26 21:49:381004// Tests that non nestable tasks run in FIFO if there are no nested loops.
[email protected]4d9bdfaf2008-08-26 05:53:571005void RunTest_NonNestableWithNoNesting(MessageLoop::Type message_loop_type) {
1006 MessageLoop loop(message_loop_type);
1007
initial.commitd7cae122008-07-26 21:49:381008 TaskList order;
1009
1010 Task* task = new OrderedTasks(&order, 1);
[email protected]752578562008-09-07 08:08:291011 MessageLoop::current()->PostNonNestableTask(FROM_HERE, task);
initial.commitd7cae122008-07-26 21:49:381012 MessageLoop::current()->PostTask(FROM_HERE, new OrderedTasks(&order, 2));
1013 MessageLoop::current()->PostTask(FROM_HERE, new QuitTask(&order, 3));
1014 MessageLoop::current()->Run();
1015
1016 // FIFO order.
[email protected]b16ef312008-08-19 18:36:231017 ASSERT_EQ(6U, order.size());
initial.commitd7cae122008-07-26 21:49:381018 EXPECT_EQ(order[ 0], TaskItem(ORDERERD, 1, true));
1019 EXPECT_EQ(order[ 1], TaskItem(ORDERERD, 1, false));
1020 EXPECT_EQ(order[ 2], TaskItem(ORDERERD, 2, true));
1021 EXPECT_EQ(order[ 3], TaskItem(ORDERERD, 2, false));
1022 EXPECT_EQ(order[ 4], TaskItem(QUITMESSAGELOOP, 3, true));
1023 EXPECT_EQ(order[ 5], TaskItem(QUITMESSAGELOOP, 3, false));
1024}
1025
1026// Tests that non nestable tasks don't run when there's code in the call stack.
[email protected]4d9bdfaf2008-08-26 05:53:571027void RunTest_NonNestableInNestedLoop(MessageLoop::Type message_loop_type) {
1028 MessageLoop loop(message_loop_type);
1029
initial.commitd7cae122008-07-26 21:49:381030 TaskList order;
1031
1032 MessageLoop::current()->PostTask(FROM_HERE,
1033 new TaskThatPumps(&order, 1));
1034 Task* task = new OrderedTasks(&order, 2);
[email protected]752578562008-09-07 08:08:291035 MessageLoop::current()->PostNonNestableTask(FROM_HERE, task);
initial.commitd7cae122008-07-26 21:49:381036 MessageLoop::current()->PostTask(FROM_HERE, new OrderedTasks(&order, 3));
[email protected]5f800ed2008-08-14 01:09:181037 MessageLoop::current()->PostTask(FROM_HERE, new OrderedTasks(&order, 4));
initial.commitd7cae122008-07-26 21:49:381038 Task* non_nestable_quit = new QuitTask(&order, 5);
[email protected]752578562008-09-07 08:08:291039 MessageLoop::current()->PostNonNestableTask(FROM_HERE, non_nestable_quit);
initial.commitd7cae122008-07-26 21:49:381040
initial.commitd7cae122008-07-26 21:49:381041 MessageLoop::current()->Run();
1042
1043 // FIFO order.
[email protected]b16ef312008-08-19 18:36:231044 ASSERT_EQ(10U, order.size());
initial.commitd7cae122008-07-26 21:49:381045 EXPECT_EQ(order[ 0], TaskItem(PUMPS, 1, true));
1046 EXPECT_EQ(order[ 1], TaskItem(ORDERERD, 3, true));
1047 EXPECT_EQ(order[ 2], TaskItem(ORDERERD, 3, false));
[email protected]5f800ed2008-08-14 01:09:181048 EXPECT_EQ(order[ 3], TaskItem(ORDERERD, 4, true));
1049 EXPECT_EQ(order[ 4], TaskItem(ORDERERD, 4, false));
initial.commitd7cae122008-07-26 21:49:381050 EXPECT_EQ(order[ 5], TaskItem(PUMPS, 1, false));
1051 EXPECT_EQ(order[ 6], TaskItem(ORDERERD, 2, true));
1052 EXPECT_EQ(order[ 7], TaskItem(ORDERERD, 2, false));
1053 EXPECT_EQ(order[ 8], TaskItem(QUITMESSAGELOOP, 5, true));
1054 EXPECT_EQ(order[ 9], TaskItem(QUITMESSAGELOOP, 5, false));
1055}
1056
[email protected]295039bd2008-08-15 04:32:571057#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:381058
[email protected]4d9bdfaf2008-08-26 05:53:571059class AutoresetWatcher : public MessageLoopForIO::Watcher {
initial.commitd7cae122008-07-26 21:49:381060 public:
[email protected]32cda29d2008-10-09 23:58:431061 explicit AutoresetWatcher(HANDLE signal) : signal_(signal) {
[email protected]295039bd2008-08-15 04:32:571062 }
initial.commitd7cae122008-07-26 21:49:381063 virtual void OnObjectSignaled(HANDLE object);
1064 private:
1065 HANDLE signal_;
initial.commitd7cae122008-07-26 21:49:381066};
1067
1068void AutoresetWatcher::OnObjectSignaled(HANDLE object) {
[email protected]4d9bdfaf2008-08-26 05:53:571069 MessageLoopForIO::current()->WatchObject(object, NULL);
initial.commitd7cae122008-07-26 21:49:381070 ASSERT_TRUE(SetEvent(signal_));
1071}
1072
1073class AutoresetTask : public Task {
1074 public:
[email protected]4d9bdfaf2008-08-26 05:53:571075 AutoresetTask(HANDLE object, MessageLoopForIO::Watcher* watcher)
initial.commitd7cae122008-07-26 21:49:381076 : object_(object), watcher_(watcher) {}
1077 virtual void Run() {
[email protected]4d9bdfaf2008-08-26 05:53:571078 MessageLoopForIO::current()->WatchObject(object_, watcher_);
initial.commitd7cae122008-07-26 21:49:381079 }
1080
1081 private:
1082 HANDLE object_;
[email protected]4d9bdfaf2008-08-26 05:53:571083 MessageLoopForIO::Watcher* watcher_;
initial.commitd7cae122008-07-26 21:49:381084};
1085
[email protected]4d9bdfaf2008-08-26 05:53:571086void RunTest_AutoresetEvents(MessageLoop::Type message_loop_type) {
1087 MessageLoop loop(message_loop_type);
initial.commitd7cae122008-07-26 21:49:381088
initial.commitd7cae122008-07-26 21:49:381089 SECURITY_ATTRIBUTES attributes;
1090 attributes.nLength = sizeof(attributes);
1091 attributes.bInheritHandle = false;
1092 attributes.lpSecurityDescriptor = NULL;
1093
1094 // Init an autoreset and a manual reset events.
1095 HANDLE autoreset = CreateEvent(&attributes, FALSE, FALSE, NULL);
1096 HANDLE callback_called = CreateEvent(&attributes, TRUE, FALSE, NULL);
1097 ASSERT_TRUE(NULL != autoreset);
1098 ASSERT_TRUE(NULL != callback_called);
1099
1100 Thread thread("Autoreset test");
[email protected]4d9bdfaf2008-08-26 05:53:571101 Thread::Options options;
1102 options.message_loop_type = message_loop_type;
1103 ASSERT_TRUE(thread.StartWithOptions(options));
initial.commitd7cae122008-07-26 21:49:381104
[email protected]4d9bdfaf2008-08-26 05:53:571105 MessageLoop* thread_loop = thread.message_loop();
1106 ASSERT_TRUE(NULL != thread_loop);
initial.commitd7cae122008-07-26 21:49:381107
[email protected]4d9bdfaf2008-08-26 05:53:571108 AutoresetWatcher watcher(callback_called);
initial.commitd7cae122008-07-26 21:49:381109 AutoresetTask* task = new AutoresetTask(autoreset, &watcher);
[email protected]4d9bdfaf2008-08-26 05:53:571110 thread_loop->PostTask(FROM_HERE, task);
initial.commitd7cae122008-07-26 21:49:381111 Sleep(100); // Make sure the thread runs and sleeps for lack of work.
1112
1113 ASSERT_TRUE(SetEvent(autoreset));
1114
1115 DWORD result = WaitForSingleObject(callback_called, 1000);
1116 EXPECT_EQ(WAIT_OBJECT_0, result);
1117
1118 thread.Stop();
1119}
1120
[email protected]4d9bdfaf2008-08-26 05:53:571121class DispatcherImpl : public MessageLoopForUI::Dispatcher {
initial.commitd7cae122008-07-26 21:49:381122 public:
1123 DispatcherImpl() : dispatch_count_(0) {}
1124
1125 virtual bool Dispatch(const MSG& msg) {
1126 ::TranslateMessage(&msg);
1127 ::DispatchMessage(&msg);
1128 return (++dispatch_count_ != 2);
1129 }
1130
1131 int dispatch_count_;
1132};
1133
[email protected]4d9bdfaf2008-08-26 05:53:571134void RunTest_Dispatcher(MessageLoop::Type message_loop_type) {
1135 MessageLoop loop(message_loop_type);
initial.commitd7cae122008-07-26 21:49:381136
initial.commitd7cae122008-07-26 21:49:381137 class MyTask : public Task {
1138 public:
1139 virtual void Run() {
1140 PostMessage(NULL, WM_LBUTTONDOWN, 0, 0);
1141 PostMessage(NULL, WM_LBUTTONUP, 'A', 0);
1142 }
1143 };
1144 Task* task = new MyTask();
1145 MessageLoop::current()->PostDelayedTask(FROM_HERE, task, 100);
1146 DispatcherImpl dispatcher;
[email protected]4d9bdfaf2008-08-26 05:53:571147 MessageLoopForUI::current()->Run(&dispatcher);
initial.commitd7cae122008-07-26 21:49:381148 ASSERT_EQ(2, dispatcher.dispatch_count_);
1149}
[email protected]295039bd2008-08-15 04:32:571150
[email protected]32cda29d2008-10-09 23:58:431151class TestIOHandler : public MessageLoopForIO::IOHandler {
1152 public:
1153 TestIOHandler(const wchar_t* name, HANDLE signal);
1154
1155 virtual void OnIOCompleted(OVERLAPPED* context, DWORD bytes_transfered,
1156 DWORD error);
1157
1158 HANDLE file() { return file_.Get(); }
1159 void* buffer() { return buffer_; }
1160 OVERLAPPED* context() { return &context_; }
1161 DWORD size() { return sizeof(buffer_); }
1162
1163 private:
1164 char buffer_[48];
1165 OVERLAPPED context_;
1166 HANDLE signal_;
1167 ScopedHandle file_;
1168 ScopedHandle event_;
1169};
1170
1171TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal)
1172 : signal_(signal) {
1173 memset(buffer_, 0, sizeof(buffer_));
1174 memset(&context_, 0, sizeof(context_));
1175
1176 event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
1177 EXPECT_TRUE(event_.IsValid());
1178 context_.hEvent = event_.Get();
1179
1180 file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1181 FILE_FLAG_OVERLAPPED, NULL));
1182 EXPECT_TRUE(file_.IsValid());
1183}
1184
1185void TestIOHandler::OnIOCompleted(OVERLAPPED* context, DWORD bytes_transfered,
1186 DWORD error) {
1187 ASSERT_TRUE(context == &context_);
1188 MessageLoopForIO::current()->RegisterIOContext(context, NULL);
1189 ASSERT_TRUE(SetEvent(signal_));
1190}
1191
1192class IOHandlerTask : public Task {
1193 public:
1194 explicit IOHandlerTask(TestIOHandler* handler) : handler_(handler) {}
1195 virtual void Run();
1196
1197 private:
1198 TestIOHandler* handler_;
1199};
1200
1201void IOHandlerTask::Run() {
1202 MessageLoopForIO::current()->RegisterIOHandler(handler_->file(), handler_);
1203 MessageLoopForIO::current()->RegisterIOContext(handler_->context(), handler_);
1204
1205 DWORD read;
1206 EXPECT_FALSE(ReadFile(handler_->file(), handler_->buffer(), handler_->size(),
1207 &read, handler_->context()));
1208 EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
1209}
1210
1211void RunTest_IOHandler() {
1212 // This test requires an IO loop.
1213 MessageLoop loop(MessageLoop::TYPE_IO);
1214
1215 ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL));
1216 ASSERT_TRUE(callback_called.IsValid());
1217
1218 const wchar_t* kPipeName = L"\\\\.\\pipe\\iohandler_pipe";
1219 ScopedHandle server(CreateNamedPipe(kPipeName, PIPE_ACCESS_OUTBOUND, 0, 1,
1220 0, 0, 0, NULL));
1221 ASSERT_TRUE(server.IsValid());
1222
1223 Thread thread("IOHandler test");
1224 Thread::Options options;
1225 options.message_loop_type = MessageLoop::TYPE_IO;
1226 ASSERT_TRUE(thread.StartWithOptions(options));
1227
1228 MessageLoop* thread_loop = thread.message_loop();
1229 ASSERT_TRUE(NULL != thread_loop);
1230
1231 TestIOHandler handler(kPipeName, callback_called);
1232 IOHandlerTask* task = new IOHandlerTask(&handler);
1233 thread_loop->PostTask(FROM_HERE, task);
1234 Sleep(100); // Make sure the thread runs and sleeps for lack of work.
1235
1236 const char buffer[] = "Hello there!";
1237 DWORD written;
1238 EXPECT_TRUE(WriteFile(server, buffer, sizeof(buffer), &written, NULL));
1239
1240 DWORD result = WaitForSingleObject(callback_called, 1000);
1241 EXPECT_EQ(WAIT_OBJECT_0, result);
1242
1243 thread.Stop();
1244}
1245
[email protected]4d9bdfaf2008-08-26 05:53:571246#endif // defined(OS_WIN)
license.botbf09a502008-08-24 00:55:551247
[email protected]4d9bdfaf2008-08-26 05:53:571248} // namespace
1249
1250//-----------------------------------------------------------------------------
1251// Each test is run against each type of MessageLoop. That way we are sure
1252// that message loops work properly in all configurations. Of course, in some
1253// cases, a unit test may only be for a particular type of loop.
1254
1255TEST(MessageLoopTest, PostTask) {
1256 RunTest_PostTask(MessageLoop::TYPE_DEFAULT);
1257 RunTest_PostTask(MessageLoop::TYPE_UI);
1258 RunTest_PostTask(MessageLoop::TYPE_IO);
1259}
1260
1261TEST(MessageLoopTest, PostTask_SEH) {
1262 RunTest_PostTask_SEH(MessageLoop::TYPE_DEFAULT);
1263 RunTest_PostTask_SEH(MessageLoop::TYPE_UI);
1264 RunTest_PostTask_SEH(MessageLoop::TYPE_IO);
1265}
1266
[email protected]752578562008-09-07 08:08:291267TEST(MessageLoopTest, PostDelayedTask_Basic) {
1268 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_DEFAULT);
1269 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_UI);
1270 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_IO);
1271}
1272
1273TEST(MessageLoopTest, PostDelayedTask_InDelayOrder) {
1274 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_DEFAULT);
1275 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_UI);
1276 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_IO);
1277}
1278
1279TEST(MessageLoopTest, PostDelayedTask_InPostOrder) {
1280 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_DEFAULT);
1281 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_UI);
1282 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_IO);
1283}
1284
1285TEST(MessageLoopTest, PostDelayedTask_InPostOrder_2) {
1286 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_DEFAULT);
1287 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_UI);
1288 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_IO);
1289}
1290
1291TEST(MessageLoopTest, PostDelayedTask_InPostOrder_3) {
1292 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_DEFAULT);
1293 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_UI);
1294 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_IO);
1295}
1296
[email protected]72deacd2008-09-23 19:19:201297TEST(MessageLoopTest, PostDelayedTask_SharedTimer) {
1298 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_DEFAULT);
1299 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_UI);
1300 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_IO);
1301}
1302
1303#if defined(OS_WIN)
1304TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) {
1305 RunTest_PostDelayedTask_SharedTimer_SubPump();
1306}
1307#endif
1308
[email protected]327a4c22008-09-10 01:03:531309// TODO(darin): re-enable these tests once MessageLoop supports them again.
1310#if 0
[email protected]001747c2008-09-10 00:37:071311TEST(MessageLoopTest, EnsureTaskDeletion) {
1312 RunTest_EnsureTaskDeletion(MessageLoop::TYPE_DEFAULT);
1313 RunTest_EnsureTaskDeletion(MessageLoop::TYPE_UI);
1314 RunTest_EnsureTaskDeletion(MessageLoop::TYPE_IO);
1315}
1316
1317TEST(MessageLoopTest, EnsureTaskDeletion_Chain) {
1318 RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_DEFAULT);
1319 RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_UI);
1320 RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_IO);
1321}
[email protected]327a4c22008-09-10 01:03:531322#endif
[email protected]001747c2008-09-10 00:37:071323
[email protected]4d9bdfaf2008-08-26 05:53:571324#if defined(OS_WIN)
1325TEST(MessageLoopTest, Crasher) {
1326 RunTest_Crasher(MessageLoop::TYPE_DEFAULT);
1327 RunTest_Crasher(MessageLoop::TYPE_UI);
1328 RunTest_Crasher(MessageLoop::TYPE_IO);
1329}
1330
1331TEST(MessageLoopTest, CrasherNasty) {
1332 RunTest_CrasherNasty(MessageLoop::TYPE_DEFAULT);
1333 RunTest_CrasherNasty(MessageLoop::TYPE_UI);
1334 RunTest_CrasherNasty(MessageLoop::TYPE_IO);
1335}
1336#endif // defined(OS_WIN)
1337
1338TEST(MessageLoopTest, Nesting) {
1339 RunTest_Nesting(MessageLoop::TYPE_DEFAULT);
1340 RunTest_Nesting(MessageLoop::TYPE_UI);
1341 RunTest_Nesting(MessageLoop::TYPE_IO);
1342}
1343
1344TEST(MessageLoopTest, RecursiveDenial1) {
1345 RunTest_RecursiveDenial1(MessageLoop::TYPE_DEFAULT);
1346 RunTest_RecursiveDenial1(MessageLoop::TYPE_UI);
1347 RunTest_RecursiveDenial1(MessageLoop::TYPE_IO);
1348}
1349
1350TEST(MessageLoopTest, RecursiveSupport1) {
1351 RunTest_RecursiveSupport1(MessageLoop::TYPE_DEFAULT);
1352 RunTest_RecursiveSupport1(MessageLoop::TYPE_UI);
1353 RunTest_RecursiveSupport1(MessageLoop::TYPE_IO);
1354}
1355
1356#if defined(OS_WIN)
1357TEST(MessageLoopTest, RecursiveDenial2) {
1358 RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT);
1359 RunTest_RecursiveDenial2(MessageLoop::TYPE_UI);
1360 RunTest_RecursiveDenial2(MessageLoop::TYPE_IO);
1361}
1362
1363TEST(MessageLoopTest, RecursiveSupport2) {
1364 // This test requires a UI loop
1365 RunTest_RecursiveSupport2(MessageLoop::TYPE_UI);
1366}
1367#endif // defined(OS_WIN)
1368
1369TEST(MessageLoopTest, NonNestableWithNoNesting) {
1370 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_DEFAULT);
1371 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_UI);
1372 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_IO);
1373}
1374
1375TEST(MessageLoopTest, NonNestableInNestedLoop) {
1376 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT);
1377 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI);
1378 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO);
1379}
1380
1381#if defined(OS_WIN)
1382TEST(MessageLoopTest, AutoresetEvents) {
1383 // This test requires an IO loop
1384 RunTest_AutoresetEvents(MessageLoop::TYPE_IO);
1385}
1386
1387TEST(MessageLoopTest, Dispatcher) {
1388 // This test requires a UI loop
1389 RunTest_Dispatcher(MessageLoop::TYPE_UI);
1390}
[email protected]32cda29d2008-10-09 23:58:431391
1392TEST(MessageLoopTest, IOHandler) {
1393 RunTest_IOHandler();
1394}
[email protected]4d9bdfaf2008-08-26 05:53:571395#endif // defined(OS_WIN)