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"
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"
27 bool SupportsMacSystemFullscreen() {
28 #if defined(OS_MACOSX)
29 return chrome::mac::SupportsSystemFullscreen();
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
] = {
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
152 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
, // Event BUBBLE_EXIT_LINK
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
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
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
189 STATE_TO_TAB_FULLSCREEN
, // Event BUBBLE_EXIT_LINK
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
196 STATE_TO_TAB_FULLSCREEN
, // Event BUBBLE_DENY
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
)))
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() {
233 const char* FullscreenControllerStateTest::GetStateString(State 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
);
248 NOTREACHED() << "No string for state " << state
;
249 return "State-Unknown";
254 const char* FullscreenControllerStateTest::GetEventString(Event 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
);
268 NOTREACHED() << "No string for event " << event
;
269 return "Event-Unknown";
274 bool FullscreenControllerStateTest::IsWindowFullscreenStateChangedReentrant() {
275 #if defined(TOOLKIT_VIEWS)
283 bool FullscreenControllerStateTest::IsPersistentState(State state
) {
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
:
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
:
306 void FullscreenControllerStateTest::TransitionToState(State final_state
) {
307 int max_steps
= NUM_STATES
;
308 while (max_steps
-- && TransitionAStepTowardState(final_state
))
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
)
324 StateTransitionInfo next
= NextTransitionInShortestPath(source_state
,
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();
336 return InvokeEvent(next
.event
);
339 const char* FullscreenControllerStateTest::GetWindowStateString() {
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
361 if (IsWindowFullscreenStateChangedReentrant())
362 next_state
= transition_table_
[next_state
][WINDOW_CHANGE
];
364 debugging_log_
<< " InvokeEvent(" << std::left
365 << std::setw(kMaxStateNameLength
) << GetEventString(event
)
367 << std::setw(kMaxStateNameLength
) << GetStateString(next_state
);
372 case TOGGLE_FULLSCREEN
:
373 GetFullscreenController()->ToggleFullscreenMode();
376 case TOGGLE_FULLSCREEN_CHROME
:
377 #if defined(OS_MACOSX)
378 if (chrome::mac::SupportsSystemFullscreen()) {
379 GetFullscreenController()->ToggleFullscreenWithChrome();
383 NOTREACHED() << GetAndClearDebugLog();
386 case TAB_FULLSCREEN_TRUE
:
387 GetFullscreenController()->ToggleFullscreenModeForTab(
388 GetBrowser()->tab_strip_model()->GetActiveWebContents(), true);
391 case TAB_FULLSCREEN_FALSE
:
392 GetFullscreenController()->ToggleFullscreenModeForTab(
393 GetBrowser()->tab_strip_model()->GetActiveWebContents(), false);
396 case METRO_SNAP_TRUE
:
398 GetFullscreenController()->SetMetroSnapMode(true);
400 NOTREACHED() << GetAndClearDebugLog();
404 case METRO_SNAP_FALSE
:
406 GetFullscreenController()->SetMetroSnapMode(false);
408 NOTREACHED() << GetAndClearDebugLog();
412 case BUBBLE_EXIT_LINK
:
413 GetFullscreenController()->ExitTabOrBrowserFullscreenToPreviousState();
417 GetFullscreenController()->OnAcceptFullscreenPermission();
421 GetFullscreenController()->OnDenyFullscreenPermission();
425 ChangeWindowFullscreenState();
429 NOTREACHED() << "InvokeEvent needs a handler for event "
430 << GetEventString(event
) << GetAndClearDebugLog();
434 if (GetWindowStateString())
435 debugging_log_
<< " Window state now " << GetWindowStateString() << "\n";
437 debugging_log_
<< "\n";
439 MaybeWaitForNotification();
445 void FullscreenControllerStateTest::VerifyWindowState() {
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
);
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
);
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
);
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
,
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
);
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
);
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
);
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
);
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
,
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 FULLSCREEN_WITHOUT_CHROME_FALSE
,
519 #if defined(OS_MACOSX)
520 FULLSCREEN_FOR_BROWSER_TRUE
,
522 FULLSCREEN_FOR_BROWSER_FALSE
,
524 FULLSCREEN_FOR_TAB_NO_EXPECTATION
,
525 IN_METRO_SNAP_FALSE
);
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();
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
);
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
))
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
))
586 ASSERT_TRUE(InvokeEvent(event2
)) << GetAndClearDebugLog();
588 // Then, add an additional event to the sequence.
589 if (ShouldSkipStateAndEventPair(state_
, event3
))
591 ASSERT_TRUE(InvokeEvent(event3
)) << GetAndClearDebugLog();
598 FullscreenControllerStateTest::StateTransitionInfo
599 FullscreenControllerStateTest::NextTransitionInShortestPath(
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
))
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());
643 bool FullscreenControllerStateTest::ShouldSkipStateAndEventPair(State state
,
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
))
652 if (state
== STATE_TO_NORMAL
&& event
== TAB_FULLSCREEN_TRUE
)
655 // Skip metro snap state and events when not on windows.
657 if (state
== STATE_METRO_SNAP
||
658 event
== METRO_SNAP_TRUE
||
659 event
== METRO_SNAP_FALSE
)
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
) {
676 bool FullscreenControllerStateTest::ShouldSkipTest(State state
, Event event
) {
677 // Quietly skip metro snap tests when not on windows.
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";
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";
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";
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
) << ").";
720 void FullscreenControllerStateTest::TestStateAndEvent(State state
,
722 if (ShouldSkipTest(state
, event
))
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();
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
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
);
785 << std::left
<< std::setw(kMaxStateNameLength
+1)
786 << std::string(GetStateString(transition_table_
[state
][event
])) + ","
788 << GetEventString(event
) << "\n";
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
];
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)
814 << GetStateString(state2
) << "\n";