OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "ash/system/logout_button/logout_button_tray.h" | |
6 | |
7 #include <queue> | |
8 #include <utility> | |
9 #include <vector> | |
10 | |
11 #include "ash/system/status_area_widget.h" | |
12 #include "base/callback.h" | |
13 #include "base/logging.h" | |
14 #include "base/memory/ref_counted.h" | |
15 #include "base/single_thread_task_runner.h" | |
16 #include "base/thread_task_runner_handle.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 #include "ui/events/event.h" | |
19 #include "ui/events/keycodes/keyboard_codes.h" | |
20 #include "ui/views/controls/button/label_button.h" | |
21 | |
22 namespace ash { | |
23 namespace internal { | |
24 | |
25 class LogoutConfirmationDialogTest; | |
26 | |
27 namespace { | |
28 | |
29 // A SingleThreadTaskRunner that mocks the current time and allows it to be | |
30 // fast-forwarded. | |
31 // TODO: crbug.com/329911 | |
32 // Move shared copies of this class to one place. | |
33 class MockTimeSingleThreadTaskRunner : public base::SingleThreadTaskRunner { | |
34 public: | |
35 MockTimeSingleThreadTaskRunner(); | |
36 | |
37 // base::SingleThreadTaskRunner: | |
38 virtual bool RunsTasksOnCurrentThread() const OVERRIDE; | |
39 virtual bool PostDelayedTask(const tracked_objects::Location& from_here, | |
40 const base::Closure& task, | |
41 base::TimeDelta delay) OVERRIDE; | |
42 virtual bool PostNonNestableDelayedTask( | |
43 const tracked_objects::Location& from_here, | |
44 const base::Closure& task, | |
45 base::TimeDelta delay) OVERRIDE; | |
46 | |
47 const base::TimeTicks& GetCurrentTime() const; | |
48 | |
49 void FastForwardBy(base::TimeDelta delta); | |
50 void FastForwardUntilNoTasksRemain(); | |
51 | |
52 private: | |
53 // Strict weak temporal ordering of tasks. | |
54 class TemporalOrder { | |
55 public: | |
56 bool operator()( | |
57 const std::pair<base::TimeTicks, base::Closure>& first_task, | |
58 const std::pair<base::TimeTicks, base::Closure>& second_task) const; | |
59 }; | |
60 | |
61 virtual ~MockTimeSingleThreadTaskRunner(); | |
62 | |
63 base::TimeTicks now_; | |
64 std::priority_queue<std::pair<base::TimeTicks, base::Closure>, | |
65 std::vector<std::pair<base::TimeTicks, base::Closure> >, | |
66 TemporalOrder> tasks_; | |
67 }; | |
68 | |
69 MockTimeSingleThreadTaskRunner::MockTimeSingleThreadTaskRunner() { | |
70 } | |
71 | |
72 bool MockTimeSingleThreadTaskRunner::RunsTasksOnCurrentThread() const { | |
73 return true; | |
74 } | |
75 | |
76 bool MockTimeSingleThreadTaskRunner::PostDelayedTask( | |
77 const tracked_objects::Location& from_here, | |
78 const base::Closure& task, | |
79 base::TimeDelta delay) { | |
80 tasks_.push(std::pair<base::TimeTicks, base::Closure>(now_ + delay, task)); | |
81 return true; | |
82 } | |
83 | |
84 bool MockTimeSingleThreadTaskRunner::PostNonNestableDelayedTask( | |
85 const tracked_objects::Location& from_here, | |
86 const base::Closure& task, | |
87 base::TimeDelta delay) { | |
88 NOTREACHED(); | |
89 return false; | |
90 } | |
91 | |
92 const base::TimeTicks& MockTimeSingleThreadTaskRunner::GetCurrentTime() const { | |
93 return now_; | |
94 } | |
95 | |
96 void MockTimeSingleThreadTaskRunner::FastForwardBy(base::TimeDelta delta) { | |
97 const base::TimeTicks latest = now_ + delta; | |
98 while (!tasks_.empty() && tasks_.top().first <= latest) { | |
99 now_ = tasks_.top().first; | |
100 base::Closure task = tasks_.top().second; | |
101 tasks_.pop(); | |
102 task.Run(); | |
103 } | |
104 now_ = latest; | |
105 } | |
106 | |
107 void MockTimeSingleThreadTaskRunner::FastForwardUntilNoTasksRemain() { | |
108 while (!tasks_.empty()) { | |
109 now_ = tasks_.top().first; | |
110 base::Closure task = tasks_.top().second; | |
111 tasks_.pop(); | |
112 task.Run(); | |
113 } | |
114 } | |
115 | |
116 bool MockTimeSingleThreadTaskRunner::TemporalOrder::operator()( | |
117 const std::pair<base::TimeTicks, base::Closure>& first_task, | |
118 const std::pair<base::TimeTicks, base::Closure>& second_task) const { | |
119 return first_task.first > second_task.first; | |
120 } | |
121 | |
122 MockTimeSingleThreadTaskRunner::~MockTimeSingleThreadTaskRunner() { | |
123 } | |
124 | |
125 } // namespace | |
126 | |
127 class MockLogoutConfirmationDelegate | |
128 : public LogoutConfirmationDialogView::Delegate { | |
129 public: | |
130 MockLogoutConfirmationDelegate( | |
131 scoped_refptr<MockTimeSingleThreadTaskRunner> runner, | |
132 LogoutConfirmationDialogTest* tester); | |
133 | |
134 // LogoutConfirmationDialogView::Delegate: | |
135 virtual void LogoutCurrentUser() OVERRIDE; | |
136 virtual base::TimeTicks GetCurrentTime() const OVERRIDE; | |
137 virtual void ShowDialog(views::DialogDelegate* dialog) OVERRIDE; | |
138 | |
139 bool logout_called() const { return logout_called_; } | |
140 | |
141 private: | |
142 bool logout_called_; | |
143 | |
144 scoped_refptr<MockTimeSingleThreadTaskRunner> runner_; | |
145 scoped_ptr<views::DialogDelegate> dialog_ownership_holder_; | |
146 LogoutConfirmationDialogTest* tester_; | |
147 | |
148 DISALLOW_COPY_AND_ASSIGN(MockLogoutConfirmationDelegate); | |
149 }; | |
150 | |
151 class LogoutConfirmationDialogTest : public testing::Test { | |
152 public: | |
153 LogoutConfirmationDialogTest(); | |
154 virtual ~LogoutConfirmationDialogTest(); | |
155 | |
156 // testing::Test: | |
157 virtual void SetUp() OVERRIDE; | |
158 | |
159 void ChangeDialogDuration(base::TimeDelta duration); | |
160 | |
161 void CloseDialog(); | |
162 bool IsDialogShowing(); | |
163 void PressButton(); | |
164 void PressDialogButtonYes(); | |
165 | |
166 protected: | |
167 scoped_ptr<LogoutButtonTray> logout_button_; | |
168 scoped_refptr<MockTimeSingleThreadTaskRunner> runner_; | |
169 base::ThreadTaskRunnerHandle runner_handle_; | |
170 MockLogoutConfirmationDelegate* delegate_; | |
171 | |
172 private: | |
173 DISALLOW_COPY_AND_ASSIGN(LogoutConfirmationDialogTest); | |
174 }; | |
175 | |
176 MockLogoutConfirmationDelegate::MockLogoutConfirmationDelegate( | |
177 scoped_refptr<MockTimeSingleThreadTaskRunner> runner, | |
178 LogoutConfirmationDialogTest* tester) | |
179 : logout_called_(false), | |
180 runner_(runner), | |
181 tester_(tester) { | |
182 } | |
183 | |
184 void MockLogoutConfirmationDelegate::LogoutCurrentUser() { | |
185 logout_called_ = true; | |
186 tester_->CloseDialog(); | |
187 } | |
188 | |
189 base::TimeTicks MockLogoutConfirmationDelegate::GetCurrentTime() const { | |
190 return runner_->GetCurrentTime(); | |
191 } | |
192 | |
193 void MockLogoutConfirmationDelegate::ShowDialog(views::DialogDelegate* dialog) { | |
194 // Simulate the ownership passing of dialog in tests. | |
195 dialog_ownership_holder_.reset(dialog); | |
196 } | |
197 | |
198 LogoutConfirmationDialogTest::LogoutConfirmationDialogTest() | |
199 : runner_(new MockTimeSingleThreadTaskRunner), | |
200 runner_handle_(runner_) { | |
201 } | |
202 | |
203 LogoutConfirmationDialogTest::~LogoutConfirmationDialogTest() { | |
204 } | |
205 | |
206 void LogoutConfirmationDialogTest::SetUp() { | |
207 logout_button_.reset(new LogoutButtonTray(NULL)); | |
208 delegate_ = new MockLogoutConfirmationDelegate(runner_, this); | |
209 logout_button_->SetDelegateForTest( | |
210 scoped_ptr<LogoutConfirmationDialogView::Delegate>(delegate_)); | |
211 ChangeDialogDuration(base::TimeDelta::FromSeconds(20)); | |
212 } | |
213 | |
214 void LogoutConfirmationDialogTest::ChangeDialogDuration( | |
215 base::TimeDelta duration) { | |
216 logout_button_->OnLogoutDialogDurationChanged(duration); | |
217 } | |
218 | |
219 void LogoutConfirmationDialogTest::CloseDialog() { | |
220 if (logout_button_->confirmation_dialog_) | |
221 logout_button_->confirmation_dialog_->OnClosed(); | |
222 } | |
223 | |
224 bool LogoutConfirmationDialogTest::IsDialogShowing() { | |
225 return logout_button_->IsConfirmationDialogShowing(); | |
226 } | |
227 | |
228 void LogoutConfirmationDialogTest::PressButton() { | |
229 const ui::TranslatedKeyEvent faked_event( | |
230 false, | |
231 static_cast<ui::KeyboardCode>(0), | |
232 0); | |
233 logout_button_->ButtonPressed( | |
234 reinterpret_cast<views::Button*>(logout_button_->button_), faked_event); | |
235 } | |
236 | |
237 void LogoutConfirmationDialogTest::PressDialogButtonYes() { | |
238 logout_button_->confirmation_dialog_->Accept(); | |
239 // |confirmation_dialog_| might already be destroyed, if not, manually call | |
240 // OnClosed() to simulate real browser environment behavior. | |
241 if (logout_button_->confirmation_dialog_) | |
242 logout_button_->confirmation_dialog_->OnClosed(); | |
243 } | |
244 | |
245 TEST_F(LogoutConfirmationDialogTest, NoClickWithDefaultValue) { | |
246 PressButton(); | |
247 | |
248 // Verify that the dialog is showing immediately after the logout button was | |
249 // pressed. | |
250 runner_->FastForwardBy(base::TimeDelta::FromSeconds(0)); | |
251 EXPECT_TRUE(IsDialogShowing()); | |
252 EXPECT_FALSE(delegate_->logout_called()); | |
253 | |
254 // Verify that the dialog is still showing after 19 seconds since the logout | |
255 // button was pressed. | |
256 runner_->FastForwardBy(base::TimeDelta::FromSeconds(19)); | |
257 EXPECT_TRUE(IsDialogShowing()); | |
258 EXPECT_FALSE(delegate_->logout_called()); | |
259 | |
260 // Verify that the dialog is closed after 21 seconds since the logout button | |
261 // was pressed. | |
262 runner_->FastForwardBy(base::TimeDelta::FromSeconds(2)); | |
263 EXPECT_FALSE(IsDialogShowing()); | |
264 EXPECT_TRUE(delegate_->logout_called()); | |
265 } | |
266 | |
267 TEST_F(LogoutConfirmationDialogTest, ZeroPreferenceValue) { | |
268 ChangeDialogDuration(base::TimeDelta::FromSeconds(0)); | |
269 | |
270 EXPECT_FALSE(IsDialogShowing()); | |
271 | |
272 PressButton(); | |
273 | |
274 // Verify that user was logged out immediately after the logout button was | |
275 // pressed. | |
276 runner_->FastForwardBy(base::TimeDelta::FromSeconds(0)); | |
277 EXPECT_FALSE(IsDialogShowing()); | |
278 EXPECT_TRUE(delegate_->logout_called()); | |
279 | |
280 runner_->FastForwardUntilNoTasksRemain(); | |
281 EXPECT_FALSE(IsDialogShowing()); | |
282 } | |
283 | |
284 TEST_F(LogoutConfirmationDialogTest, OnTheFlyDialogDurationChange) { | |
285 ChangeDialogDuration(base::TimeDelta::FromSeconds(5)); | |
286 | |
287 EXPECT_FALSE(IsDialogShowing()); | |
288 | |
289 PressButton(); | |
290 | |
291 // Verify that the dialog is showing immediately after the logout button was | |
292 // pressed. | |
293 runner_->FastForwardBy(base::TimeDelta::FromSeconds(0)); | |
294 EXPECT_TRUE(IsDialogShowing()); | |
295 EXPECT_FALSE(delegate_->logout_called()); | |
296 | |
297 // Verify that the dialog is still showing after 3 seconds since the logout | |
298 // button was pressed. | |
299 runner_->FastForwardBy(base::TimeDelta::FromSeconds(3)); | |
300 EXPECT_TRUE(IsDialogShowing()); | |
301 EXPECT_FALSE(delegate_->logout_called()); | |
302 | |
303 // And at this point we change the dialog duration preference. | |
304 ChangeDialogDuration(base::TimeDelta::FromSeconds(10)); | |
305 | |
306 // Verify that the dialog is still showing after 9 seconds since the logout | |
307 // button was pressed, with dialog duration preference changed. | |
308 runner_->FastForwardBy(base::TimeDelta::FromSeconds(6)); | |
309 EXPECT_TRUE(IsDialogShowing()); | |
310 EXPECT_FALSE(delegate_->logout_called()); | |
311 | |
312 // Verify that the dialog is closed after 11 seconds since the logout button | |
313 // was pressed. | |
314 runner_->FastForwardBy(base::TimeDelta::FromSeconds(2)); | |
315 EXPECT_FALSE(IsDialogShowing()); | |
316 EXPECT_TRUE(delegate_->logout_called()); | |
317 } | |
318 | |
319 TEST_F(LogoutConfirmationDialogTest, UserClickedButton) { | |
320 PressButton(); | |
321 | |
322 // Verify that the dialog is showing immediately after the logout button was | |
323 // pressed. | |
324 runner_->FastForwardBy(base::TimeDelta::FromSeconds(0)); | |
325 EXPECT_TRUE(IsDialogShowing()); | |
326 EXPECT_FALSE(delegate_->logout_called()); | |
327 | |
328 // Verify that the dialog is still showing after 3 seconds since the logout | |
329 // button was pressed. | |
330 runner_->FastForwardBy(base::TimeDelta::FromSeconds(3)); | |
331 EXPECT_TRUE(IsDialogShowing()); | |
332 EXPECT_FALSE(delegate_->logout_called()); | |
333 | |
334 // And at this point we click the accept button. | |
335 PressDialogButtonYes(); | |
336 | |
337 // Verify that the user was logged out immediately after the accept button | |
338 // was clicked. | |
339 runner_->FastForwardBy(base::TimeDelta::FromSeconds(0)); | |
340 EXPECT_TRUE(delegate_->logout_called()); | |
341 } | |
342 | |
343 } // namespace internal | |
344 } // namespace ash | |
OLD | NEW |