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 "build/build_config.h"
6 #include "chrome/browser/ui/browser.h"
7 #include "chrome/browser/ui/browser_tabstrip.h"
8 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
9 #include "chrome/browser/ui/fullscreen/fullscreen_controller_state_test.h"
10 #include "chrome/test/base/browser_with_test_window_test.h"
11 #include "content/public/browser/web_contents.h"
12 #include "content/public/common/url_constants.h"
13 #include "testing/gtest/include/gtest/gtest.h"
15 // The FullscreenControllerStateUnitTest unit test suite exhastively tests
16 // the FullscreenController through all permutations of events. The behavior
17 // of the BrowserWindow is mocked via FullscreenControllerTestWindow.
19 // FullscreenControllerStateInteractiveTest is an interactive test suite
20 // used to verify that the FullscreenControllerTestWindow models the behavior
21 // of actual windows accurately. The interactive tests are too flaky to run
22 // on infrastructure, and so those tests are disabled. Run them with:
23 // interactive_ui_tests
24 // --gtest_filter="FullscreenControllerStateInteractiveTest.*"
25 // --gtest_also_run_disabled_tests
27 // A BrowserWindow used for testing FullscreenController. ----------------------
28 class FullscreenControllerTestWindow
: public TestBrowserWindow
{
30 // Simulate the window state with an enumeration.
34 // No TO_ state for METRO_SNAP, the windows implementation is synchronous.
40 FullscreenControllerTestWindow();
41 virtual ~FullscreenControllerTestWindow() {}
43 // BrowserWindow Interface:
44 virtual void EnterFullscreen(const GURL
& url
,
45 FullscreenExitBubbleType type
) OVERRIDE
;
46 virtual void EnterFullscreen();
47 virtual void ExitFullscreen() OVERRIDE
;
48 virtual bool IsFullscreen() const OVERRIDE
;
50 virtual void SetMetroSnapMode(bool enable
) OVERRIDE
;
51 virtual bool IsInMetroSnapMode() const OVERRIDE
;
53 #if defined(OS_MACOSX)
54 virtual void EnterPresentationMode(
56 FullscreenExitBubbleType bubble_type
) OVERRIDE
;
57 virtual void ExitPresentationMode() OVERRIDE
;
58 virtual bool InPresentationMode() OVERRIDE
;
61 static const char* GetWindowStateString(WindowState state
);
62 WindowState
state() const { return state_
; }
63 void set_browser(Browser
* browser
) { browser_
= browser
; }
64 void set_reentrant(bool value
) { reentrant_
= value
; }
65 bool reentrant() const { return reentrant_
; }
67 // Simulates the window changing state.
68 void ChangeWindowFullscreenState();
69 // Calls ChangeWindowFullscreenState() if |reentrant_| is true.
70 void ChangeWindowFullscreenStateIfReentrant();
74 bool mac_presentation_mode_
;
77 // Causes reentrant calls to be made by calling
78 // browser_->WindowFullscreenStateChanged() from the BrowserWindow
83 FullscreenControllerTestWindow::FullscreenControllerTestWindow()
85 mac_presentation_mode_(false),
90 void FullscreenControllerTestWindow::EnterFullscreen(
91 const GURL
& url
, FullscreenExitBubbleType type
) {
95 void FullscreenControllerTestWindow::EnterFullscreen() {
96 if (!IsFullscreen()) {
97 state_
= TO_FULLSCREEN
;
98 ChangeWindowFullscreenStateIfReentrant();
102 void FullscreenControllerTestWindow::ExitFullscreen() {
103 if (IsFullscreen()) {
105 mac_presentation_mode_
= false;
106 ChangeWindowFullscreenStateIfReentrant();
110 bool FullscreenControllerTestWindow::IsFullscreen() const {
111 #if defined(OS_MACOSX)
112 return state_
== FULLSCREEN
|| state_
== TO_FULLSCREEN
;
114 return state_
== FULLSCREEN
|| state_
== TO_NORMAL
;
119 void FullscreenControllerTestWindow::SetMetroSnapMode(bool enable
) {
120 if (enable
!= IsInMetroSnapMode()) {
126 ChangeWindowFullscreenStateIfReentrant();
129 bool FullscreenControllerTestWindow::IsInMetroSnapMode() const {
130 return state_
== METRO_SNAP
;
134 #if defined(OS_MACOSX)
135 void FullscreenControllerTestWindow::EnterPresentationMode(
137 FullscreenExitBubbleType bubble_type
) {
138 mac_presentation_mode_
= true;
142 void FullscreenControllerTestWindow::ExitPresentationMode() {
143 if (InPresentationMode()) {
144 mac_presentation_mode_
= false;
149 bool FullscreenControllerTestWindow::InPresentationMode() {
150 return mac_presentation_mode_
;
155 const char* FullscreenControllerTestWindow::GetWindowStateString(
165 return "TO_FULLSCREEN";
169 NOTREACHED() << "No string for state " << state
;
170 return "WindowState-Unknown";
174 void FullscreenControllerTestWindow::ChangeWindowFullscreenState() {
175 // Several states result in "no operation" intentionally. The tests
176 // assume that all possible states and event pairs can be tested, even
177 // though window managers will not generate all of these.
194 // Emit a change event from every state to ensure the Fullscreen Controller
195 // handles it in all circumstances.
196 browser_
->WindowFullscreenStateChanged();
199 void FullscreenControllerTestWindow::ChangeWindowFullscreenStateIfReentrant() {
201 ChangeWindowFullscreenState();
204 // Unit test fixture testing Fullscreen Controller through its states. ---------
205 class FullscreenControllerStateUnitTest
: public BrowserWithTestWindowTest
,
206 public FullscreenControllerStateTest
{
208 FullscreenControllerStateUnitTest();
210 // FullscreenControllerStateTest:
211 virtual void SetUp() OVERRIDE
;
212 virtual void ChangeWindowFullscreenState() OVERRIDE
;
213 virtual const char* GetWindowStateString() OVERRIDE
;
214 virtual void VerifyWindowState() OVERRIDE
;
217 // FullscreenControllerStateTest:
218 virtual bool ShouldSkipStateAndEventPair(State state
, Event event
) OVERRIDE
;
219 virtual void TestStateAndEvent(State state
,
221 bool reentrant
) OVERRIDE
;
222 virtual Browser
* GetBrowser() OVERRIDE
;
223 FullscreenControllerTestWindow
* window_
;
226 FullscreenControllerStateUnitTest::FullscreenControllerStateUnitTest ()
230 void FullscreenControllerStateUnitTest::SetUp() {
231 window_
= new FullscreenControllerTestWindow();
232 set_window(window_
); // BrowserWithTestWindowTest takes ownership.
233 BrowserWithTestWindowTest::SetUp();
234 window_
->set_browser(browser());
237 void FullscreenControllerStateUnitTest::ChangeWindowFullscreenState() {
238 window_
->ChangeWindowFullscreenState();
241 const char* FullscreenControllerStateUnitTest::GetWindowStateString() {
242 return FullscreenControllerTestWindow::GetWindowStateString(window_
->state());
245 void FullscreenControllerStateUnitTest::VerifyWindowState() {
248 EXPECT_EQ(FullscreenControllerTestWindow::NORMAL
,
249 window_
->state()) << GetAndClearDebugLog();
251 case STATE_BROWSER_FULLSCREEN_NO_CHROME
:
252 EXPECT_EQ(FullscreenControllerTestWindow::FULLSCREEN
,
253 window_
->state()) << GetAndClearDebugLog();
256 case STATE_METRO_SNAP
:
257 EXPECT_EQ(FullscreenControllerTestWindow::METRO_SNAP
,
258 window_
->state()) << GetAndClearDebugLog();
261 case STATE_TAB_FULLSCREEN
:
262 EXPECT_EQ(FullscreenControllerTestWindow::FULLSCREEN
,
263 window_
->state()) << GetAndClearDebugLog();
265 case STATE_TAB_BROWSER_FULLSCREEN
:
266 EXPECT_EQ(FullscreenControllerTestWindow::FULLSCREEN
,
267 window_
->state()) << GetAndClearDebugLog();
269 case STATE_TO_NORMAL
:
270 EXPECT_EQ(FullscreenControllerTestWindow::TO_NORMAL
,
271 window_
->state()) << GetAndClearDebugLog();
273 case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
:
274 EXPECT_EQ(FullscreenControllerTestWindow::TO_FULLSCREEN
,
275 window_
->state()) << GetAndClearDebugLog();
277 case STATE_TO_TAB_FULLSCREEN
:
278 EXPECT_EQ(FullscreenControllerTestWindow::TO_FULLSCREEN
,
279 window_
->state()) << GetAndClearDebugLog();
282 NOTREACHED() << GetAndClearDebugLog();
285 FullscreenControllerStateTest::VerifyWindowState();
288 bool FullscreenControllerStateUnitTest::ShouldSkipStateAndEventPair(
289 State state
, Event event
) {
290 #if defined(OS_MACOSX)
291 // TODO(scheib) Toggle, Window Event, Toggle, Toggle on Mac as exposed by
292 // test *.STATE_TO_NORMAL__TOGGLE_FULLSCREEN runs interactively and exits to
293 // Normal. This doesn't appear to be the desired result, and would add
294 // too much complexity to mimic in our simple FullscreenControllerTestWindow.
295 // http://crbug.com/156968
296 if ((state
== STATE_TO_NORMAL
||
297 state
== STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
||
298 state
== STATE_TO_TAB_FULLSCREEN
) &&
299 event
== TOGGLE_FULLSCREEN
)
303 return FullscreenControllerStateTest::ShouldSkipStateAndEventPair(state
,
307 void FullscreenControllerStateUnitTest::TestStateAndEvent(State state
,
310 window_
->set_reentrant(reentrant
);
311 FullscreenControllerStateTest::TestStateAndEvent(state
, event
, reentrant
);
314 Browser
* FullscreenControllerStateUnitTest::GetBrowser() {
315 return BrowserWithTestWindowTest::browser();
318 // Tests -----------------------------------------------------------------------
320 #define TEST_EVENT_INNER(state, event, reentrant, reentrant_id) \
321 TEST_F(FullscreenControllerStateUnitTest, \
322 state##__##event##reentrant_id) { \
323 AddTab(browser(), GURL(chrome::kAboutBlankURL)); \
324 ASSERT_NO_FATAL_FAILURE(TestStateAndEvent(state, event, reentrant)) \
325 << GetAndClearDebugLog(); \
327 // Progress of tests can be examined by inserting the following line:
328 // LOG(INFO) << GetAndClearDebugLog(); }
330 #define TEST_EVENT(state, event) \
331 TEST_EVENT_INNER(state, event, false, ); \
332 TEST_EVENT_INNER(state, event, true, _Reentrant);
334 // Individual tests for each pair of state and event:
336 TEST_EVENT(STATE_NORMAL
, TOGGLE_FULLSCREEN
);
337 TEST_EVENT(STATE_NORMAL
, TAB_FULLSCREEN_TRUE
);
338 TEST_EVENT(STATE_NORMAL
, TAB_FULLSCREEN_FALSE
);
340 TEST_EVENT(STATE_NORMAL
, METRO_SNAP_TRUE
);
341 TEST_EVENT(STATE_NORMAL
, METRO_SNAP_FALSE
);
343 TEST_EVENT(STATE_NORMAL
, WINDOW_CHANGE
);
345 TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME
, TOGGLE_FULLSCREEN
);
346 TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME
, TAB_FULLSCREEN_TRUE
);
347 TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME
, TAB_FULLSCREEN_FALSE
);
349 TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME
, METRO_SNAP_TRUE
);
350 TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME
, METRO_SNAP_FALSE
);
352 TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME
, WINDOW_CHANGE
);
355 TEST_EVENT(STATE_METRO_SNAP
, TOGGLE_FULLSCREEN
);
356 TEST_EVENT(STATE_METRO_SNAP
, TAB_FULLSCREEN_TRUE
);
357 TEST_EVENT(STATE_METRO_SNAP
, TAB_FULLSCREEN_FALSE
);
358 TEST_EVENT(STATE_METRO_SNAP
, METRO_SNAP_TRUE
);
359 TEST_EVENT(STATE_METRO_SNAP
, METRO_SNAP_FALSE
);
360 TEST_EVENT(STATE_METRO_SNAP
, WINDOW_CHANGE
);
363 TEST_EVENT(STATE_TAB_FULLSCREEN
, TOGGLE_FULLSCREEN
);
364 TEST_EVENT(STATE_TAB_FULLSCREEN
, TAB_FULLSCREEN_TRUE
);
365 TEST_EVENT(STATE_TAB_FULLSCREEN
, TAB_FULLSCREEN_FALSE
);
367 TEST_EVENT(STATE_TAB_FULLSCREEN
, METRO_SNAP_TRUE
);
368 TEST_EVENT(STATE_TAB_FULLSCREEN
, METRO_SNAP_FALSE
);
370 TEST_EVENT(STATE_TAB_FULLSCREEN
, WINDOW_CHANGE
);
372 TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN
, TOGGLE_FULLSCREEN
);
373 TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN
, TAB_FULLSCREEN_TRUE
);
374 TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN
, TAB_FULLSCREEN_FALSE
);
376 TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN
, METRO_SNAP_TRUE
);
377 TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN
, METRO_SNAP_FALSE
);
379 TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN
, WINDOW_CHANGE
);
381 TEST_EVENT(STATE_TO_NORMAL
, TOGGLE_FULLSCREEN
);
382 TEST_EVENT(STATE_TO_NORMAL
, TAB_FULLSCREEN_TRUE
);
383 TEST_EVENT(STATE_TO_NORMAL
, TAB_FULLSCREEN_FALSE
);
385 TEST_EVENT(STATE_TO_NORMAL
, METRO_SNAP_TRUE
);
386 TEST_EVENT(STATE_TO_NORMAL
, METRO_SNAP_FALSE
);
388 TEST_EVENT(STATE_TO_NORMAL
, WINDOW_CHANGE
);
390 TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
, TOGGLE_FULLSCREEN
);
391 TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
, TAB_FULLSCREEN_TRUE
);
392 TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
, TAB_FULLSCREEN_FALSE
);
394 TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
, METRO_SNAP_TRUE
);
395 TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
, METRO_SNAP_FALSE
);
397 TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
, WINDOW_CHANGE
);
399 TEST_EVENT(STATE_TO_TAB_FULLSCREEN
, TOGGLE_FULLSCREEN
);
400 TEST_EVENT(STATE_TO_TAB_FULLSCREEN
, TAB_FULLSCREEN_TRUE
);
401 TEST_EVENT(STATE_TO_TAB_FULLSCREEN
, TAB_FULLSCREEN_FALSE
);
403 TEST_EVENT(STATE_TO_TAB_FULLSCREEN
, METRO_SNAP_TRUE
);
404 TEST_EVENT(STATE_TO_TAB_FULLSCREEN
, METRO_SNAP_FALSE
);
406 TEST_EVENT(STATE_TO_TAB_FULLSCREEN
, WINDOW_CHANGE
);
408 // Specific one-off tests for known issues:
410 // TODO(scheib) Toggling Tab fullscreen while pending Tab or
411 // Browser fullscreen is broken currently http://crbug.com/154196
412 TEST_F(FullscreenControllerStateUnitTest
,
413 DISABLED_ToggleTabWhenPendingBrowser
) {
414 #if !defined(OS_WIN) // Only possible without reentrancy
415 AddTab(browser(), GURL(chrome::kAboutBlankURL
));
416 ASSERT_NO_FATAL_FAILURE(
417 TransitionToState(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
))
418 << GetAndClearDebugLog();
420 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
)) << GetAndClearDebugLog();
421 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE
)) << GetAndClearDebugLog();
422 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
)) << GetAndClearDebugLog();
426 // TODO(scheib) Toggling Tab fullscreen while pending Tab or
427 // Browser fullscreen is broken currently http://crbug.com/154196
428 TEST_F(FullscreenControllerStateUnitTest
, DISABLED_ToggleTabWhenPendingTab
) {
429 #if !defined(OS_WIN) // Only possible without reentrancy
430 AddTab(browser(), GURL(chrome::kAboutBlankURL
));
431 ASSERT_NO_FATAL_FAILURE(
432 TransitionToState(STATE_TO_TAB_FULLSCREEN
))
433 << GetAndClearDebugLog();
435 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
)) << GetAndClearDebugLog();
436 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE
)) << GetAndClearDebugLog();
437 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
)) << GetAndClearDebugLog();
443 // Tests all states with all permutations of multiple events to detect lingering
444 // state issues that would bleed over to other states.
445 // I.E. for each state test all combinations of events E1, E2, E3.
447 // This produces coverage for event sequences that may happen normally but
448 // would not be exposed by traversing to each state via TransitionToState().
449 // TransitionToState() always takes the same path even when multiple paths
451 TEST_F(FullscreenControllerStateUnitTest
, TransitionsForEachState
) {
452 // A tab is needed for tab fullscreen.
453 AddTab(browser(), GURL(chrome::kAboutBlankURL
));
454 TestTransitionsForEachState();
455 // Progress of test can be examined via LOG(INFO) << GetAndClearDebugLog();