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"
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"
24 bool SupportsMacSystemFullscreen() {
25 #if defined(OS_MACOSX)
26 return chrome::mac::SupportsSystemFullscreen();
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
] = {
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
149 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
, // Event BUBBLE_EXIT_LINK
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
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
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
186 STATE_TO_TAB_FULLSCREEN
, // Event BUBBLE_EXIT_LINK
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
193 STATE_TO_TAB_FULLSCREEN
, // Event BUBBLE_DENY
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
)))
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() {
230 const char* FullscreenControllerStateTest::GetStateString(State 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
);
245 NOTREACHED() << "No string for state " << state
;
246 return "State-Unknown";
251 const char* FullscreenControllerStateTest::GetEventString(Event 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
);
265 NOTREACHED() << "No string for event " << event
;
266 return "Event-Unknown";
271 bool FullscreenControllerStateTest::IsWindowFullscreenStateChangedReentrant() {
272 #if defined(OS_MACOSX)
280 bool FullscreenControllerStateTest::IsPersistentState(State state
) {
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
:
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
:
303 void FullscreenControllerStateTest::TransitionToState(State final_state
) {
304 int max_steps
= NUM_STATES
;
305 while (max_steps
-- && TransitionAStepTowardState(final_state
))
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
)
321 StateTransitionInfo next
= NextTransitionInShortestPath(source_state
,
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();
333 return InvokeEvent(next
.event
);
336 const char* FullscreenControllerStateTest::GetWindowStateString() {
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
358 if (IsWindowFullscreenStateChangedReentrant())
359 next_state
= transition_table_
[next_state
][WINDOW_CHANGE
];
361 debugging_log_
<< " InvokeEvent(" << std::left
362 << std::setw(kMaxStateNameLength
) << GetEventString(event
)
364 << std::setw(kMaxStateNameLength
) << GetStateString(next_state
);
369 case TOGGLE_FULLSCREEN
:
370 GetFullscreenController()->ToggleBrowserFullscreenMode();
373 case TOGGLE_FULLSCREEN_CHROME
:
374 #if defined(OS_MACOSX)
375 if (chrome::mac::SupportsSystemFullscreen()) {
376 GetFullscreenController()->ToggleBrowserFullscreenWithToolbar();
380 NOTREACHED() << GetAndClearDebugLog();
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
,
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
;
401 case METRO_SNAP_TRUE
:
403 GetFullscreenController()->SetMetroSnapMode(true);
405 NOTREACHED() << GetAndClearDebugLog();
409 case METRO_SNAP_FALSE
:
411 GetFullscreenController()->SetMetroSnapMode(false);
413 NOTREACHED() << GetAndClearDebugLog();
417 case BUBBLE_EXIT_LINK
:
418 GetFullscreenController()->ExitExclusiveAccessToPreviousState();
423 ->exclusive_access_manager()
424 ->OnAcceptExclusiveAccessPermission();
429 ->exclusive_access_manager()
430 ->OnDenyExclusiveAccessPermission();
434 ChangeWindowFullscreenState();
438 NOTREACHED() << "InvokeEvent needs a handler for event "
439 << GetEventString(event
) << GetAndClearDebugLog();
443 if (GetWindowStateString())
444 debugging_log_
<< " Window state now " << GetWindowStateString() << "\n";
446 debugging_log_
<< "\n";
448 MaybeWaitForNotification();
454 void FullscreenControllerStateTest::VerifyWindowState() {
457 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE
,
458 FULLSCREEN_FOR_BROWSER_FALSE
,
459 FULLSCREEN_FOR_TAB_FALSE
,
460 IN_METRO_SNAP_FALSE
);
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
);
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
);
474 case STATE_METRO_SNAP
:
475 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_NO_EXPECTATION
,
476 FULLSCREEN_FOR_BROWSER_NO_EXPECTATION
,
477 FULLSCREEN_FOR_TAB_NO_EXPECTATION
,
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
);
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
);
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
);
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
);
505 case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
:
506 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_FALSE
,
507 #if defined(OS_MACOSX)
508 FULLSCREEN_FOR_BROWSER_TRUE
,
510 FULLSCREEN_FOR_BROWSER_FALSE
,
512 FULLSCREEN_FOR_TAB_NO_EXPECTATION
,
513 IN_METRO_SNAP_FALSE
);
516 case STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME
:
517 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_TRUE
,
518 #if defined(OS_MACOSX)
519 FULLSCREEN_FOR_BROWSER_TRUE
,
521 FULLSCREEN_FOR_BROWSER_FALSE
,
523 FULLSCREEN_FOR_TAB_NO_EXPECTATION
,
524 IN_METRO_SNAP_FALSE
);
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();
538 VerifyWindowStateExpectations(FULLSCREEN_WITH_CHROME_NO_EXPECTATION
,
539 FULLSCREEN_FOR_BROWSER_FALSE
,
540 FULLSCREEN_FOR_TAB_TRUE
,
541 IN_METRO_SNAP_FALSE
);
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
))
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
))
584 ASSERT_TRUE(InvokeEvent(event2
)) << GetAndClearDebugLog();
586 // Then, add an additional event to the sequence.
587 if (ShouldSkipStateAndEventPair(state_
, event3
))
589 ASSERT_TRUE(InvokeEvent(event3
)) << GetAndClearDebugLog();
596 FullscreenControllerStateTest::StateTransitionInfo
597 FullscreenControllerStateTest::NextTransitionInShortestPath(
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
))
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());
641 bool FullscreenControllerStateTest::ShouldSkipStateAndEventPair(State state
,
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
))
650 if (state
== STATE_TO_NORMAL
&& event
== TAB_FULLSCREEN_TRUE
)
653 // Skip metro snap state and events when not on windows.
655 if (state
== STATE_METRO_SNAP
||
656 event
== METRO_SNAP_TRUE
||
657 event
== METRO_SNAP_FALSE
)
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
) {
674 bool FullscreenControllerStateTest::ShouldSkipTest(State state
, Event event
) {
675 // Quietly skip metro snap tests when not on windows.
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";
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";
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";
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
) << ").";
718 void FullscreenControllerStateTest::TestStateAndEvent(State state
,
720 if (ShouldSkipTest(state
, event
))
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();
758 if (in_metro_snap
!= IN_METRO_SNAP_NO_EXPECTATION
) {
759 EXPECT_EQ(GetFullscreenController()->IsInMetroSnapMode(),
760 !!in_metro_snap
) << GetAndClearDebugLog();
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
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
);
780 << std::left
<< std::setw(kMaxStateNameLength
+1)
781 << std::string(GetStateString(transition_table_
[state
][event
])) + ","
783 << GetEventString(event
) << "\n";
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
];
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)
809 << GetStateString(state2
) << "\n";