Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / fullscreen / fullscreen_controller_state_test.cc
blobcafbcd588402f291cff866fc3c51f6c9ced90560
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/common/url_constants.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 #if defined(OS_MACOSX)
22 #include "base/mac/mac_util.h"
23 #endif
25 namespace {
27 bool SupportsMacSystemFullscreen() {
28 #if defined(OS_MACOSX)
29 return chrome::mac::SupportsSystemFullscreen();
30 #else
31 return false;
32 #endif
35 } // namespace
37 FullscreenControllerStateTest::FullscreenControllerStateTest()
38 : state_(STATE_NORMAL),
39 last_notification_received_state_(STATE_NORMAL) {
40 // Human specified state machine data.
41 // For each state, for each event, define the resulting state.
42 State transition_table_data[][NUM_EVENTS] = {
43 { // STATE_NORMAL:
44 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN
45 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TOGGLE_FULLSCREEN_CHROME
46 STATE_TO_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
47 STATE_NORMAL, // Event TAB_FULLSCREEN_FALSE
48 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
49 STATE_NORMAL, // Event METRO_SNAP_FALSE
50 STATE_NORMAL, // Event BUBBLE_EXIT_LINK
51 STATE_NORMAL, // Event BUBBLE_ALLOW
52 STATE_NORMAL, // Event BUBBLE_DENY
53 STATE_NORMAL, // Event WINDOW_CHANGE
55 { // STATE_BROWSER_FULLSCREEN_NO_CHROME:
56 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
57 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event TOGGLE_FULLSCREEN_CHROME
58 STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
59 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE
60 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
61 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event METRO_SNAP_FALSE
62 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
63 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_ALLOW
64 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_DENY
65 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event WINDOW_CHANGE
67 { // STATE_BROWSER_FULLSCREEN_WITH_CHROME:
68 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN
69 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
70 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event TAB_FULLSCREEN_TRUE
71 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event TAB_FULLSCREEN_FALSE
72 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event METRO_SNAP_TRUE
73 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event METRO_SNAP_FALSE
74 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
75 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_ALLOW
76 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_DENY
77 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event WINDOW_CHANGE
79 { // STATE_METRO_SNAP:
80 STATE_METRO_SNAP, // Event TOGGLE_FULLSCREEN
81 STATE_METRO_SNAP, // Event TOGGLE_FULLSCREEN_CHROME
82 STATE_METRO_SNAP, // Event TAB_FULLSCREEN_TRUE
83 STATE_METRO_SNAP, // Event TAB_FULLSCREEN_FALSE
84 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
85 STATE_NORMAL, // Event METRO_SNAP_FALSE
86 STATE_METRO_SNAP, // Event BUBBLE_EXIT_LINK
87 STATE_METRO_SNAP, // Event BUBBLE_ALLOW
88 STATE_METRO_SNAP, // Event BUBBLE_DENY
89 STATE_METRO_SNAP, // Event WINDOW_CHANGE
91 { // STATE_TAB_FULLSCREEN:
92 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
93 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
94 STATE_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
95 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE
96 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
97 STATE_TAB_FULLSCREEN, // Event METRO_SNAP_FALSE
98 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
99 STATE_TAB_FULLSCREEN, // Event BUBBLE_ALLOW
100 STATE_TO_NORMAL, // Event BUBBLE_DENY
101 STATE_TAB_FULLSCREEN, // Event WINDOW_CHANGE
103 { // STATE_TAB_BROWSER_FULLSCREEN:
104 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
105 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
106 STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
107 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE
108 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
109 STATE_TAB_BROWSER_FULLSCREEN, // Event METRO_SNAP_FALSE
110 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_EXIT_LINK
111 STATE_TAB_BROWSER_FULLSCREEN, // Event BUBBLE_ALLOW
112 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_DENY
113 STATE_TAB_BROWSER_FULLSCREEN, // Event WINDOW_CHANGE
115 { // STATE_TAB_BROWSER_FULLSCREEN_CHROME:
116 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
117 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
118 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event TAB_FULLSCREEN_TRUE
119 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event TAB_FULLSCREEN_FALSE
120 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
121 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event METRO_SNAP_FALSE
122 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_EXIT_LINK
123 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event BUBBLE_ALLOW
124 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_DENY
125 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event WINDOW_CHANGE
127 { // STATE_TO_NORMAL:
128 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
129 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TOGGLE_FULLSCREEN_CHROME
130 // TODO(scheib) Should be a route back to TAB. http://crbug.com/154196
131 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_TRUE
132 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE
133 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
134 STATE_TO_NORMAL, // Event METRO_SNAP_FALSE
135 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
136 STATE_TO_NORMAL, // Event BUBBLE_ALLOW
137 STATE_TO_NORMAL, // Event BUBBLE_DENY
138 STATE_NORMAL, // Event WINDOW_CHANGE
140 { // STATE_TO_BROWSER_FULLSCREEN_NO_CHROME:
141 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN
142 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TOGGLE_FULLSCREEN_CHROME
143 // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196
144 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_TRUE
145 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE
146 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
147 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event METRO_SNAP_FALSE
148 #if defined(OS_MACOSX)
149 // Mac window reports fullscreen immediately and an exit triggers exit.
150 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
151 #else
152 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_EXIT_LINK
153 #endif
154 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_ALLOW
155 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_DENY
156 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event WINDOW_CHANGE
158 { // STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME:
159 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN
160 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
161 // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196
162 STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
163 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TAB_FULLSCREEN_FALSE
164 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event METRO_SNAP_TRUE
165 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event METRO_SNAP_FALSE
166 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
167 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event BUBBLE_ALLOW
168 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event BUBBLE_DENY
169 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event WINDOW_CHANGE
171 { // STATE_TO_TAB_FULLSCREEN:
172 // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196
173 STATE_TO_TAB_FULLSCREEN, // Event TOGGLE_FULLSCREEN
174 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
175 STATE_TO_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
176 #if defined(OS_MACOSX)
177 // Mac runs as expected due to a forced NotifyTabOfExitIfNecessary();
178 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE
179 #else
180 // TODO(scheib) Should be a route back to NORMAL. http://crbug.com/154196
181 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE
182 #endif
183 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
184 STATE_TO_TAB_FULLSCREEN, // Event METRO_SNAP_FALSE
185 #if defined(OS_MACOSX)
186 // Mac window reports fullscreen immediately and an exit triggers exit.
187 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
188 #else
189 STATE_TO_TAB_FULLSCREEN, // Event BUBBLE_EXIT_LINK
190 #endif
191 STATE_TO_TAB_FULLSCREEN, // Event BUBBLE_ALLOW
192 #if defined(OS_MACOSX)
193 // Mac window reports fullscreen immediately and an exit triggers exit.
194 STATE_TO_NORMAL, // Event BUBBLE_DENY
195 #else
196 STATE_TO_TAB_FULLSCREEN, // Event BUBBLE_DENY
197 #endif
198 STATE_TAB_FULLSCREEN, // Event WINDOW_CHANGE
201 COMPILE_ASSERT(sizeof(transition_table_data) == sizeof(transition_table_),
202 transition_table_incorrect_size);
203 memcpy(transition_table_, transition_table_data,
204 sizeof(transition_table_data));
206 // Verify that transition_table_ has been completely defined.
207 for (int source = 0; source < NUM_STATES; ++source) {
208 for (int event = 0; event < NUM_EVENTS; ++event) {
209 EXPECT_NE(transition_table_[source][event], STATE_INVALID);
210 EXPECT_GE(transition_table_[source][event], 0);
211 EXPECT_LT(transition_table_[source][event], NUM_STATES);
215 // Copy transition_table_ data into state_transitions_ table.
216 for (int source = 0; source < NUM_STATES; ++source) {
217 for (int event = 0; event < NUM_EVENTS; ++event) {
218 if (ShouldSkipStateAndEventPair(static_cast<State>(source),
219 static_cast<Event>(event)))
220 continue;
221 State destination = transition_table_[source][event];
222 state_transitions_[source][destination].event = static_cast<Event>(event);
223 state_transitions_[source][destination].state = destination;
224 state_transitions_[source][destination].distance = 1;
229 FullscreenControllerStateTest::~FullscreenControllerStateTest() {
232 // static
233 const char* FullscreenControllerStateTest::GetStateString(State state) {
234 switch (state) {
235 ENUM_TO_STRING(STATE_NORMAL);
236 ENUM_TO_STRING(STATE_BROWSER_FULLSCREEN_NO_CHROME);
237 ENUM_TO_STRING(STATE_BROWSER_FULLSCREEN_WITH_CHROME);
238 ENUM_TO_STRING(STATE_METRO_SNAP);
239 ENUM_TO_STRING(STATE_TAB_FULLSCREEN);
240 ENUM_TO_STRING(STATE_TAB_BROWSER_FULLSCREEN);
241 ENUM_TO_STRING(STATE_TAB_BROWSER_FULLSCREEN_CHROME);
242 ENUM_TO_STRING(STATE_TO_NORMAL);
243 ENUM_TO_STRING(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME);
244 ENUM_TO_STRING(STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME);
245 ENUM_TO_STRING(STATE_TO_TAB_FULLSCREEN);
246 ENUM_TO_STRING(STATE_INVALID);
247 default:
248 NOTREACHED() << "No string for state " << state;
249 return "State-Unknown";
253 // static
254 const char* FullscreenControllerStateTest::GetEventString(Event event) {
255 switch (event) {
256 ENUM_TO_STRING(TOGGLE_FULLSCREEN);
257 ENUM_TO_STRING(TOGGLE_FULLSCREEN_CHROME);
258 ENUM_TO_STRING(TAB_FULLSCREEN_TRUE);
259 ENUM_TO_STRING(TAB_FULLSCREEN_FALSE);
260 ENUM_TO_STRING(METRO_SNAP_TRUE);
261 ENUM_TO_STRING(METRO_SNAP_FALSE);
262 ENUM_TO_STRING(BUBBLE_EXIT_LINK);
263 ENUM_TO_STRING(BUBBLE_ALLOW);
264 ENUM_TO_STRING(BUBBLE_DENY);
265 ENUM_TO_STRING(WINDOW_CHANGE);
266 ENUM_TO_STRING(EVENT_INVALID);
267 default:
268 NOTREACHED() << "No string for event " << event;
269 return "Event-Unknown";
273 // static
274 bool FullscreenControllerStateTest::IsWindowFullscreenStateChangedReentrant() {
275 #if defined(TOOLKIT_VIEWS)
276 return true;
277 #else
278 return false;
279 #endif
282 // static
283 bool FullscreenControllerStateTest::IsPersistentState(State state) {
284 switch (state) {
285 case STATE_NORMAL:
286 case STATE_BROWSER_FULLSCREEN_NO_CHROME:
287 case STATE_BROWSER_FULLSCREEN_WITH_CHROME:
288 case STATE_METRO_SNAP:
289 case STATE_TAB_FULLSCREEN:
290 case STATE_TAB_BROWSER_FULLSCREEN:
291 case STATE_TAB_BROWSER_FULLSCREEN_CHROME:
292 return true;
294 case STATE_TO_NORMAL:
295 case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME:
296 case STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME:
297 case STATE_TO_TAB_FULLSCREEN:
298 return false;
300 default:
301 NOTREACHED();
302 return false;
306 void FullscreenControllerStateTest::TransitionToState(State final_state) {
307 int max_steps = NUM_STATES;
308 while (max_steps-- && TransitionAStepTowardState(final_state))
309 continue;
310 ASSERT_GE(max_steps, 0) << "TransitionToState was unable to achieve desired "
311 << "target state. TransitionAStepTowardState iterated too many times."
312 << GetAndClearDebugLog();
313 ASSERT_EQ(final_state, state_) << "TransitionToState was unable to achieve "
314 << "desired target state. TransitionAStepTowardState returned false."
315 << GetAndClearDebugLog();
318 bool FullscreenControllerStateTest::TransitionAStepTowardState(
319 State destination_state) {
320 State source_state = state_;
321 if (source_state == destination_state)
322 return false;
324 StateTransitionInfo next = NextTransitionInShortestPath(source_state,
325 destination_state,
326 NUM_STATES);
327 if (next.state == STATE_INVALID) {
328 NOTREACHED() << "TransitionAStepTowardState unable to transition. "
329 << "NextTransitionInShortestPath("
330 << GetStateString(source_state) << ", "
331 << GetStateString(destination_state) << ") returned STATE_INVALID."
332 << GetAndClearDebugLog();
333 return false;
336 return InvokeEvent(next.event);
339 const char* FullscreenControllerStateTest::GetWindowStateString() {
340 return NULL;
343 bool FullscreenControllerStateTest::InvokeEvent(Event event) {
344 if (!fullscreen_notification_observer_.get()) {
345 // Start observing NOTIFICATION_FULLSCREEN_CHANGED. Construct the
346 // notification observer here instead of in
347 // FullscreenControllerStateTest::FullscreenControllerStateTest() so that we
348 // listen to notifications on the proper thread.
349 fullscreen_notification_observer_.reset(
350 new FullscreenNotificationObserver());
353 State source_state = state_;
354 State next_state = transition_table_[source_state][event];
356 EXPECT_FALSE(ShouldSkipStateAndEventPair(source_state, event))
357 << GetAndClearDebugLog();
359 // When simulating reentrant window change calls, expect the next state
360 // automatically.
361 if (IsWindowFullscreenStateChangedReentrant())
362 next_state = transition_table_[next_state][WINDOW_CHANGE];
364 debugging_log_ << " InvokeEvent(" << std::left
365 << std::setw(kMaxStateNameLength) << GetEventString(event)
366 << ") to "
367 << std::setw(kMaxStateNameLength) << GetStateString(next_state);
369 state_ = next_state;
371 switch (event) {
372 case TOGGLE_FULLSCREEN:
373 GetFullscreenController()->ToggleFullscreenMode();
374 break;
376 case TOGGLE_FULLSCREEN_CHROME:
377 #if defined(OS_MACOSX)
378 if (chrome::mac::SupportsSystemFullscreen()) {
379 GetFullscreenController()->ToggleFullscreenWithChrome();
380 break;
382 #endif
383 NOTREACHED() << GetAndClearDebugLog();
384 break;
386 case TAB_FULLSCREEN_TRUE:
387 GetFullscreenController()->ToggleFullscreenModeForTab(
388 GetBrowser()->tab_strip_model()->GetActiveWebContents(), true);
389 break;
391 case TAB_FULLSCREEN_FALSE:
392 GetFullscreenController()->ToggleFullscreenModeForTab(
393 GetBrowser()->tab_strip_model()->GetActiveWebContents(), false);
394 break;
396 case METRO_SNAP_TRUE:
397 #if defined(OS_WIN)
398 GetFullscreenController()->SetMetroSnapMode(true);
399 #else
400 NOTREACHED() << GetAndClearDebugLog();
401 #endif
402 break;
404 case METRO_SNAP_FALSE:
405 #if defined(OS_WIN)
406 GetFullscreenController()->SetMetroSnapMode(false);
407 #else
408 NOTREACHED() << GetAndClearDebugLog();
409 #endif
410 break;
412 case BUBBLE_EXIT_LINK:
413 GetFullscreenController()->ExitTabOrBrowserFullscreenToPreviousState();
414 break;
416 case BUBBLE_ALLOW:
417 GetFullscreenController()->OnAcceptFullscreenPermission();
418 break;
420 case BUBBLE_DENY:
421 GetFullscreenController()->OnDenyFullscreenPermission();
422 break;
424 case WINDOW_CHANGE:
425 ChangeWindowFullscreenState();
426 break;
428 default:
429 NOTREACHED() << "InvokeEvent needs a handler for event "
430 << GetEventString(event) << GetAndClearDebugLog();
431 return false;
434 if (GetWindowStateString())
435 debugging_log_ << " Window state now " << GetWindowStateString() << "\n";
436 else
437 debugging_log_ << "\n";
439 MaybeWaitForNotification();
440 VerifyWindowState();
442 return true;
445 void FullscreenControllerStateTest::VerifyWindowState() {
446 switch (state_) {
447 case STATE_NORMAL:
448 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
449 FULLSCREEN_WITHOUT_CHROME_FALSE,
450 FULLSCREEN_FOR_BROWSER_FALSE,
451 FULLSCREEN_FOR_TAB_FALSE,
452 IN_METRO_SNAP_FALSE);
453 break;
454 case STATE_BROWSER_FULLSCREEN_NO_CHROME:
455 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
456 FULLSCREEN_WITHOUT_CHROME_TRUE,
457 FULLSCREEN_FOR_BROWSER_TRUE,
458 FULLSCREEN_FOR_TAB_FALSE,
459 IN_METRO_SNAP_FALSE);
460 break;
461 case STATE_BROWSER_FULLSCREEN_WITH_CHROME:
462 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_TRUE,
463 FULLSCREEN_WITHOUT_CHROME_FALSE,
464 FULLSCREEN_FOR_BROWSER_TRUE,
465 FULLSCREEN_FOR_TAB_FALSE,
466 IN_METRO_SNAP_FALSE);
467 break;
468 case STATE_METRO_SNAP:
469 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_NO_EXPECTATION,
470 FULLSCREEN_WITHOUT_CHROME_NO_EXPECTATION,
471 FULLSCREEN_FOR_BROWSER_NO_EXPECTATION,
472 FULLSCREEN_FOR_TAB_NO_EXPECTATION,
473 IN_METRO_SNAP_TRUE);
474 break;
475 case STATE_TAB_FULLSCREEN:
476 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
477 FULLSCREEN_WITHOUT_CHROME_TRUE,
478 FULLSCREEN_FOR_BROWSER_FALSE,
479 FULLSCREEN_FOR_TAB_TRUE,
480 IN_METRO_SNAP_FALSE);
481 break;
482 case STATE_TAB_BROWSER_FULLSCREEN:
483 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
484 FULLSCREEN_WITHOUT_CHROME_TRUE,
485 FULLSCREEN_FOR_BROWSER_TRUE,
486 FULLSCREEN_FOR_TAB_TRUE,
487 IN_METRO_SNAP_FALSE);
488 break;
489 case STATE_TAB_BROWSER_FULLSCREEN_CHROME:
490 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
491 FULLSCREEN_WITHOUT_CHROME_TRUE,
492 FULLSCREEN_FOR_BROWSER_TRUE,
493 FULLSCREEN_FOR_TAB_TRUE,
494 IN_METRO_SNAP_FALSE);
495 break;
496 case STATE_TO_NORMAL:
497 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
498 FULLSCREEN_WITHOUT_CHROME_FALSE,
499 FULLSCREEN_FOR_BROWSER_NO_EXPECTATION,
500 FULLSCREEN_FOR_TAB_NO_EXPECTATION,
501 IN_METRO_SNAP_FALSE);
502 break;
504 case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME:
505 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
506 FULLSCREEN_WITHOUT_CHROME_TRUE,
507 #if defined(OS_MACOSX)
508 FULLSCREEN_FOR_BROWSER_TRUE,
509 #else
510 FULLSCREEN_FOR_BROWSER_FALSE,
511 #endif
512 FULLSCREEN_FOR_TAB_NO_EXPECTATION,
513 IN_METRO_SNAP_FALSE);
514 break;
516 case STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME:
517 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_TRUE,
518 FULLSCREEN_WITHOUT_CHROME_FALSE,
519 #if defined(OS_MACOSX)
520 FULLSCREEN_FOR_BROWSER_TRUE,
521 #else
522 FULLSCREEN_FOR_BROWSER_FALSE,
523 #endif
524 FULLSCREEN_FOR_TAB_NO_EXPECTATION,
525 IN_METRO_SNAP_FALSE);
526 break;
528 case STATE_TO_TAB_FULLSCREEN:
529 #if defined(OS_MACOSX)
530 // TODO(scheib) InPresentationMode returns false when invoking events:
531 // TAB_FULLSCREEN_TRUE, TOGGLE_FULLSCREEN. http://crbug.com/156645
532 // It may be that a new testing state TO_TAB_BROWSER_FULLSCREEN
533 // would help work around this http://crbug.com/154196
534 // Test with: STATE_TO_TAB_FULLSCREEN__TOGGLE_FULLSCREEN
536 // EXPECT_TRUE(GetBrowser()->window()->InPresentationMode())
537 // << GetAndClearDebugLog();
538 #endif
539 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_NO_EXPECTATION,
540 FULLSCREEN_WITHOUT_CHROME_NO_EXPECTATION,
541 FULLSCREEN_FOR_BROWSER_FALSE,
542 FULLSCREEN_FOR_TAB_TRUE,
543 IN_METRO_SNAP_FALSE);
544 break;
546 default:
547 NOTREACHED() << GetAndClearDebugLog();
551 void FullscreenControllerStateTest::MaybeWaitForNotification() {
552 // We should get a fullscreen notification each time we get to a new
553 // persistent state. If we don't get a notification, the test will
554 // fail by timing out.
555 if (state_ != last_notification_received_state_ &&
556 IsPersistentState(state_)) {
557 fullscreen_notification_observer_->Wait();
558 last_notification_received_state_ = state_;
559 fullscreen_notification_observer_.reset(
560 new FullscreenNotificationObserver());
564 void FullscreenControllerStateTest::TestTransitionsForEachState() {
565 for (int source_int = 0; source_int < NUM_STATES; ++source_int) {
566 for (int event1_int = 0; event1_int < NUM_EVENTS; ++event1_int) {
567 State state = static_cast<State>(source_int);
568 Event event1 = static_cast<Event>(event1_int);
570 // Early out if skipping all tests for this state, reduces log noise.
571 if (ShouldSkipTest(state, event1))
572 continue;
574 for (int event2_int = 0; event2_int < NUM_EVENTS; ++event2_int) {
575 for (int event3_int = 0; event3_int < NUM_EVENTS; ++event3_int) {
576 Event event2 = static_cast<Event>(event2_int);
577 Event event3 = static_cast<Event>(event3_int);
579 // Test each state and each event.
580 ASSERT_NO_FATAL_FAILURE(TestStateAndEvent(state, event1))
581 << GetAndClearDebugLog();
583 // Then, add an additional event to the sequence.
584 if (ShouldSkipStateAndEventPair(state_, event2))
585 continue;
586 ASSERT_TRUE(InvokeEvent(event2)) << GetAndClearDebugLog();
588 // Then, add an additional event to the sequence.
589 if (ShouldSkipStateAndEventPair(state_, event3))
590 continue;
591 ASSERT_TRUE(InvokeEvent(event3)) << GetAndClearDebugLog();
598 FullscreenControllerStateTest::StateTransitionInfo
599 FullscreenControllerStateTest::NextTransitionInShortestPath(
600 State source,
601 State destination,
602 int search_limit) {
603 if (search_limit <= 0)
604 return StateTransitionInfo(); // Return a default (invalid) state.
606 if (state_transitions_[source][destination].state == STATE_INVALID) {
607 // Don't know the next state yet, do a depth first search.
608 StateTransitionInfo result;
610 // Consider all states reachable via each event from the source state.
611 for (int event_int = 0; event_int < NUM_EVENTS; ++event_int) {
612 Event event = static_cast<Event>(event_int);
613 State next_state_candidate = transition_table_[source][event];
615 if (ShouldSkipStateAndEventPair(source, event))
616 continue;
618 // Recurse.
619 StateTransitionInfo candidate = NextTransitionInShortestPath(
620 next_state_candidate, destination, search_limit - 1);
622 if (candidate.distance + 1 < result.distance) {
623 result.event = event;
624 result.state = next_state_candidate;
625 result.distance = candidate.distance + 1;
629 // Cache result so that a search is not required next time.
630 state_transitions_[source][destination] = result;
633 return state_transitions_[source][destination];
636 std::string FullscreenControllerStateTest::GetAndClearDebugLog() {
637 debugging_log_ << "(End of Debugging Log)\n";
638 std::string output_log = "\nDebugging Log:\n" + debugging_log_.str();
639 debugging_log_.str(std::string());
640 return output_log;
643 bool FullscreenControllerStateTest::ShouldSkipStateAndEventPair(State state,
644 Event event) {
645 // TODO(scheib) Toggling Tab fullscreen while pending Tab or
646 // Browser fullscreen is broken currently http://crbug.com/154196
647 if ((state == STATE_TO_BROWSER_FULLSCREEN_NO_CHROME ||
648 state == STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME ||
649 state == STATE_TO_TAB_FULLSCREEN) &&
650 (event == TAB_FULLSCREEN_TRUE || event == TAB_FULLSCREEN_FALSE))
651 return true;
652 if (state == STATE_TO_NORMAL && event == TAB_FULLSCREEN_TRUE)
653 return true;
655 // Skip metro snap state and events when not on windows.
656 #if !defined(OS_WIN)
657 if (state == STATE_METRO_SNAP ||
658 event == METRO_SNAP_TRUE ||
659 event == METRO_SNAP_FALSE)
660 return true;
661 #endif
663 // Skip Mac Lion Fullscreen state and events when not on OSX 10.7+.
664 if (!SupportsMacSystemFullscreen()) {
665 if (state == STATE_BROWSER_FULLSCREEN_WITH_CHROME ||
666 state == STATE_TAB_BROWSER_FULLSCREEN_CHROME ||
667 state == STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME ||
668 event == TOGGLE_FULLSCREEN_CHROME) {
669 return true;
673 return false;
676 bool FullscreenControllerStateTest::ShouldSkipTest(State state, Event event) {
677 // Quietly skip metro snap tests when not on windows.
678 #if !defined(OS_WIN)
679 if (state == STATE_METRO_SNAP ||
680 event == METRO_SNAP_TRUE ||
681 event == METRO_SNAP_FALSE) {
682 debugging_log_ << "\nSkipping metro snap test on non-Windows.\n";
683 return true;
685 #endif
687 // Quietly skip Mac Lion Fullscreen tests when not on OSX 10.7+.
688 if (!SupportsMacSystemFullscreen()) {
689 if (state == STATE_BROWSER_FULLSCREEN_WITH_CHROME ||
690 event == TOGGLE_FULLSCREEN_CHROME) {
691 debugging_log_ << "\nSkipping Lion Fullscreen test on non-OSX 10.7+.\n";
692 return true;
696 // When testing reentrancy there are states the fullscreen controller
697 // will be unable to remain in, as they will progress due to the
698 // reentrant window change call. Skip states that will be instantly
699 // exited by the reentrant call.
700 if (IsWindowFullscreenStateChangedReentrant() &&
701 (transition_table_[state][WINDOW_CHANGE] != state)) {
702 debugging_log_ << "\nSkipping reentrant test for transitory source state "
703 << GetStateString(state) << ".\n";
704 return true;
707 if (ShouldSkipStateAndEventPair(state, event)) {
708 debugging_log_ << "\nSkipping test due to ShouldSkipStateAndEventPair("
709 << GetStateString(state) << ", "
710 << GetEventString(event) << ").\n";
711 LOG(INFO) << "Skipping test due to ShouldSkipStateAndEventPair("
712 << GetStateString(state) << ", "
713 << GetEventString(event) << ").";
714 return true;
717 return false;
720 void FullscreenControllerStateTest::TestStateAndEvent(State state,
721 Event event) {
722 if (ShouldSkipTest(state, event))
723 return;
725 debugging_log_ << "\nTest transition from state "
726 << GetStateString(state)
727 << (IsWindowFullscreenStateChangedReentrant() ?
728 " with reentrant calls.\n" : ".\n");
730 // Spaced out text to line up with columns printed in InvokeEvent().
731 debugging_log_ << "First, from "
732 << GetStateString(state_) << "\n";
733 ASSERT_NO_FATAL_FAILURE(TransitionToState(state))
734 << GetAndClearDebugLog();
736 debugging_log_ << " Then,\n";
737 ASSERT_TRUE(InvokeEvent(event)) << GetAndClearDebugLog();
740 void FullscreenControllerStateTest::VerifyWindowStateExpectations(
741 FullscreenWithChromeExpectation fullscreen_with_chrome,
742 FullscreenWithoutChromeExpectation fullscreen_without_chrome,
743 FullscreenForBrowserExpectation fullscreen_for_browser,
744 FullscreenForTabExpectation fullscreen_for_tab,
745 InMetroSnapExpectation in_metro_snap) {
746 #if defined(OS_MACOSX)
747 if (fullscreen_with_chrome != FULLSCREEN_WITH_CHROME_NO_EXPECTATION) {
748 EXPECT_EQ(GetBrowser()->window()->IsFullscreenWithChrome(),
749 !!fullscreen_with_chrome) << GetAndClearDebugLog();
751 if (fullscreen_without_chrome != FULLSCREEN_WITHOUT_CHROME_NO_EXPECTATION) {
752 EXPECT_EQ(GetBrowser()->window()->IsFullscreenWithoutChrome(),
753 !!fullscreen_without_chrome) << GetAndClearDebugLog();
755 #endif
756 if (fullscreen_for_browser != FULLSCREEN_FOR_BROWSER_NO_EXPECTATION) {
757 EXPECT_EQ(GetFullscreenController()->IsFullscreenForBrowser(),
758 !!fullscreen_for_browser) << GetAndClearDebugLog();
760 if (fullscreen_for_tab != FULLSCREEN_FOR_TAB_NO_EXPECTATION) {
761 EXPECT_EQ(GetFullscreenController()->IsFullscreenForTabOrPending(),
762 !!fullscreen_for_tab) << GetAndClearDebugLog();
764 if (in_metro_snap != IN_METRO_SNAP_NO_EXPECTATION) {
765 EXPECT_EQ(GetFullscreenController()->IsInMetroSnapMode(),
766 !!in_metro_snap) << GetAndClearDebugLog();
770 FullscreenController* FullscreenControllerStateTest::GetFullscreenController() {
771 return GetBrowser()->fullscreen_controller();
774 std::string FullscreenControllerStateTest::GetTransitionTableAsString() const {
775 std::ostringstream output;
776 output << "transition_table_[NUM_STATES = " << NUM_STATES
777 << "][NUM_EVENTS = " << NUM_EVENTS
778 << "] =\n";
779 for (int state_int = 0; state_int < NUM_STATES; ++state_int) {
780 State state = static_cast<State>(state_int);
781 output << " { // " << GetStateString(state) << ":\n";
782 for (int event_int = 0; event_int < NUM_EVENTS; ++event_int) {
783 Event event = static_cast<Event>(event_int);
784 output << " "
785 << std::left << std::setw(kMaxStateNameLength+1)
786 << std::string(GetStateString(transition_table_[state][event])) + ","
787 << "// Event "
788 << GetEventString(event) << "\n";
790 output << " },\n";
792 output << " };\n";
793 return output.str();
796 std::string FullscreenControllerStateTest::GetStateTransitionsAsString() const {
797 std::ostringstream output;
798 output << "state_transitions_[NUM_STATES = " << NUM_STATES
799 << "][NUM_STATES = " << NUM_STATES << "] =\n";
800 for (int state1_int = 0; state1_int < NUM_STATES; ++state1_int) {
801 State state1 = static_cast<State>(state1_int);
802 output << "{ // " << GetStateString(state1) << ":\n";
803 for (int state2_int = 0; state2_int < NUM_STATES; ++state2_int) {
804 State state2 = static_cast<State>(state2_int);
805 const StateTransitionInfo& info = state_transitions_[state1][state2];
806 output << " { "
807 << std::left << std::setw(kMaxStateNameLength+1)
808 << std::string(GetEventString(info.event)) + ","
809 << std::left << std::setw(kMaxStateNameLength+1)
810 << std::string(GetStateString(info.state)) + ","
811 << std::right << std::setw(2)
812 << info.distance
813 << " }, // "
814 << GetStateString(state2) << "\n";
816 output << "},\n";
818 output << "};";
819 return output.str();