Infobar material design refresh: layout
[chromium-blink-merge.git] / chrome / browser / ui / exclusive_access / fullscreen_controller_state_test.cc
bloba8af8b3ba20fb2e6c26ca61dbf3891751e794430
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/exclusive_access/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/exclusive_access/fullscreen_controller.h"
16 #include "chrome/browser/ui/exclusive_access/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 namespace {
24 bool SupportsMacSystemFullscreen() {
25 #if defined(OS_MACOSX)
26 return chrome::mac::SupportsSystemFullscreen();
27 #else
28 return false;
29 #endif
32 } // namespace
34 FullscreenControllerStateTest::FullscreenControllerStateTest()
35 : state_(STATE_NORMAL),
36 last_notification_received_state_(STATE_NORMAL) {
37 // Human specified state machine data.
38 // For each state, for each event, define the resulting state.
39 State transition_table_data[][NUM_EVENTS] = {
40 { // STATE_NORMAL:
41 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN
42 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TOGGLE_FULLSCREEN_CHROME
43 STATE_TO_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
44 STATE_NORMAL, // Event TAB_FULLSCREEN_FALSE
45 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
46 STATE_NORMAL, // Event METRO_SNAP_FALSE
47 STATE_NORMAL, // Event BUBBLE_EXIT_LINK
48 STATE_NORMAL, // Event BUBBLE_ALLOW
49 STATE_NORMAL, // Event BUBBLE_DENY
50 STATE_NORMAL, // Event WINDOW_CHANGE
52 { // STATE_BROWSER_FULLSCREEN_NO_CHROME:
53 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
54 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event TOGGLE_FULLSCREEN_CHROME
55 STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
56 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE
57 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
58 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event METRO_SNAP_FALSE
59 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
60 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_ALLOW
61 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_DENY
62 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event WINDOW_CHANGE
64 { // STATE_BROWSER_FULLSCREEN_WITH_CHROME:
65 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN
66 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
67 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event TAB_FULLSCREEN_TRUE
68 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event TAB_FULLSCREEN_FALSE
69 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event METRO_SNAP_TRUE
70 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event METRO_SNAP_FALSE
71 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
72 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_ALLOW
73 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_DENY
74 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event WINDOW_CHANGE
76 { // STATE_METRO_SNAP:
77 STATE_METRO_SNAP, // Event TOGGLE_FULLSCREEN
78 STATE_METRO_SNAP, // Event TOGGLE_FULLSCREEN_CHROME
79 STATE_METRO_SNAP, // Event TAB_FULLSCREEN_TRUE
80 STATE_METRO_SNAP, // Event TAB_FULLSCREEN_FALSE
81 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
82 STATE_NORMAL, // Event METRO_SNAP_FALSE
83 STATE_METRO_SNAP, // Event BUBBLE_EXIT_LINK
84 STATE_METRO_SNAP, // Event BUBBLE_ALLOW
85 STATE_METRO_SNAP, // Event BUBBLE_DENY
86 STATE_METRO_SNAP, // Event WINDOW_CHANGE
88 { // STATE_TAB_FULLSCREEN:
89 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
90 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
91 STATE_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
92 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE
93 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
94 STATE_TAB_FULLSCREEN, // Event METRO_SNAP_FALSE
95 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
96 STATE_TAB_FULLSCREEN, // Event BUBBLE_ALLOW
97 STATE_TO_NORMAL, // Event BUBBLE_DENY
98 STATE_TAB_FULLSCREEN, // Event WINDOW_CHANGE
100 { // STATE_TAB_BROWSER_FULLSCREEN:
101 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
102 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
103 STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
104 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE
105 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
106 STATE_TAB_BROWSER_FULLSCREEN, // Event METRO_SNAP_FALSE
107 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_EXIT_LINK
108 STATE_TAB_BROWSER_FULLSCREEN, // Event BUBBLE_ALLOW
109 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_DENY
110 STATE_TAB_BROWSER_FULLSCREEN, // Event WINDOW_CHANGE
112 { // STATE_TAB_BROWSER_FULLSCREEN_CHROME:
113 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
114 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
115 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event TAB_FULLSCREEN_TRUE
116 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event TAB_FULLSCREEN_FALSE
117 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
118 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event METRO_SNAP_FALSE
119 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_EXIT_LINK
120 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event BUBBLE_ALLOW
121 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_DENY
122 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event WINDOW_CHANGE
124 { // STATE_TO_NORMAL:
125 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN
126 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TOGGLE_FULLSCREEN_CHROME
127 // TODO(scheib) Should be a route back to TAB. http://crbug.com/154196
128 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_TRUE
129 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE
130 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
131 STATE_TO_NORMAL, // Event METRO_SNAP_FALSE
132 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
133 STATE_TO_NORMAL, // Event BUBBLE_ALLOW
134 STATE_TO_NORMAL, // Event BUBBLE_DENY
135 STATE_NORMAL, // Event WINDOW_CHANGE
137 { // STATE_TO_BROWSER_FULLSCREEN_NO_CHROME:
138 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN
139 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TOGGLE_FULLSCREEN_CHROME
140 // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196
141 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_TRUE
142 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE
143 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
144 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event METRO_SNAP_FALSE
145 #if defined(OS_MACOSX)
146 // Mac window reports fullscreen immediately and an exit triggers exit.
147 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
148 #else
149 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_EXIT_LINK
150 #endif
151 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_ALLOW
152 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_DENY
153 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event WINDOW_CHANGE
155 { // STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME:
156 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN
157 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
158 // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196
159 STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
160 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TAB_FULLSCREEN_FALSE
161 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event METRO_SNAP_TRUE
162 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event METRO_SNAP_FALSE
163 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
164 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event BUBBLE_ALLOW
165 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event BUBBLE_DENY
166 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event WINDOW_CHANGE
168 { // STATE_TO_TAB_FULLSCREEN:
169 // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196
170 STATE_TO_TAB_FULLSCREEN, // Event TOGGLE_FULLSCREEN
171 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME
172 STATE_TO_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE
173 #if defined(OS_MACOSX)
174 // Mac runs as expected due to a forced NotifyTabOfExitIfNecessary();
175 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE
176 #else
177 // TODO(scheib) Should be a route back to NORMAL. http://crbug.com/154196
178 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE
179 #endif
180 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE
181 STATE_TO_TAB_FULLSCREEN, // Event METRO_SNAP_FALSE
182 #if defined(OS_MACOSX)
183 // Mac window reports fullscreen immediately and an exit triggers exit.
184 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK
185 #else
186 STATE_TO_TAB_FULLSCREEN, // Event BUBBLE_EXIT_LINK
187 #endif
188 STATE_TO_TAB_FULLSCREEN, // Event BUBBLE_ALLOW
189 #if defined(OS_MACOSX)
190 // Mac window reports fullscreen immediately and an exit triggers exit.
191 STATE_TO_NORMAL, // Event BUBBLE_DENY
192 #else
193 STATE_TO_TAB_FULLSCREEN, // Event BUBBLE_DENY
194 #endif
195 STATE_TAB_FULLSCREEN, // Event WINDOW_CHANGE
198 static_assert(sizeof(transition_table_data) == sizeof(transition_table_),
199 "transition_table has unexpected size");
200 memcpy(transition_table_, transition_table_data,
201 sizeof(transition_table_data));
203 // Verify that transition_table_ has been completely defined.
204 for (int source = 0; source < NUM_STATES; ++source) {
205 for (int event = 0; event < NUM_EVENTS; ++event) {
206 EXPECT_NE(transition_table_[source][event], STATE_INVALID);
207 EXPECT_GE(transition_table_[source][event], 0);
208 EXPECT_LT(transition_table_[source][event], NUM_STATES);
212 // Copy transition_table_ data into state_transitions_ table.
213 for (int source = 0; source < NUM_STATES; ++source) {
214 for (int event = 0; event < NUM_EVENTS; ++event) {
215 if (ShouldSkipStateAndEventPair(static_cast<State>(source),
216 static_cast<Event>(event)))
217 continue;
218 State destination = transition_table_[source][event];
219 state_transitions_[source][destination].event = static_cast<Event>(event);
220 state_transitions_[source][destination].state = destination;
221 state_transitions_[source][destination].distance = 1;
226 FullscreenControllerStateTest::~FullscreenControllerStateTest() {
229 // static
230 const char* FullscreenControllerStateTest::GetStateString(State state) {
231 switch (state) {
232 ENUM_TO_STRING(STATE_NORMAL);
233 ENUM_TO_STRING(STATE_BROWSER_FULLSCREEN_NO_CHROME);
234 ENUM_TO_STRING(STATE_BROWSER_FULLSCREEN_WITH_CHROME);
235 ENUM_TO_STRING(STATE_METRO_SNAP);
236 ENUM_TO_STRING(STATE_TAB_FULLSCREEN);
237 ENUM_TO_STRING(STATE_TAB_BROWSER_FULLSCREEN);
238 ENUM_TO_STRING(STATE_TAB_BROWSER_FULLSCREEN_CHROME);
239 ENUM_TO_STRING(STATE_TO_NORMAL);
240 ENUM_TO_STRING(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME);
241 ENUM_TO_STRING(STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME);
242 ENUM_TO_STRING(STATE_TO_TAB_FULLSCREEN);
243 ENUM_TO_STRING(STATE_INVALID);
244 default:
245 NOTREACHED() << "No string for state " << state;
246 return "State-Unknown";
250 // static
251 const char* FullscreenControllerStateTest::GetEventString(Event event) {
252 switch (event) {
253 ENUM_TO_STRING(TOGGLE_FULLSCREEN);
254 ENUM_TO_STRING(TOGGLE_FULLSCREEN_CHROME);
255 ENUM_TO_STRING(TAB_FULLSCREEN_TRUE);
256 ENUM_TO_STRING(TAB_FULLSCREEN_FALSE);
257 ENUM_TO_STRING(METRO_SNAP_TRUE);
258 ENUM_TO_STRING(METRO_SNAP_FALSE);
259 ENUM_TO_STRING(BUBBLE_EXIT_LINK);
260 ENUM_TO_STRING(BUBBLE_ALLOW);
261 ENUM_TO_STRING(BUBBLE_DENY);
262 ENUM_TO_STRING(WINDOW_CHANGE);
263 ENUM_TO_STRING(EVENT_INVALID);
264 default:
265 NOTREACHED() << "No string for event " << event;
266 return "Event-Unknown";
270 // static
271 bool FullscreenControllerStateTest::IsWindowFullscreenStateChangedReentrant() {
272 #if defined(OS_MACOSX)
273 return false;
274 #else
275 return true;
276 #endif
279 // static
280 bool FullscreenControllerStateTest::IsPersistentState(State state) {
281 switch (state) {
282 case STATE_NORMAL:
283 case STATE_BROWSER_FULLSCREEN_NO_CHROME:
284 case STATE_BROWSER_FULLSCREEN_WITH_CHROME:
285 case STATE_METRO_SNAP:
286 case STATE_TAB_FULLSCREEN:
287 case STATE_TAB_BROWSER_FULLSCREEN:
288 case STATE_TAB_BROWSER_FULLSCREEN_CHROME:
289 return true;
291 case STATE_TO_NORMAL:
292 case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME:
293 case STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME:
294 case STATE_TO_TAB_FULLSCREEN:
295 return false;
297 default:
298 NOTREACHED();
299 return false;
303 void FullscreenControllerStateTest::TransitionToState(State final_state) {
304 int max_steps = NUM_STATES;
305 while (max_steps-- && TransitionAStepTowardState(final_state))
306 continue;
307 ASSERT_GE(max_steps, 0) << "TransitionToState was unable to achieve desired "
308 << "target state. TransitionAStepTowardState iterated too many times."
309 << GetAndClearDebugLog();
310 ASSERT_EQ(final_state, state_) << "TransitionToState was unable to achieve "
311 << "desired target state. TransitionAStepTowardState returned false."
312 << GetAndClearDebugLog();
315 bool FullscreenControllerStateTest::TransitionAStepTowardState(
316 State destination_state) {
317 State source_state = state_;
318 if (source_state == destination_state)
319 return false;
321 StateTransitionInfo next = NextTransitionInShortestPath(source_state,
322 destination_state,
323 NUM_STATES);
324 if (next.state == STATE_INVALID) {
325 NOTREACHED() << "TransitionAStepTowardState unable to transition. "
326 << "NextTransitionInShortestPath("
327 << GetStateString(source_state) << ", "
328 << GetStateString(destination_state) << ") returned STATE_INVALID."
329 << GetAndClearDebugLog();
330 return false;
333 return InvokeEvent(next.event);
336 const char* FullscreenControllerStateTest::GetWindowStateString() {
337 return NULL;
340 bool FullscreenControllerStateTest::InvokeEvent(Event event) {
341 if (!fullscreen_notification_observer_.get()) {
342 // Start observing NOTIFICATION_FULLSCREEN_CHANGED. Construct the
343 // notification observer here instead of in
344 // FullscreenControllerStateTest::FullscreenControllerStateTest() so that we
345 // listen to notifications on the proper thread.
346 fullscreen_notification_observer_.reset(
347 new FullscreenNotificationObserver());
350 State source_state = state_;
351 State next_state = transition_table_[source_state][event];
353 EXPECT_FALSE(ShouldSkipStateAndEventPair(source_state, event))
354 << GetAndClearDebugLog();
356 // When simulating reentrant window change calls, expect the next state
357 // automatically.
358 if (IsWindowFullscreenStateChangedReentrant())
359 next_state = transition_table_[next_state][WINDOW_CHANGE];
361 debugging_log_ << " InvokeEvent(" << std::left
362 << std::setw(kMaxStateNameLength) << GetEventString(event)
363 << ") to "
364 << std::setw(kMaxStateNameLength) << GetStateString(next_state);
366 state_ = next_state;
368 switch (event) {
369 case TOGGLE_FULLSCREEN:
370 GetFullscreenController()->ToggleBrowserFullscreenMode();
371 break;
373 case TOGGLE_FULLSCREEN_CHROME:
374 #if defined(OS_MACOSX)
375 if (chrome::mac::SupportsSystemFullscreen()) {
376 GetFullscreenController()->ToggleBrowserFullscreenWithToolbar();
377 break;
379 #endif
380 NOTREACHED() << GetAndClearDebugLog();
381 break;
383 case TAB_FULLSCREEN_TRUE:
384 case TAB_FULLSCREEN_FALSE: {
385 content::WebContents* const active_tab =
386 GetBrowser()->tab_strip_model()->GetActiveWebContents();
387 if (event == TAB_FULLSCREEN_TRUE) {
388 GetFullscreenController()->EnterFullscreenModeForTab(active_tab,
389 GURL());
390 } else {
391 GetFullscreenController()->ExitFullscreenModeForTab(active_tab);
394 // Activating/Deactivating tab fullscreen on a captured tab should not
395 // evoke a state change in the browser window.
396 if (active_tab->GetCapturerCount() > 0)
397 state_ = source_state;
398 break;
401 case METRO_SNAP_TRUE:
402 #if defined(OS_WIN)
403 GetFullscreenController()->SetMetroSnapMode(true);
404 #else
405 NOTREACHED() << GetAndClearDebugLog();
406 #endif
407 break;
409 case METRO_SNAP_FALSE:
410 #if defined(OS_WIN)
411 GetFullscreenController()->SetMetroSnapMode(false);
412 #else
413 NOTREACHED() << GetAndClearDebugLog();
414 #endif
415 break;
417 case BUBBLE_EXIT_LINK:
418 GetFullscreenController()->ExitExclusiveAccessToPreviousState();
419 break;
421 case BUBBLE_ALLOW:
422 GetBrowser()
423 ->exclusive_access_manager()
424 ->OnAcceptExclusiveAccessPermission();
425 break;
427 case BUBBLE_DENY:
428 GetBrowser()
429 ->exclusive_access_manager()
430 ->OnDenyExclusiveAccessPermission();
431 break;
433 case WINDOW_CHANGE:
434 ChangeWindowFullscreenState();
435 break;
437 default:
438 NOTREACHED() << "InvokeEvent needs a handler for event "
439 << GetEventString(event) << GetAndClearDebugLog();
440 return false;
443 if (GetWindowStateString())
444 debugging_log_ << " Window state now " << GetWindowStateString() << "\n";
445 else
446 debugging_log_ << "\n";
448 MaybeWaitForNotification();
449 VerifyWindowState();
451 return true;
454 void FullscreenControllerStateTest::VerifyWindowState() {
455 switch (state_) {
456 case STATE_NORMAL:
457 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
458 FULLSCREEN_FOR_BROWSER_FALSE,
459 FULLSCREEN_FOR_TAB_FALSE,
460 IN_METRO_SNAP_FALSE);
461 break;
462 case STATE_BROWSER_FULLSCREEN_NO_CHROME:
463 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
464 FULLSCREEN_FOR_BROWSER_TRUE,
465 FULLSCREEN_FOR_TAB_FALSE,
466 IN_METRO_SNAP_FALSE);
467 break;
468 case STATE_BROWSER_FULLSCREEN_WITH_CHROME:
469 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_TRUE,
470 FULLSCREEN_FOR_BROWSER_TRUE,
471 FULLSCREEN_FOR_TAB_FALSE,
472 IN_METRO_SNAP_FALSE);
473 break;
474 case STATE_METRO_SNAP:
475 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_NO_EXPECTATION,
476 FULLSCREEN_FOR_BROWSER_NO_EXPECTATION,
477 FULLSCREEN_FOR_TAB_NO_EXPECTATION,
478 IN_METRO_SNAP_TRUE);
479 break;
480 case STATE_TAB_FULLSCREEN:
481 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
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_FOR_BROWSER_TRUE,
489 FULLSCREEN_FOR_TAB_TRUE,
490 IN_METRO_SNAP_FALSE);
491 break;
492 case STATE_TAB_BROWSER_FULLSCREEN_CHROME:
493 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
494 FULLSCREEN_FOR_BROWSER_TRUE,
495 FULLSCREEN_FOR_TAB_TRUE,
496 IN_METRO_SNAP_FALSE);
497 break;
498 case STATE_TO_NORMAL:
499 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
500 FULLSCREEN_FOR_BROWSER_NO_EXPECTATION,
501 FULLSCREEN_FOR_TAB_NO_EXPECTATION,
502 IN_METRO_SNAP_FALSE);
503 break;
505 case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME:
506 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE,
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 #if defined(OS_MACOSX)
519 FULLSCREEN_FOR_BROWSER_TRUE,
520 #else
521 FULLSCREEN_FOR_BROWSER_FALSE,
522 #endif
523 FULLSCREEN_FOR_TAB_NO_EXPECTATION,
524 IN_METRO_SNAP_FALSE);
525 break;
527 case STATE_TO_TAB_FULLSCREEN:
528 #if defined(OS_MACOSX)
529 // TODO(scheib) InPresentationMode returns false when invoking events:
530 // TAB_FULLSCREEN_TRUE, TOGGLE_FULLSCREEN. http://crbug.com/156645
531 // It may be that a new testing state TO_TAB_BROWSER_FULLSCREEN
532 // would help work around this http://crbug.com/154196
533 // Test with: STATE_TO_TAB_FULLSCREEN__TOGGLE_FULLSCREEN
535 // EXPECT_TRUE(GetBrowser()->window()->InPresentationMode())
536 // << GetAndClearDebugLog();
537 #endif
538 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_NO_EXPECTATION,
539 FULLSCREEN_FOR_BROWSER_FALSE,
540 FULLSCREEN_FOR_TAB_TRUE,
541 IN_METRO_SNAP_FALSE);
542 break;
544 default:
545 NOTREACHED() << GetAndClearDebugLog();
549 void FullscreenControllerStateTest::MaybeWaitForNotification() {
550 // We should get a fullscreen notification each time we get to a new
551 // persistent state. If we don't get a notification, the test will
552 // fail by timing out.
553 if (state_ != last_notification_received_state_ &&
554 IsPersistentState(state_)) {
555 fullscreen_notification_observer_->Wait();
556 last_notification_received_state_ = state_;
557 fullscreen_notification_observer_.reset(
558 new FullscreenNotificationObserver());
562 void FullscreenControllerStateTest::TestTransitionsForEachState() {
563 for (int source_int = 0; source_int < NUM_STATES; ++source_int) {
564 for (int event1_int = 0; event1_int < NUM_EVENTS; ++event1_int) {
565 State state = static_cast<State>(source_int);
566 Event event1 = static_cast<Event>(event1_int);
568 // Early out if skipping all tests for this state, reduces log noise.
569 if (ShouldSkipTest(state, event1))
570 continue;
572 for (int event2_int = 0; event2_int < NUM_EVENTS; ++event2_int) {
573 for (int event3_int = 0; event3_int < NUM_EVENTS; ++event3_int) {
574 Event event2 = static_cast<Event>(event2_int);
575 Event event3 = static_cast<Event>(event3_int);
577 // Test each state and each event.
578 ASSERT_NO_FATAL_FAILURE(TestStateAndEvent(state, event1))
579 << GetAndClearDebugLog();
581 // Then, add an additional event to the sequence.
582 if (ShouldSkipStateAndEventPair(state_, event2))
583 continue;
584 ASSERT_TRUE(InvokeEvent(event2)) << GetAndClearDebugLog();
586 // Then, add an additional event to the sequence.
587 if (ShouldSkipStateAndEventPair(state_, event3))
588 continue;
589 ASSERT_TRUE(InvokeEvent(event3)) << GetAndClearDebugLog();
596 FullscreenControllerStateTest::StateTransitionInfo
597 FullscreenControllerStateTest::NextTransitionInShortestPath(
598 State source,
599 State destination,
600 int search_limit) {
601 if (search_limit <= 0)
602 return StateTransitionInfo(); // Return a default (invalid) state.
604 if (state_transitions_[source][destination].state == STATE_INVALID) {
605 // Don't know the next state yet, do a depth first search.
606 StateTransitionInfo result;
608 // Consider all states reachable via each event from the source state.
609 for (int event_int = 0; event_int < NUM_EVENTS; ++event_int) {
610 Event event = static_cast<Event>(event_int);
611 State next_state_candidate = transition_table_[source][event];
613 if (ShouldSkipStateAndEventPair(source, event))
614 continue;
616 // Recurse.
617 StateTransitionInfo candidate = NextTransitionInShortestPath(
618 next_state_candidate, destination, search_limit - 1);
620 if (candidate.distance + 1 < result.distance) {
621 result.event = event;
622 result.state = next_state_candidate;
623 result.distance = candidate.distance + 1;
627 // Cache result so that a search is not required next time.
628 state_transitions_[source][destination] = result;
631 return state_transitions_[source][destination];
634 std::string FullscreenControllerStateTest::GetAndClearDebugLog() {
635 debugging_log_ << "(End of Debugging Log)\n";
636 std::string output_log = "\nDebugging Log:\n" + debugging_log_.str();
637 debugging_log_.str(std::string());
638 return output_log;
641 bool FullscreenControllerStateTest::ShouldSkipStateAndEventPair(State state,
642 Event event) {
643 // TODO(scheib) Toggling Tab fullscreen while pending Tab or
644 // Browser fullscreen is broken currently http://crbug.com/154196
645 if ((state == STATE_TO_BROWSER_FULLSCREEN_NO_CHROME ||
646 state == STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME ||
647 state == STATE_TO_TAB_FULLSCREEN) &&
648 (event == TAB_FULLSCREEN_TRUE || event == TAB_FULLSCREEN_FALSE))
649 return true;
650 if (state == STATE_TO_NORMAL && event == TAB_FULLSCREEN_TRUE)
651 return true;
653 // Skip metro snap state and events when not on windows.
654 #if !defined(OS_WIN)
655 if (state == STATE_METRO_SNAP ||
656 event == METRO_SNAP_TRUE ||
657 event == METRO_SNAP_FALSE)
658 return true;
659 #endif
661 // Skip Mac Lion Fullscreen state and events when not on OSX 10.7+.
662 if (!SupportsMacSystemFullscreen()) {
663 if (state == STATE_BROWSER_FULLSCREEN_WITH_CHROME ||
664 state == STATE_TAB_BROWSER_FULLSCREEN_CHROME ||
665 state == STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME ||
666 event == TOGGLE_FULLSCREEN_CHROME) {
667 return true;
671 return false;
674 bool FullscreenControllerStateTest::ShouldSkipTest(State state, Event event) {
675 // Quietly skip metro snap tests when not on windows.
676 #if !defined(OS_WIN)
677 if (state == STATE_METRO_SNAP ||
678 event == METRO_SNAP_TRUE ||
679 event == METRO_SNAP_FALSE) {
680 debugging_log_ << "\nSkipping metro snap test on non-Windows.\n";
681 return true;
683 #endif
685 // Quietly skip Mac Lion Fullscreen tests when not on OSX 10.7+.
686 if (!SupportsMacSystemFullscreen()) {
687 if (state == STATE_BROWSER_FULLSCREEN_WITH_CHROME ||
688 event == TOGGLE_FULLSCREEN_CHROME) {
689 debugging_log_ << "\nSkipping Lion Fullscreen test on non-OSX 10.7+.\n";
690 return true;
694 // When testing reentrancy there are states the fullscreen controller
695 // will be unable to remain in, as they will progress due to the
696 // reentrant window change call. Skip states that will be instantly
697 // exited by the reentrant call.
698 if (IsWindowFullscreenStateChangedReentrant() &&
699 (transition_table_[state][WINDOW_CHANGE] != state)) {
700 debugging_log_ << "\nSkipping reentrant test for transitory source state "
701 << GetStateString(state) << ".\n";
702 return true;
705 if (ShouldSkipStateAndEventPair(state, event)) {
706 debugging_log_ << "\nSkipping test due to ShouldSkipStateAndEventPair("
707 << GetStateString(state) << ", "
708 << GetEventString(event) << ").\n";
709 LOG(INFO) << "Skipping test due to ShouldSkipStateAndEventPair("
710 << GetStateString(state) << ", "
711 << GetEventString(event) << ").";
712 return true;
715 return false;
718 void FullscreenControllerStateTest::TestStateAndEvent(State state,
719 Event event) {
720 if (ShouldSkipTest(state, event))
721 return;
723 debugging_log_ << "\nTest transition from state "
724 << GetStateString(state)
725 << (IsWindowFullscreenStateChangedReentrant() ?
726 " with reentrant calls.\n" : ".\n");
728 // Spaced out text to line up with columns printed in InvokeEvent().
729 debugging_log_ << "First, from "
730 << GetStateString(state_) << "\n";
731 ASSERT_NO_FATAL_FAILURE(TransitionToState(state))
732 << GetAndClearDebugLog();
734 debugging_log_ << " Then,\n";
735 ASSERT_TRUE(InvokeEvent(event)) << GetAndClearDebugLog();
738 void FullscreenControllerStateTest::VerifyWindowStateExpectations(
739 FullscreenWithToolbarExpectation fullscreen_with_toolbar,
740 FullscreenForBrowserExpectation fullscreen_for_browser,
741 FullscreenForTabExpectation fullscreen_for_tab,
742 InMetroSnapExpectation in_metro_snap) {
743 if (fullscreen_with_toolbar != FULLSCREEN_WITH_CHROME_NO_EXPECTATION &&
744 GetBrowser()->window()->SupportsFullscreenWithToolbar()) {
745 EXPECT_EQ(GetBrowser()->window()->IsFullscreenWithToolbar(),
746 !!fullscreen_with_toolbar) << GetAndClearDebugLog();
748 if (fullscreen_for_browser != FULLSCREEN_FOR_BROWSER_NO_EXPECTATION) {
749 EXPECT_EQ(GetFullscreenController()->IsFullscreenForBrowser(),
750 !!fullscreen_for_browser) << GetAndClearDebugLog();
752 if (fullscreen_for_tab != FULLSCREEN_FOR_TAB_NO_EXPECTATION) {
753 EXPECT_EQ(GetFullscreenController()->IsWindowFullscreenForTabOrPending(),
754 !!fullscreen_for_tab) << GetAndClearDebugLog();
757 #if defined(OS_WIN)
758 if (in_metro_snap != IN_METRO_SNAP_NO_EXPECTATION) {
759 EXPECT_EQ(GetFullscreenController()->IsInMetroSnapMode(),
760 !!in_metro_snap) << GetAndClearDebugLog();
762 #endif // OS_WIN
765 FullscreenController* FullscreenControllerStateTest::GetFullscreenController() {
766 return GetBrowser()->exclusive_access_manager()->fullscreen_controller();
769 std::string FullscreenControllerStateTest::GetTransitionTableAsString() const {
770 std::ostringstream output;
771 output << "transition_table_[NUM_STATES = " << NUM_STATES
772 << "][NUM_EVENTS = " << NUM_EVENTS
773 << "] =\n";
774 for (int state_int = 0; state_int < NUM_STATES; ++state_int) {
775 State state = static_cast<State>(state_int);
776 output << " { // " << GetStateString(state) << ":\n";
777 for (int event_int = 0; event_int < NUM_EVENTS; ++event_int) {
778 Event event = static_cast<Event>(event_int);
779 output << " "
780 << std::left << std::setw(kMaxStateNameLength+1)
781 << std::string(GetStateString(transition_table_[state][event])) + ","
782 << "// Event "
783 << GetEventString(event) << "\n";
785 output << " },\n";
787 output << " };\n";
788 return output.str();
791 std::string FullscreenControllerStateTest::GetStateTransitionsAsString() const {
792 std::ostringstream output;
793 output << "state_transitions_[NUM_STATES = " << NUM_STATES
794 << "][NUM_STATES = " << NUM_STATES << "] =\n";
795 for (int state1_int = 0; state1_int < NUM_STATES; ++state1_int) {
796 State state1 = static_cast<State>(state1_int);
797 output << "{ // " << GetStateString(state1) << ":\n";
798 for (int state2_int = 0; state2_int < NUM_STATES; ++state2_int) {
799 State state2 = static_cast<State>(state2_int);
800 const StateTransitionInfo& info = state_transitions_[state1][state2];
801 output << " { "
802 << std::left << std::setw(kMaxStateNameLength+1)
803 << std::string(GetEventString(info.event)) + ","
804 << std::left << std::setw(kMaxStateNameLength+1)
805 << std::string(GetStateString(info.state)) + ","
806 << std::right << std::setw(2)
807 << info.distance
808 << " }, // "
809 << GetStateString(state2) << "\n";
811 output << "},\n";
813 output << "};";
814 return output.str();