1// Copyright (c) 2012 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 "base/synchronization/waitable_event_watcher.h"
6
7#include "base/bind.h"
8#include "base/callback.h"
9#include "base/message_loop/message_loop.h"
10#include "base/run_loop.h"
11#include "base/synchronization/waitable_event.h"
12#include "base/threading/platform_thread.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15namespace base {
16
17namespace {
18
19// The message loops on which each waitable event timer should be tested.
20const MessageLoop::Type testing_message_loops[] = {
21  MessageLoop::TYPE_DEFAULT,
22  MessageLoop::TYPE_IO,
23#if !defined(OS_IOS)  // iOS does not allow direct running of the UI loop.
24  MessageLoop::TYPE_UI,
25#endif
26};
27
28const int kNumTestingMessageLoops = arraysize(testing_message_loops);
29
30void QuitWhenSignaled(WaitableEvent* event) {
31  MessageLoop::current()->QuitWhenIdle();
32}
33
34class DecrementCountContainer {
35 public:
36  explicit DecrementCountContainer(int* counter) : counter_(counter) {
37  }
38  void OnWaitableEventSignaled(WaitableEvent* object) {
39    --(*counter_);
40  }
41 private:
42  int* counter_;
43};
44
45void RunTest_BasicSignal(MessageLoop::Type message_loop_type) {
46  MessageLoop message_loop(message_loop_type);
47
48  // A manual-reset event that is not yet signaled.
49  WaitableEvent event(true, false);
50
51  WaitableEventWatcher watcher;
52  EXPECT_TRUE(watcher.GetWatchedEvent() == NULL);
53
54  watcher.StartWatching(&event, Bind(&QuitWhenSignaled));
55  EXPECT_EQ(&event, watcher.GetWatchedEvent());
56
57  event.Signal();
58
59  MessageLoop::current()->Run();
60
61  EXPECT_TRUE(watcher.GetWatchedEvent() == NULL);
62}
63
64void RunTest_BasicCancel(MessageLoop::Type message_loop_type) {
65  MessageLoop message_loop(message_loop_type);
66
67  // A manual-reset event that is not yet signaled.
68  WaitableEvent event(true, false);
69
70  WaitableEventWatcher watcher;
71
72  watcher.StartWatching(&event, Bind(&QuitWhenSignaled));
73
74  watcher.StopWatching();
75}
76
77void RunTest_CancelAfterSet(MessageLoop::Type message_loop_type) {
78  MessageLoop message_loop(message_loop_type);
79
80  // A manual-reset event that is not yet signaled.
81  WaitableEvent event(true, false);
82
83  WaitableEventWatcher watcher;
84
85  int counter = 1;
86  DecrementCountContainer delegate(&counter);
87  WaitableEventWatcher::EventCallback callback =
88      Bind(&DecrementCountContainer::OnWaitableEventSignaled,
89           Unretained(&delegate));
90  watcher.StartWatching(&event, callback);
91
92  event.Signal();
93
94  // Let the background thread do its business
95  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30));
96
97  watcher.StopWatching();
98
99  RunLoop().RunUntilIdle();
100
101  // Our delegate should not have fired.
102  EXPECT_EQ(1, counter);
103}
104
105void RunTest_OutlivesMessageLoop(MessageLoop::Type message_loop_type) {
106  // Simulate a MessageLoop that dies before an WaitableEventWatcher.  This
107  // ordinarily doesn't happen when people use the Thread class, but it can
108  // happen when people use the Singleton pattern or atexit.
109  WaitableEvent event(true, false);
110  {
111    WaitableEventWatcher watcher;
112    {
113      MessageLoop message_loop(message_loop_type);
114
115      watcher.StartWatching(&event, Bind(&QuitWhenSignaled));
116    }
117  }
118}
119
120void RunTest_DeleteUnder(MessageLoop::Type message_loop_type) {
121  // Delete the WaitableEvent out from under the Watcher. This is explictly
122  // allowed by the interface.
123
124  MessageLoop message_loop(message_loop_type);
125
126  {
127    WaitableEventWatcher watcher;
128
129    WaitableEvent* event = new WaitableEvent(false, false);
130
131    watcher.StartWatching(event, Bind(&QuitWhenSignaled));
132    delete event;
133  }
134}
135
136}  // namespace
137
138//-----------------------------------------------------------------------------
139
140TEST(WaitableEventWatcherTest, BasicSignal) {
141  for (int i = 0; i < kNumTestingMessageLoops; i++) {
142    RunTest_BasicSignal(testing_message_loops[i]);
143  }
144}
145
146TEST(WaitableEventWatcherTest, BasicCancel) {
147  for (int i = 0; i < kNumTestingMessageLoops; i++) {
148    RunTest_BasicCancel(testing_message_loops[i]);
149  }
150}
151
152TEST(WaitableEventWatcherTest, CancelAfterSet) {
153  for (int i = 0; i < kNumTestingMessageLoops; i++) {
154    RunTest_CancelAfterSet(testing_message_loops[i]);
155  }
156}
157
158TEST(WaitableEventWatcherTest, OutlivesMessageLoop) {
159  for (int i = 0; i < kNumTestingMessageLoops; i++) {
160    RunTest_OutlivesMessageLoop(testing_message_loops[i]);
161  }
162}
163
164#if defined(OS_WIN)
165// Crashes sometimes on vista.  http://crbug.com/62119
166#define MAYBE_DeleteUnder DISABLED_DeleteUnder
167#else
168#define MAYBE_DeleteUnder DeleteUnder
169#endif
170TEST(WaitableEventWatcherTest, MAYBE_DeleteUnder) {
171  for (int i = 0; i < kNumTestingMessageLoops; i++) {
172    RunTest_DeleteUnder(testing_message_loops[i]);
173  }
174}
175
176}  // namespace base
177