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