Componentize AccountReconcilor.
[chromium-blink-merge.git] / chrome / browser / ui / fullscreen / fullscreen_controller_state_test.cc
blobc0d21de86b84e5d09faaf69465d07f9960a6f6ad
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.
5 #include "chrome/browser/ui/fullscreen/fullscreen_controller_state_test.h"
7 #include <memory.h>
9 #include <iomanip>
10 #include <iostream>
12 #include "chrome/browser/fullscreen.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/browser_window.h"
15 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
16 #include "chrome/browser/ui/fullscreen/fullscreen_controller_test.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/common/url_constants.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 #if defined(OS_MACOSX)
23 #include "base/mac/mac_util.h"
24 #endif
26 namespace {
28 bool SupportsMacSystemFullscreen() {
29 #if defined(OS_MACOSX)
30 return chrome::mac::SupportsSystemFullscreen();
31 #else
32 return false;
33 #endif
36 } // namespace
38 FullscreenControllerStateTest::FullscreenControllerStateTest()
39 : state_(STATE_NORMAL),
40 last_notification_received_state_(STATE_NORMAL) {
41 // Human specified state machine data.
42 // For each state, for each event, define the resulting state.
43 State transition_table_data[][NUM_EVENTS] = {
44 { // STATE_NORMAL:
45 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN
46 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TOGGLE_FULLSCREEN_CHROME
47 STATE_TO_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
48 STATE_NORMAL, // Event TAB_FULLSCREEN_FALSE
49 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
50 STATE_NORMAL, // Event METRO_SNAP_FALSE
51 STATE_NORMAL, // Event BUBBLE_EXIT_LINK
52 STATE_NORMAL, // Event BUBBLE_ALLOW
53 STATE_NORMAL, // Event BUBBLE_DENY
54 STATE_NORMAL, // Event WINDOW_CHANGE
56 { // STATE_BROWSER_FULLSCREEN_NO_CHROME:
57 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
58 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event TOGGLE_FULLSCREEN_CHROME
59 STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
60 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE
61 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
62 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event METRO_SNAP_FALSE
63 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
64 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_ALLOW
65 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_DENY
66 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event WINDOW_CHANGE
68 { // STATE_BROWSER_FULLSCREEN_WITH_CHROME:
69 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN
70 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
71 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event TAB_FULLSCREEN_TRUE
72 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event TAB_FULLSCREEN_FALSE
73 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event METRO_SNAP_TRUE
74 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event METRO_SNAP_FALSE
75 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
76 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_ALLOW
77 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_DENY
78 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event WINDOW_CHANGE
80 { // STATE_METRO_SNAP:
81 STATE_METRO_SNAP, // Event TOGGLE_FULLSCREEN
82 STATE_METRO_SNAP, // Event TOGGLE_FULLSCREEN_CHROME
83 STATE_METRO_SNAP, // Event TAB_FULLSCREEN_TRUE
84 STATE_METRO_SNAP, // Event TAB_FULLSCREEN_FALSE
85 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
86 STATE_NORMAL, // Event METRO_SNAP_FALSE
87 STATE_METRO_SNAP, // Event BUBBLE_EXIT_LINK
88 STATE_METRO_SNAP, // Event BUBBLE_ALLOW
89 STATE_METRO_SNAP, // Event BUBBLE_DENY
90 STATE_METRO_SNAP, // Event WINDOW_CHANGE
92 { // STATE_TAB_FULLSCREEN:
93 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
94 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
95 STATE_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
96 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE
97 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
98 STATE_TAB_FULLSCREEN, // Event METRO_SNAP_FALSE
99 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
100 STATE_TAB_FULLSCREEN, // Event BUBBLE_ALLOW
101 STATE_TO_NORMAL, // Event BUBBLE_DENY
102 STATE_TAB_FULLSCREEN, // Event WINDOW_CHANGE
104 { // STATE_TAB_BROWSER_FULLSCREEN:
105 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
106 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
107 STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
108 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE
109 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
110 STATE_TAB_BROWSER_FULLSCREEN, // Event METRO_SNAP_FALSE
111 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_EXIT_LINK
112 STATE_TAB_BROWSER_FULLSCREEN, // Event BUBBLE_ALLOW
113 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_DENY
114 STATE_TAB_BROWSER_FULLSCREEN, // Event WINDOW_CHANGE
116 { // STATE_TAB_BROWSER_FULLSCREEN_CHROME:
117 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
118 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
119 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event TAB_FULLSCREEN_TRUE
120 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event TAB_FULLSCREEN_FALSE
121 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
122 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event METRO_SNAP_FALSE
123 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_EXIT_LINK
124 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event BUBBLE_ALLOW
125 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_DENY
126 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event WINDOW_CHANGE
128 { // STATE_TO_NORMAL:
129 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
130 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TOGGLE_FULLSCREEN_CHROME
131 // TODO(scheib) Should be a route back to TAB. http://crbug.com/154196
132 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_TRUE
133 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE
134 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
135 STATE_TO_NORMAL, // Event METRO_SNAP_FALSE
136 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
137 STATE_TO_NORMAL, // Event BUBBLE_ALLOW
138 STATE_TO_NORMAL, // Event BUBBLE_DENY
139 STATE_NORMAL, // Event WINDOW_CHANGE
141 { // STATE_TO_BROWSER_FULLSCREEN_NO_CHROME:
142 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN
143 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TOGGLE_FULLSCREEN_CHROME
144 // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196
145 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_TRUE
146 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE
147 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
148 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event METRO_SNAP_FALSE
149 #if defined(OS_MACOSX)
150 // Mac window reports fullscreen immediately and an exit triggers exit.
151 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
152 #else
153 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_EXIT_LINK
154 #endif
155 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_ALLOW
156 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_DENY
157 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event WINDOW_CHANGE
159 { // STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME:
160 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN
161 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
162 // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196
163 STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
164 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TAB_FULLSCREEN_FALSE
165 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event METRO_SNAP_TRUE
166 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event METRO_SNAP_FALSE
167 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
168 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event BUBBLE_ALLOW
169 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event BUBBLE_DENY
170 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event WINDOW_CHANGE
172 { // STATE_TO_TAB_FULLSCREEN:
173 // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196
174 STATE_TO_TAB_FULLSCREEN, // Event TOGGLE_FULLSCREEN
175 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
176 STATE_TO_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
177 #if defined(OS_MACOSX)
178 // Mac runs as expected due to a forced NotifyTabOfExitIfNecessary();
179 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE
180 #else
181 // TODO(scheib) Should be a route back to NORMAL. http://crbug.com/154196
182 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE
183 #endif
184 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
185 STATE_TO_TAB_FULLSCREEN, // Event METRO_SNAP_FALSE
186 #if defined(OS_MACOSX)
187 // Mac window reports fullscreen immediately and an exit triggers exit.
188 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
189 #else
190 STATE_TO_TAB_FULLSCREEN, // Event BUBBLE_EXIT_LINK
191 #endif
192 STATE_TO_TAB_FULLSCREEN, // Event BUBBLE_ALLOW
193 #if defined(OS_MACOSX)
194 // Mac window reports fullscreen immediately and an exit triggers exit.
195 STATE_TO_NORMAL, // Event BUBBLE_DENY
196 #else
197 STATE_TO_TAB_FULLSCREEN, // Event BUBBLE_DENY
198 #endif
199 STATE_TAB_FULLSCREEN, // Event WINDOW_CHANGE
202 COMPILE_ASSERT(sizeof(transition_table_data) == sizeof(transition_table_),
203 transition_table_incorrect_size);
204 memcpy(transition_table_, transition_table_data,
205 sizeof(transition_table_data));
207 // Verify that transition_table_ has been completely defined.
208 for (int source = 0; source < NUM_STATES; ++source) {
209 for (int event = 0; event < NUM_EVENTS; ++event) {
210 EXPECT_NE(transition_table_[source][event], STATE_INVALID);
211 EXPECT_GE(transition_table_[source][event], 0);
212 EXPECT_LT(transition_table_[source][event], NUM_STATES);
216 // Copy transition_table_ data into state_transitions_ table.
217 for (int source = 0; source < NUM_STATES; ++source) {
218 for (int event = 0; event < NUM_EVENTS; ++event) {
219 if (ShouldSkipStateAndEventPair(static_cast<State>(source),
220 static_cast<Event>(event)))
221 continue;
222 State destination = transition_table_[source][event];
223 state_transitions_[source][destination].event = static_cast<Event>(event);
224 state_transitions_[source][destination].state = destination;
225 state_transitions_[source][destination].distance = 1;
230 FullscreenControllerStateTest::~FullscreenControllerStateTest() {
233 // static
234 const char* FullscreenControllerStateTest::GetStateString(State state) {
235 switch (state) {
236 ENUM_TO_STRING(STATE_NORMAL);
237 ENUM_TO_STRING(STATE_BROWSER_FULLSCREEN_NO_CHROME);
238 ENUM_TO_STRING(STATE_BROWSER_FULLSCREEN_WITH_CHROME);
239 ENUM_TO_STRING(STATE_METRO_SNAP);
240 ENUM_TO_STRING(STATE_TAB_FULLSCREEN);
241 ENUM_TO_STRING(STATE_TAB_BROWSER_FULLSCREEN);
242 ENUM_TO_STRING(STATE_TAB_BROWSER_FULLSCREEN_CHROME);
243 ENUM_TO_STRING(STATE_TO_NORMAL);
244 ENUM_TO_STRING(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME);
245 ENUM_TO_STRING(STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME);
246 ENUM_TO_STRING(STATE_TO_TAB_FULLSCREEN);
247 ENUM_TO_STRING(STATE_INVALID);
248 default:
249 NOTREACHED() << "No string for state " << state;
250 return "State-Unknown";
254 // static
255 const char* FullscreenControllerStateTest::GetEventString(Event event) {
256 switch (event) {
257 ENUM_TO_STRING(TOGGLE_FULLSCREEN);
258 ENUM_TO_STRING(TOGGLE_FULLSCREEN_CHROME);
259 ENUM_TO_STRING(TAB_FULLSCREEN_TRUE);
260 ENUM_TO_STRING(TAB_FULLSCREEN_FALSE);
261 ENUM_TO_STRING(METRO_SNAP_TRUE);
262 ENUM_TO_STRING(METRO_SNAP_FALSE);
263 ENUM_TO_STRING(BUBBLE_EXIT_LINK);
264 ENUM_TO_STRING(BUBBLE_ALLOW);
265 ENUM_TO_STRING(BUBBLE_DENY);
266 ENUM_TO_STRING(WINDOW_CHANGE);
267 ENUM_TO_STRING(EVENT_INVALID);
268 default:
269 NOTREACHED() << "No string for event " << event;
270 return "Event-Unknown";
274 // static
275 bool FullscreenControllerStateTest::IsWindowFullscreenStateChangedReentrant() {
276 #if defined(TOOLKIT_VIEWS)
277 return true;
278 #else
279 return false;
280 #endif
283 // static
284 bool FullscreenControllerStateTest::IsPersistentState(State state) {
285 switch (state) {
286 case STATE_NORMAL:
287 case STATE_BROWSER_FULLSCREEN_NO_CHROME:
288 case STATE_BROWSER_FULLSCREEN_WITH_CHROME:
289 case STATE_METRO_SNAP:
290 case STATE_TAB_FULLSCREEN:
291 case STATE_TAB_BROWSER_FULLSCREEN:
292 case STATE_TAB_BROWSER_FULLSCREEN_CHROME:
293 return true;
295 case STATE_TO_NORMAL:
296 case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME:
297 case STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME:
298 case STATE_TO_TAB_FULLSCREEN:
299 return false;
301 default:
302 NOTREACHED();
303 return false;
307 void FullscreenControllerStateTest::TransitionToState(State final_state) {
308 int max_steps = NUM_STATES;
309 while (max_steps-- && TransitionAStepTowardState(final_state))
310 continue;
311 ASSERT_GE(max_steps, 0) << "TransitionToState was unable to achieve desired "
312 << "target state. TransitionAStepTowardState iterated too many times."
313 << GetAndClearDebugLog();
314 ASSERT_EQ(final_state, state_) << "TransitionToState was unable to achieve "
315 << "desired target state. TransitionAStepTowardState returned false."
316 << GetAndClearDebugLog();
319 bool FullscreenControllerStateTest::TransitionAStepTowardState(
320 State destination_state) {
321 State source_state = state_;
322 if (source_state == destination_state)
323 return false;
325 StateTransitionInfo next = NextTransitionInShortestPath(source_state,
326 destination_state,
327 NUM_STATES);
328 if (next.state == STATE_INVALID) {
329 NOTREACHED() << "TransitionAStepTowardState unable to transition. "
330 << "NextTransitionInShortestPath("
331 << GetStateString(source_state) << ", "
332 << GetStateString(destination_state) << ") returned STATE_INVALID."
333 << GetAndClearDebugLog();
334 return false;
337 return InvokeEvent(next.event);
340 const char* FullscreenControllerStateTest::GetWindowStateString() {
341 return NULL;
344 bool FullscreenControllerStateTest::InvokeEvent(Event event) {
345 if (!fullscreen_notification_observer_.get()) {
346 // Start observing NOTIFICATION_FULLSCREEN_CHANGED. Construct the
347 // notification observer here instead of in
348 // FullscreenControllerStateTest::FullscreenControllerStateTest() so that we
349 // listen to notifications on the proper thread.
350 fullscreen_notification_observer_.reset(
351 new FullscreenNotificationObserver());
354 State source_state = state_;
355 State next_state = transition_table_[source_state][event];
357 EXPECT_FALSE(ShouldSkipStateAndEventPair(source_state, event))
358 << GetAndClearDebugLog();
360 // When simulating reentrant window change calls, expect the next state
361 // automatically.
362 if (IsWindowFullscreenStateChangedReentrant())
363 next_state = transition_table_[next_state][WINDOW_CHANGE];
365 debugging_log_ << " InvokeEvent(" << std::left
366 << std::setw(kMaxStateNameLength) << GetEventString(event)
367 << ") to "
368 << std::setw(kMaxStateNameLength) << GetStateString(next_state);
370 state_ = next_state;
372 switch (event) {
373 case TOGGLE_FULLSCREEN:
374 GetFullscreenController()->ToggleBrowserFullscreenMode();
375 break;
377 case TOGGLE_FULLSCREEN_CHROME:
378 #if defined(OS_MACOSX)
379 if (chrome::mac::SupportsSystemFullscreen()) {
380 GetFullscreenController()->ToggleBrowserFullscreenWithChrome();
381 break;
383 #endif
384 NOTREACHED() << GetAndClearDebugLog();
385 break;
387 case TAB_FULLSCREEN_TRUE:
388 case TAB_FULLSCREEN_FALSE: {
389 content::WebContents* const active_tab =
390 GetBrowser()->tab_strip_model()->GetActiveWebContents();
391 GetFullscreenController()->
392 ToggleFullscreenModeForTab(active_tab, event == TAB_FULLSCREEN_TRUE);
393 // Activating/Deactivating tab fullscreen on a captured tab should not
394 // evoke a state change in the browser window.
395 if (active_tab->GetCapturerCount() > 0)
396 state_ = source_state;
397 break;
400 case METRO_SNAP_TRUE:
401 #if defined(OS_WIN)
402 GetFullscreenController()->SetMetroSnapMode(true);
403 #else
404 NOTREACHED() << GetAndClearDebugLog();
405 #endif
406 break;
408 case METRO_SNAP_FALSE:
409 #if defined(OS_WIN)
410 GetFullscreenController()->SetMetroSnapMode(false);
411 #else
412 NOTREACHED() << GetAndClearDebugLog();
413 #endif
414 break;
416 case BUBBLE_EXIT_LINK:
417 GetFullscreenController()->ExitTabOrBrowserFullscreenToPreviousState();
418 break;
420 case BUBBLE_ALLOW:
421 GetFullscreenController()->OnAcceptFullscreenPermission();
422 break;
424 case BUBBLE_DENY:
425 GetFullscreenController()->OnDenyFullscreenPermission();
426 break;
428 case WINDOW_CHANGE:
429 ChangeWindowFullscreenState();
430 break;
432 default:
433 NOTREACHED() << "InvokeEvent needs a handler for event "
434 << GetEventString(event) << GetAndClearDebugLog();
435 return false;
438 if (GetWindowStateString())
439 debugging_log_ << " Window state now " << GetWindowStateString() << "\n";
440 else
441 debugging_log_ << "\n";
443 MaybeWaitForNotification();
444 VerifyWindowState();
446 return true;
449 void FullscreenControllerStateTest::VerifyWindowState() {
450 switch (state_) {
451 case STATE_NORMAL:
452 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
453 FULLSCREEN_WITHOUT_CHROME_FALSE,
454 FULLSCREEN_FOR_BROWSER_FALSE,
455 FULLSCREEN_FOR_TAB_FALSE,
456 IN_METRO_SNAP_FALSE);
457 break;
458 case STATE_BROWSER_FULLSCREEN_NO_CHROME:
459 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
460 FULLSCREEN_WITHOUT_CHROME_TRUE,
461 FULLSCREEN_FOR_BROWSER_TRUE,
462 FULLSCREEN_FOR_TAB_FALSE,
463 IN_METRO_SNAP_FALSE);
464 break;
465 case STATE_BROWSER_FULLSCREEN_WITH_CHROME:
466 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_TRUE,
467 FULLSCREEN_WITHOUT_CHROME_FALSE,
468 FULLSCREEN_FOR_BROWSER_TRUE,
469 FULLSCREEN_FOR_TAB_FALSE,
470 IN_METRO_SNAP_FALSE);
471 break;
472 case STATE_METRO_SNAP:
473 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_NO_EXPECTATION,
474 FULLSCREEN_WITHOUT_CHROME_NO_EXPECTATION,
475 FULLSCREEN_FOR_BROWSER_NO_EXPECTATION,
476 FULLSCREEN_FOR_TAB_NO_EXPECTATION,
477 IN_METRO_SNAP_TRUE);
478 break;
479 case STATE_TAB_FULLSCREEN:
480 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
481 FULLSCREEN_WITHOUT_CHROME_TRUE,
482 FULLSCREEN_FOR_BROWSER_FALSE,
483 FULLSCREEN_FOR_TAB_TRUE,
484 IN_METRO_SNAP_FALSE);
485 break;
486 case STATE_TAB_BROWSER_FULLSCREEN:
487 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
488 FULLSCREEN_WITHOUT_CHROME_TRUE,
489 FULLSCREEN_FOR_BROWSER_TRUE,
490 FULLSCREEN_FOR_TAB_TRUE,
491 IN_METRO_SNAP_FALSE);
492 break;
493 case STATE_TAB_BROWSER_FULLSCREEN_CHROME:
494 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
495 FULLSCREEN_WITHOUT_CHROME_TRUE,
496 FULLSCREEN_FOR_BROWSER_TRUE,
497 FULLSCREEN_FOR_TAB_TRUE,
498 IN_METRO_SNAP_FALSE);
499 break;
500 case STATE_TO_NORMAL:
501 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
502 FULLSCREEN_WITHOUT_CHROME_FALSE,
503 FULLSCREEN_FOR_BROWSER_NO_EXPECTATION,
504 FULLSCREEN_FOR_TAB_NO_EXPECTATION,
505 IN_METRO_SNAP_FALSE);
506 break;
508 case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME:
509 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
510 FULLSCREEN_WITHOUT_CHROME_TRUE,
511 #if defined(OS_MACOSX)
512 FULLSCREEN_FOR_BROWSER_TRUE,
513 #else
514 FULLSCREEN_FOR_BROWSER_FALSE,
515 #endif
516 FULLSCREEN_FOR_TAB_NO_EXPECTATION,
517 IN_METRO_SNAP_FALSE);
518 break;
520 case STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME:
521 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_TRUE,
522 FULLSCREEN_WITHOUT_CHROME_FALSE,
523 #if defined(OS_MACOSX)
524 FULLSCREEN_FOR_BROWSER_TRUE,
525 #else
526 FULLSCREEN_FOR_BROWSER_FALSE,
527 #endif
528 FULLSCREEN_FOR_TAB_NO_EXPECTATION,
529 IN_METRO_SNAP_FALSE);
530 break;
532 case STATE_TO_TAB_FULLSCREEN:
533 #if defined(OS_MACOSX)
534 // TODO(scheib) InPresentationMode returns false when invoking events:
535 // TAB_FULLSCREEN_TRUE, TOGGLE_FULLSCREEN. http://crbug.com/156645
536 // It may be that a new testing state TO_TAB_BROWSER_FULLSCREEN
537 // would help work around this http://crbug.com/154196
538 // Test with: STATE_TO_TAB_FULLSCREEN__TOGGLE_FULLSCREEN
540 // EXPECT_TRUE(GetBrowser()->window()->InPresentationMode())
541 // << GetAndClearDebugLog();
542 #endif
543 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_NO_EXPECTATION,
544 FULLSCREEN_WITHOUT_CHROME_NO_EXPECTATION,
545 FULLSCREEN_FOR_BROWSER_FALSE,
546 FULLSCREEN_FOR_TAB_TRUE,
547 IN_METRO_SNAP_FALSE);
548 break;
550 default:
551 NOTREACHED() << GetAndClearDebugLog();
555 void FullscreenControllerStateTest::MaybeWaitForNotification() {
556 // We should get a fullscreen notification each time we get to a new
557 // persistent state. If we don't get a notification, the test will
558 // fail by timing out.
559 if (state_ != last_notification_received_state_ &&
560 IsPersistentState(state_)) {
561 fullscreen_notification_observer_->Wait();
562 last_notification_received_state_ = state_;
563 fullscreen_notification_observer_.reset(
564 new FullscreenNotificationObserver());
568 void FullscreenControllerStateTest::TestTransitionsForEachState() {
569 for (int source_int = 0; source_int < NUM_STATES; ++source_int) {
570 for (int event1_int = 0; event1_int < NUM_EVENTS; ++event1_int) {
571 State state = static_cast<State>(source_int);
572 Event event1 = static_cast<Event>(event1_int);
574 // Early out if skipping all tests for this state, reduces log noise.
575 if (ShouldSkipTest(state, event1))
576 continue;
578 for (int event2_int = 0; event2_int < NUM_EVENTS; ++event2_int) {
579 for (int event3_int = 0; event3_int < NUM_EVENTS; ++event3_int) {
580 Event event2 = static_cast<Event>(event2_int);
581 Event event3 = static_cast<Event>(event3_int);
583 // Test each state and each event.
584 ASSERT_NO_FATAL_FAILURE(TestStateAndEvent(state, event1))
585 << GetAndClearDebugLog();
587 // Then, add an additional event to the sequence.
588 if (ShouldSkipStateAndEventPair(state_, event2))
589 continue;
590 ASSERT_TRUE(InvokeEvent(event2)) << GetAndClearDebugLog();
592 // Then, add an additional event to the sequence.
593 if (ShouldSkipStateAndEventPair(state_, event3))
594 continue;
595 ASSERT_TRUE(InvokeEvent(event3)) << GetAndClearDebugLog();
602 FullscreenControllerStateTest::StateTransitionInfo
603 FullscreenControllerStateTest::NextTransitionInShortestPath(
604 State source,
605 State destination,
606 int search_limit) {
607 if (search_limit <= 0)
608 return StateTransitionInfo(); // Return a default (invalid) state.
610 if (state_transitions_[source][destination].state == STATE_INVALID) {
611 // Don't know the next state yet, do a depth first search.
612 StateTransitionInfo result;
614 // Consider all states reachable via each event from the source state.
615 for (int event_int = 0; event_int < NUM_EVENTS; ++event_int) {
616 Event event = static_cast<Event>(event_int);
617 State next_state_candidate = transition_table_[source][event];
619 if (ShouldSkipStateAndEventPair(source, event))
620 continue;
622 // Recurse.
623 StateTransitionInfo candidate = NextTransitionInShortestPath(
624 next_state_candidate, destination, search_limit - 1);
626 if (candidate.distance + 1 < result.distance) {
627 result.event = event;
628 result.state = next_state_candidate;
629 result.distance = candidate.distance + 1;
633 // Cache result so that a search is not required next time.
634 state_transitions_[source][destination] = result;
637 return state_transitions_[source][destination];
640 std::string FullscreenControllerStateTest::GetAndClearDebugLog() {
641 debugging_log_ << "(End of Debugging Log)\n";
642 std::string output_log = "\nDebugging Log:\n" + debugging_log_.str();
643 debugging_log_.str(std::string());
644 return output_log;
647 bool FullscreenControllerStateTest::ShouldSkipStateAndEventPair(State state,
648 Event event) {
649 // TODO(scheib) Toggling Tab fullscreen while pending Tab or
650 // Browser fullscreen is broken currently http://crbug.com/154196
651 if ((state == STATE_TO_BROWSER_FULLSCREEN_NO_CHROME ||
652 state == STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME ||
653 state == STATE_TO_TAB_FULLSCREEN) &&
654 (event == TAB_FULLSCREEN_TRUE || event == TAB_FULLSCREEN_FALSE))
655 return true;
656 if (state == STATE_TO_NORMAL && event == TAB_FULLSCREEN_TRUE)
657 return true;
659 // Skip metro snap state and events when not on windows.
660 #if !defined(OS_WIN)
661 if (state == STATE_METRO_SNAP ||
662 event == METRO_SNAP_TRUE ||
663 event == METRO_SNAP_FALSE)
664 return true;
665 #endif
667 // Skip Mac Lion Fullscreen state and events when not on OSX 10.7+.
668 if (!SupportsMacSystemFullscreen()) {
669 if (state == STATE_BROWSER_FULLSCREEN_WITH_CHROME ||
670 state == STATE_TAB_BROWSER_FULLSCREEN_CHROME ||
671 state == STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME ||
672 event == TOGGLE_FULLSCREEN_CHROME) {
673 return true;
677 return false;
680 bool FullscreenControllerStateTest::ShouldSkipTest(State state, Event event) {
681 // Quietly skip metro snap tests when not on windows.
682 #if !defined(OS_WIN)
683 if (state == STATE_METRO_SNAP ||
684 event == METRO_SNAP_TRUE ||
685 event == METRO_SNAP_FALSE) {
686 debugging_log_ << "\nSkipping metro snap test on non-Windows.\n";
687 return true;
689 #endif
691 // Quietly skip Mac Lion Fullscreen tests when not on OSX 10.7+.
692 if (!SupportsMacSystemFullscreen()) {
693 if (state == STATE_BROWSER_FULLSCREEN_WITH_CHROME ||
694 event == TOGGLE_FULLSCREEN_CHROME) {
695 debugging_log_ << "\nSkipping Lion Fullscreen test on non-OSX 10.7+.\n";
696 return true;
700 // When testing reentrancy there are states the fullscreen controller
701 // will be unable to remain in, as they will progress due to the
702 // reentrant window change call. Skip states that will be instantly
703 // exited by the reentrant call.
704 if (IsWindowFullscreenStateChangedReentrant() &&
705 (transition_table_[state][WINDOW_CHANGE] != state)) {
706 debugging_log_ << "\nSkipping reentrant test for transitory source state "
707 << GetStateString(state) << ".\n";
708 return true;
711 if (ShouldSkipStateAndEventPair(state, event)) {
712 debugging_log_ << "\nSkipping test due to ShouldSkipStateAndEventPair("
713 << GetStateString(state) << ", "
714 << GetEventString(event) << ").\n";
715 LOG(INFO) << "Skipping test due to ShouldSkipStateAndEventPair("
716 << GetStateString(state) << ", "
717 << GetEventString(event) << ").";
718 return true;
721 return false;
724 void FullscreenControllerStateTest::TestStateAndEvent(State state,
725 Event event) {
726 if (ShouldSkipTest(state, event))
727 return;
729 debugging_log_ << "\nTest transition from state "
730 << GetStateString(state)
731 << (IsWindowFullscreenStateChangedReentrant() ?
732 " with reentrant calls.\n" : ".\n");
734 // Spaced out text to line up with columns printed in InvokeEvent().
735 debugging_log_ << "First, from "
736 << GetStateString(state_) << "\n";
737 ASSERT_NO_FATAL_FAILURE(TransitionToState(state))
738 << GetAndClearDebugLog();
740 debugging_log_ << " Then,\n";
741 ASSERT_TRUE(InvokeEvent(event)) << GetAndClearDebugLog();
744 void FullscreenControllerStateTest::VerifyWindowStateExpectations(
745 FullscreenWithChromeExpectation fullscreen_with_chrome,
746 FullscreenWithoutChromeExpectation fullscreen_without_chrome,
747 FullscreenForBrowserExpectation fullscreen_for_browser,
748 FullscreenForTabExpectation fullscreen_for_tab,
749 InMetroSnapExpectation in_metro_snap) {
750 #if defined(OS_MACOSX)
751 if (fullscreen_with_chrome != FULLSCREEN_WITH_CHROME_NO_EXPECTATION) {
752 EXPECT_EQ(GetBrowser()->window()->IsFullscreenWithChrome(),
753 !!fullscreen_with_chrome) << GetAndClearDebugLog();
755 if (fullscreen_without_chrome != FULLSCREEN_WITHOUT_CHROME_NO_EXPECTATION) {
756 EXPECT_EQ(GetBrowser()->window()->IsFullscreenWithoutChrome(),
757 !!fullscreen_without_chrome) << GetAndClearDebugLog();
759 #endif
760 if (fullscreen_for_browser != FULLSCREEN_FOR_BROWSER_NO_EXPECTATION) {
761 EXPECT_EQ(GetFullscreenController()->IsFullscreenForBrowser(),
762 !!fullscreen_for_browser) << GetAndClearDebugLog();
764 if (fullscreen_for_tab != FULLSCREEN_FOR_TAB_NO_EXPECTATION) {
765 EXPECT_EQ(GetFullscreenController()->IsWindowFullscreenForTabOrPending(),
766 !!fullscreen_for_tab) << GetAndClearDebugLog();
768 if (in_metro_snap != IN_METRO_SNAP_NO_EXPECTATION) {
769 EXPECT_EQ(GetFullscreenController()->IsInMetroSnapMode(),
770 !!in_metro_snap) << GetAndClearDebugLog();
774 FullscreenController* FullscreenControllerStateTest::GetFullscreenController() {
775 return GetBrowser()->fullscreen_controller();
778 std::string FullscreenControllerStateTest::GetTransitionTableAsString() const {
779 std::ostringstream output;
780 output << "transition_table_[NUM_STATES = " << NUM_STATES
781 << "][NUM_EVENTS = " << NUM_EVENTS
782 << "] =\n";
783 for (int state_int = 0; state_int < NUM_STATES; ++state_int) {
784 State state = static_cast<State>(state_int);
785 output << " { // " << GetStateString(state) << ":\n";
786 for (int event_int = 0; event_int < NUM_EVENTS; ++event_int) {
787 Event event = static_cast<Event>(event_int);
788 output << " "
789 << std::left << std::setw(kMaxStateNameLength+1)
790 << std::string(GetStateString(transition_table_[state][event])) + ","
791 << "// Event "
792 << GetEventString(event) << "\n";
794 output << " },\n";
796 output << " };\n";
797 return output.str();
800 std::string FullscreenControllerStateTest::GetStateTransitionsAsString() const {
801 std::ostringstream output;
802 output << "state_transitions_[NUM_STATES = " << NUM_STATES
803 << "][NUM_STATES = " << NUM_STATES << "] =\n";
804 for (int state1_int = 0; state1_int < NUM_STATES; ++state1_int) {
805 State state1 = static_cast<State>(state1_int);
806 output << "{ // " << GetStateString(state1) << ":\n";
807 for (int state2_int = 0; state2_int < NUM_STATES; ++state2_int) {
808 State state2 = static_cast<State>(state2_int);
809 const StateTransitionInfo& info = state_transitions_[state1][state2];
810 output << " { "
811 << std::left << std::setw(kMaxStateNameLength+1)
812 << std::string(GetEventString(info.event)) + ","
813 << std::left << std::setw(kMaxStateNameLength+1)
814 << std::string(GetStateString(info.state)) + ","
815 << std::right << std::setw(2)
816 << info.distance
817 << " }, // "
818 << GetStateString(state2) << "\n";
820 output << "},\n";
822 output << "};";
823 return output.str();