diff options
author | scheib@chromium.org <scheib@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-10 00:03:12 +0000 |
---|---|---|
committer | scheib@chromium.org <scheib@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-10 00:03:12 +0000 |
commit | c36000e00d75b51321a18aff9260ee7f66f2b54e (patch) | |
tree | 0edd7507571527900e040bc9fccfb2c1411320e4 | |
parent | b3a259b88b030ec2786bd13a7dc79a951d7e4fb7 (diff) | |
download | chromium_src-c36000e00d75b51321a18aff9260ee7f66f2b54e.zip chromium_src-c36000e00d75b51321a18aff9260ee7f66f2b54e.tar.gz chromium_src-c36000e00d75b51321a18aff9260ee7f66f2b54e.tar.bz2 |
Refactor Fullscreen Controller State Machine tests to Interactive tests and Unit Tests.
Previously the state machine tests ran only as unit tests, and were not verified against actual operating system window behavior.
R=yzshen, phajdan.jr
chrome/browser/ui/fullscreen/*,
chrome/test/base/in_process_browser_test.cc
TBR=ben
chrome/chrome_tests.gypi &
chrome/browser/ui/cocoa/browser_window_controller.mm
BUG=146666
Review URL: https://chromiumcodereview.appspot.com/11264021
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@167011 0039d316-1c4b-4281-b951-d872f2087c98
14 files changed, 1458 insertions, 1027 deletions
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm index 8d62a40..90bb372 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller.mm @@ -2016,8 +2016,10 @@ willAnimateFromState:(bookmarks::VisualState)oldState [self setPresentationModeInternal:YES forceDropdown:YES]; [self releaseBarVisibilityForOwner:self withAnimation:YES delay:YES]; // Since -windowDidEnterFullScreen: won't be called in the - // fullscreen --> presentation mode case, manually show the exit bubble. + // fullscreen --> presentation mode case, manually show the exit bubble + // and notify the change happened with WindowFullscreenStateChanged(). [self showFullscreenExitBubbleIfNecessary]; + browser_->WindowFullscreenStateChanged(); } else { // If not in fullscreen mode, trigger the Lion fullscreen mode machinery. // Presentation mode will automatically be enabled in diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller.cc b/chrome/browser/ui/fullscreen/fullscreen_controller.cc index cf66456..289f6e2 100644 --- a/chrome/browser/ui/fullscreen/fullscreen_controller.cc +++ b/chrome/browser/ui/fullscreen/fullscreen_controller.cc @@ -110,6 +110,10 @@ void FullscreenController::ToggleFullscreenModeForTab(WebContents* web_contents, GetFullscreenSetting(url) == CONTENT_SETTING_ALLOW; } UpdateFullscreenExitBubbleContent(); + + // This is only a change between Browser and Tab fullscreen. We generate + // a fullscreen notification now because there is no window change. + PostFullscreenChangeNotification(true); } } else { if (in_browser_or_tab_fullscreen_mode) { @@ -126,6 +130,10 @@ void FullscreenController::ToggleFullscreenModeForTab(WebContents* web_contents, // case, all we have to do is notifying the tab that it has exited "tab // fullscreen" mode. NotifyTabOfExitIfNecessary(); + + // This is only a change between Browser and Tab fullscreen. We generate + // a fullscreen notification now because there is no window change. + PostFullscreenChangeNotification(true); } } } @@ -258,9 +266,7 @@ void FullscreenController::WindowFullscreenStateChanged() { #else exiting_fullscreen = !window_->IsFullscreen(); #endif - MessageLoop::current()->PostTask(FROM_HERE, - base::Bind(&FullscreenController::NotifyFullscreenChange, - ptr_factory_.GetWeakPtr(), !exiting_fullscreen)); + PostFullscreenChangeNotification(!exiting_fullscreen); if (exiting_fullscreen) NotifyTabOfExitIfNecessary(); if (exiting_fullscreen) @@ -441,6 +447,13 @@ void FullscreenController::UpdateNotificationRegistrations() { } } +void FullscreenController::PostFullscreenChangeNotification( + bool is_fullscreen) { + MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(&FullscreenController::NotifyFullscreenChange, + ptr_factory_.GetWeakPtr(), is_fullscreen)); +} + void FullscreenController::NotifyFullscreenChange(bool is_fullscreen) { content::NotificationService::current()->Notify( chrome::NOTIFICATION_FULLSCREEN_CHANGED, diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller.h b/chrome/browser/ui/fullscreen/fullscreen_controller.h index 918568c..7638076 100644 --- a/chrome/browser/ui/fullscreen/fullscreen_controller.h +++ b/chrome/browser/ui/fullscreen/fullscreen_controller.h @@ -130,6 +130,9 @@ class FullscreenController : public content::NotificationObserver { void UpdateNotificationRegistrations(); + // Posts a task to call NotifyFullscreenChange. + void PostFullscreenChangeNotification(bool is_fullscreen); + // Sends a NOTIFICATION_FULLSCREEN_CHANGED notification. void NotifyFullscreenChange(bool is_fullscreen); // Notifies the tab that it has been forced out of fullscreen and mouse lock // mode if necessary. diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller_browsertest.cc b/chrome/browser/ui/fullscreen/fullscreen_controller_browsertest.cc index a154431..c9da148 100644 --- a/chrome/browser/ui/fullscreen/fullscreen_controller_browsertest.cc +++ b/chrome/browser/ui/fullscreen/fullscreen_controller_browsertest.cc @@ -19,17 +19,17 @@ #include "base/mac/mac_util.h" #endif +using chrome::kAboutBlankURL; using content::WebContents; +using content::PAGE_TRANSITION_TYPED; class FullscreenControllerBrowserTest: public FullscreenControllerTest { }; IN_PROC_BROWSER_TEST_F(FullscreenControllerTest, PendingMouseLockExitsOnTabSwitch) { - AddTabAtIndexAndWait(0, GURL(chrome::kAboutBlankURL), - content::PAGE_TRANSITION_TYPED); - AddTabAtIndexAndWait(0, GURL(chrome::kAboutBlankURL), - content::PAGE_TRANSITION_TYPED); + AddTabAtIndex(0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); + AddTabAtIndex(0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); WebContents* tab1 = chrome::GetActiveWebContents(browser()); // Request mouse lock. Bubble is displayed. @@ -62,10 +62,8 @@ IN_PROC_BROWSER_TEST_F(FullscreenControllerTest, IN_PROC_BROWSER_TEST_F(FullscreenControllerTest, PendingMouseLockExitsOnTabClose) { // Add more tabs. - AddTabAtIndexAndWait(0, GURL(chrome::kAboutBlankURL), - content::PAGE_TRANSITION_TYPED); - AddTabAtIndexAndWait(0, GURL(chrome::kAboutBlankURL), - content::PAGE_TRANSITION_TYPED); + AddTabAtIndex(0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); + AddTabAtIndex(0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); // Request mouse lock. Bubble is displayed. RequestToLockMouse(true, false); diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller_interactive_browsertest.cc b/chrome/browser/ui/fullscreen/fullscreen_controller_interactive_browsertest.cc index 0dc9507..5882c69 100644 --- a/chrome/browser/ui/fullscreen/fullscreen_controller_interactive_browsertest.cc +++ b/chrome/browser/ui/fullscreen/fullscreen_controller_interactive_browsertest.cc @@ -20,7 +20,9 @@ #include "base/mac/mac_util.h" #endif +using chrome::kAboutBlankURL; using content::WebContents; +using content::PAGE_TRANSITION_TYPED; namespace { @@ -94,7 +96,7 @@ void FullscreenControllerInteractiveTest::ToggleBrowserFullscreen( void FullscreenControllerInteractiveTest::TestFullscreenMouseLockContentSettings() { GURL url = test_server()->GetURL("simple.html"); - AddTabAtIndexAndWait(0, url, content::PAGE_TRANSITION_TYPED); + AddTabAtIndex(0, url, PAGE_TRANSITION_TYPED); // Validate that going fullscreen for a URL defaults to asking permision. ASSERT_FALSE(IsFullscreenPermissionRequested()); @@ -154,23 +156,19 @@ FullscreenControllerInteractiveTest::TestFullscreenMouseLockContentSettings() { void FullscreenControllerInteractiveTest::ToggleTabFullscreen_Internal( bool enter_fullscreen, bool retry_until_success) { WebContents* tab = chrome::GetActiveWebContents(browser()); - if (IsFullscreenForBrowser()) { - // Changing tab fullscreen state will not actually change the window - // when browser fullscreen is in effect. + do { + FullscreenNotificationObserver fullscreen_observer; browser()->ToggleFullscreenModeForTab(tab, enter_fullscreen); - } else { // Not in browser fullscreen, expect window to actually change. - ASSERT_NE(browser()->window()->IsFullscreen(), enter_fullscreen); - do { - FullscreenNotificationObserver fullscreen_observer; - browser()->ToggleFullscreenModeForTab(tab, enter_fullscreen); - fullscreen_observer.Wait(); - // Repeat ToggleFullscreenModeForTab until the correct state is entered. - // This addresses flakiness on test bots running many fullscreen - // tests in parallel. - } while (retry_until_success && - browser()->window()->IsFullscreen() != enter_fullscreen); + fullscreen_observer.Wait(); + // Repeat ToggleFullscreenModeForTab until the correct state is entered. + // This addresses flakiness on test bots running many fullscreen + // tests in parallel. + } while (retry_until_success && + !IsFullscreenForBrowser() && + browser()->window()->IsFullscreen() != enter_fullscreen); + ASSERT_EQ(IsFullscreenForTabOrPending(), enter_fullscreen); + if (!IsFullscreenForBrowser()) ASSERT_EQ(browser()->window()->IsFullscreen(), enter_fullscreen); - } } // Tests /////////////////////////////////////////////////////////////////////// @@ -181,15 +179,13 @@ IN_PROC_BROWSER_TEST_F(FullscreenControllerInteractiveTest, DISABLED_TestNewTabExitsFullscreen) { ASSERT_TRUE(test_server()->Start()); - AddTabAtIndexAndWait( - 0, GURL(chrome::kAboutBlankURL), content::PAGE_TRANSITION_TYPED); + AddTabAtIndex(0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); ASSERT_NO_FATAL_FAILURE(ToggleTabFullscreen(true)); { FullscreenNotificationObserver fullscreen_observer; - AddTabAtIndexAndWait( - 1, GURL(chrome::kAboutBlankURL), content::PAGE_TRANSITION_TYPED); + AddTabAtIndex(1, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); fullscreen_observer.Wait(); ASSERT_FALSE(browser()->window()->IsFullscreen()); } @@ -201,8 +197,7 @@ IN_PROC_BROWSER_TEST_F(FullscreenControllerInteractiveTest, DISABLED_TestTabExitsItselfFromFullscreen) { ASSERT_TRUE(test_server()->Start()); - AddTabAtIndexAndWait( - 0, GURL(chrome::kAboutBlankURL), content::PAGE_TRANSITION_TYPED); + AddTabAtIndex(0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); ASSERT_NO_FATAL_FAILURE(ToggleTabFullscreen(true)); ASSERT_NO_FATAL_FAILURE(ToggleTabFullscreen(false)); @@ -215,10 +210,8 @@ IN_PROC_BROWSER_TEST_F(FullscreenControllerInteractiveTest, DISABLED_TestFullscreenBubbleMouseLockState) { ASSERT_TRUE(test_server()->Start()); - AddTabAtIndexAndWait(0, GURL(chrome::kAboutBlankURL), - content::PAGE_TRANSITION_TYPED); - AddTabAtIndexAndWait(1, GURL(chrome::kAboutBlankURL), - content::PAGE_TRANSITION_TYPED); + AddTabAtIndex(0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); + AddTabAtIndex(1, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); ASSERT_NO_FATAL_FAILURE(ToggleTabFullscreen(true)); @@ -257,8 +250,7 @@ IN_PROC_BROWSER_TEST_F(FullscreenControllerInteractiveTest, ASSERT_NO_FATAL_FAILURE(ToggleBrowserFullscreen(true)); // Enter tab fullscreen. - AddTabAtIndexAndWait(0, GURL(chrome::kAboutBlankURL), - content::PAGE_TRANSITION_TYPED); + AddTabAtIndex(0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); ASSERT_NO_FATAL_FAILURE(ToggleTabFullscreen(true)); // Exit browser fullscreen. @@ -274,8 +266,7 @@ IN_PROC_BROWSER_TEST_F(FullscreenControllerInteractiveTest, ASSERT_NO_FATAL_FAILURE(ToggleBrowserFullscreen(true)); // Enter and then exit tab fullscreen. - AddTabAtIndexAndWait(0, GURL(chrome::kAboutBlankURL), - content::PAGE_TRANSITION_TYPED); + AddTabAtIndex(0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); ASSERT_NO_FATAL_FAILURE(ToggleTabFullscreen(true)); ASSERT_NO_FATAL_FAILURE(ToggleTabFullscreen(false)); @@ -369,8 +360,7 @@ IN_PROC_BROWSER_TEST_F( FullscreenControllerTest, DISABLED_TabEntersPresentationModeFromWindowed) { ASSERT_TRUE(test_server()->Start()); - AddTabAtIndexAndWait( - 0, GURL(chrome::kAboutBlankURL), content::PAGE_TRANSITION_TYPED); + AddTabAtIndex(0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); WebContents* tab = chrome::GetActiveWebContents(browser()); @@ -877,7 +867,7 @@ IN_PROC_BROWSER_TEST_F(FullscreenControllerInteractiveTest, // http://crbug.com/133831 GURL url = test_server()->GetURL("simple.html"); - AddTabAtIndexAndWait(0, url, content::PAGE_TRANSITION_TYPED); + AddTabAtIndex(0, url, PAGE_TRANSITION_TYPED); // Validate that going fullscreen for a URL defaults to asking permision. ASSERT_FALSE(IsFullscreenPermissionRequested()); diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller_state_interactive_browsertest.cc b/chrome/browser/ui/fullscreen/fullscreen_controller_state_interactive_browsertest.cc new file mode 100644 index 0000000..1cc5739 --- /dev/null +++ b/chrome/browser/ui/fullscreen/fullscreen_controller_state_interactive_browsertest.cc @@ -0,0 +1,226 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "build/build_config.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_tabstrip.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/fullscreen/fullscreen_controller.h" +#include "chrome/browser/ui/fullscreen/fullscreen_controller_state_test.h" +#include "chrome/browser/ui/fullscreen/fullscreen_controller_test.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/url_constants.h" +#include "content/public/test/test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +using chrome::kAboutBlankURL; +using content::PAGE_TRANSITION_TYPED; + +// Interactive test fixture testing Fullscreen Controller through its states. -- +// See documentation at the top of fullscreen_controller_state_unittest.cc. +class FullscreenControllerStateInteractiveTest + : public InProcessBrowserTest, + public FullscreenControllerStateTest { + public: + // FullscreenControllerStateTest: + virtual void ChangeWindowFullscreenState() OVERRIDE; + virtual bool InvokeEvent(Event event) OVERRIDE; + + protected: + // FullscreenControllerStateTest: + virtual bool ShouldSkipTest(State state, + Event event, + bool reentrant) OVERRIDE; + virtual Browser* GetBrowser() OVERRIDE; + + scoped_ptr<FullscreenNotificationObserver> fullscreen_observer_; +}; + +void FullscreenControllerStateInteractiveTest::ChangeWindowFullscreenState() { + if (fullscreen_observer_) { + // If tests are stuck here, use the following log command to see progress. + // LOG(INFO) << GetAndClearDebugLog(); + fullscreen_observer_->Wait(); + fullscreen_observer_.reset(NULL); + } +} + +bool FullscreenControllerStateInteractiveTest::InvokeEvent(Event event) { + switch (event) { + case TOGGLE_FULLSCREEN: + case TAB_FULLSCREEN_TRUE: + case TAB_FULLSCREEN_FALSE: +#if defined(OS_WIN) + case METRO_SNAP_TRUE: + case METRO_SNAP_FALSE: +#endif + fullscreen_observer_.reset(new FullscreenNotificationObserver()); + break; + case WINDOW_CHANGE: + // ChangeWindowFullscreenState() will be called and then wait on + // fullscreen_observer_ if needed. + break; + default: + NOTREACHED() << "InvokeEvent needs a handler for event " + << GetEventString(event) << GetAndClearDebugLog(); + return false; + } + + return FullscreenControllerStateTest::InvokeEvent(event); +} + +bool FullscreenControllerStateInteractiveTest::ShouldSkipTest(State state, + Event event, + bool reentrant) { + // Interactive tests run reentrant or not based on the platform + // implementation, so limit our test runs to match. +#if defined(OS_WIN) + if (!reentrant) { + debugging_log_ << "\nSkipping non-reentrant test on Windows.\n"; + return true; + } +#else + if (reentrant) { + debugging_log_ << "\nSkipping reentrant test on non-Windows.\n"; + return true; + } +#endif + + return FullscreenControllerStateTest::ShouldSkipTest(state, + event, + reentrant); +} + +Browser* FullscreenControllerStateInteractiveTest::GetBrowser() { + return InProcessBrowserTest::browser(); +} + +// Tests ----------------------------------------------------------------------- + +#define TEST_EVENT_INNER(state, event, reentrant, reentrant_id) \ + IN_PROC_BROWSER_TEST_F(FullscreenControllerStateInteractiveTest, \ + DISABLED_##state##__##event##reentrant_id) { \ + AddTabAtIndex(0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); \ + ASSERT_NO_FATAL_FAILURE(TestStateAndEvent(state, event, reentrant)) \ + << GetAndClearDebugLog(); \ + } + // Progress of tests can be examined by inserting the following line: + // LOG(INFO) << GetAndClearDebugLog(); } + +#define TEST_EVENT(state, event) \ + TEST_EVENT_INNER(state, event, false, ); \ + TEST_EVENT_INNER(state, event, true, _Reentrant); + +// Individual tests for each pair of state and event: + +TEST_EVENT(STATE_NORMAL, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_NORMAL, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_NORMAL, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_NORMAL, METRO_SNAP_TRUE); +TEST_EVENT(STATE_NORMAL, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_NORMAL, WINDOW_CHANGE); + +TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, METRO_SNAP_TRUE); +TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, WINDOW_CHANGE); + +#if defined(OS_WIN) +TEST_EVENT(STATE_METRO_SNAP, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_METRO_SNAP, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_METRO_SNAP, TAB_FULLSCREEN_FALSE); +TEST_EVENT(STATE_METRO_SNAP, METRO_SNAP_TRUE); +TEST_EVENT(STATE_METRO_SNAP, METRO_SNAP_FALSE); +TEST_EVENT(STATE_METRO_SNAP, WINDOW_CHANGE); +#endif + +TEST_EVENT(STATE_TAB_FULLSCREEN, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_TAB_FULLSCREEN, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_TAB_FULLSCREEN, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_TAB_FULLSCREEN, METRO_SNAP_TRUE); +TEST_EVENT(STATE_TAB_FULLSCREEN, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_TAB_FULLSCREEN, WINDOW_CHANGE); + +TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, METRO_SNAP_TRUE); +TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, WINDOW_CHANGE); + +TEST_EVENT(STATE_TO_NORMAL, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_TO_NORMAL, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_TO_NORMAL, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_TO_NORMAL, METRO_SNAP_TRUE); +TEST_EVENT(STATE_TO_NORMAL, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_TO_NORMAL, WINDOW_CHANGE); + +TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, METRO_SNAP_TRUE); +TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, WINDOW_CHANGE); + +TEST_EVENT(STATE_TO_TAB_FULLSCREEN, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_TO_TAB_FULLSCREEN, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_TO_TAB_FULLSCREEN, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_TO_TAB_FULLSCREEN, METRO_SNAP_TRUE); +TEST_EVENT(STATE_TO_TAB_FULLSCREEN, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_TO_TAB_FULLSCREEN, WINDOW_CHANGE); + +// Specific one-off tests for known issues: + +// Used manually to determine what happens on a platform. +IN_PROC_BROWSER_TEST_F(FullscreenControllerStateInteractiveTest, + DISABLED_ManualTest) { + // A tab is needed for tab fullscreen. + AddTabAtIndex(0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); + ASSERT_TRUE(InvokeEvent(TOGGLE_FULLSCREEN)) << GetAndClearDebugLog(); + ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE)) << GetAndClearDebugLog(); + ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE)) << GetAndClearDebugLog(); + ASSERT_TRUE(InvokeEvent(TOGGLE_FULLSCREEN)) << GetAndClearDebugLog(); + ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE)) << GetAndClearDebugLog(); + + // Wait, allowing human operator to observe the result. + scoped_refptr<content::MessageLoopRunner> message_loop; + message_loop = new content::MessageLoopRunner(); + message_loop->Run(); +} + +// Soak tests: + +// Tests all states with all permutations of multiple events to detect lingering +// state issues that would bleed over to other states. +// I.E. for each state test all combinations of events E1, E2, E3. +// +// This produces coverage for event sequences that may happen normally but +// would not be exposed by traversing to each state via TransitionToState(). +// TransitionToState() always takes the same path even when multiple paths +// exist. +IN_PROC_BROWSER_TEST_F(FullscreenControllerStateInteractiveTest, + DISABLED_TransitionsForEachState) { + // A tab is needed for tab fullscreen. + AddTabAtIndex(0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED); + TestTransitionsForEachState(); + // Progress of test can be examined via LOG(INFO) << GetAndClearDebugLog(); +} + diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller_state_test.cc b/chrome/browser/ui/fullscreen/fullscreen_controller_state_test.cc new file mode 100644 index 0000000..09283b4 --- /dev/null +++ b/chrome/browser/ui/fullscreen/fullscreen_controller_state_test.cc @@ -0,0 +1,570 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/fullscreen/fullscreen_controller_state_test.h" + +#include <memory.h> + +#include <iomanip> +#include <iostream> + +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_tabstrip.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/fullscreen/fullscreen_controller.h" +#include "content/public/common/url_constants.h" +#include "testing/gtest/include/gtest/gtest.h" + +FullscreenControllerStateTest::FullscreenControllerStateTest() + : state_(STATE_NORMAL), + reentrant_(false) { + // Human specified state machine data. + // For each state, for each event, define the resulting state. + State transition_table_data[][NUM_EVENTS] = { + { // STATE_NORMAL: + STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN + STATE_TO_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE + STATE_NORMAL, // Event TAB_FULLSCREEN_FALSE +#if defined(OS_WIN) + STATE_METRO_SNAP, // Event METRO_SNAP_TRUE + STATE_NORMAL, // Event METRO_SNAP_FALSE +#endif + STATE_NORMAL, // Event WINDOW_CHANGE + }, + { // STATE_BROWSER_FULLSCREEN_NO_CHROME: + STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN + STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE + STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE +#if defined(OS_WIN) + STATE_METRO_SNAP, // Event METRO_SNAP_TRUE + STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event METRO_SNAP_FALSE +#endif + STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event WINDOW_CHANGE + }, +#if defined(OS_WIN) + { // STATE_METRO_SNAP: + STATE_METRO_SNAP, // Event TOGGLE_FULLSCREEN + STATE_METRO_SNAP, // Event TAB_FULLSCREEN_TRUE + STATE_METRO_SNAP, // Event TAB_FULLSCREEN_FALSE + STATE_METRO_SNAP, // Event METRO_SNAP_TRUE + STATE_NORMAL, // Event METRO_SNAP_FALSE + STATE_METRO_SNAP, // Event WINDOW_CHANGE + }, +#endif + { // STATE_TAB_FULLSCREEN: + STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN + STATE_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE + STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE +#if defined(OS_WIN) + STATE_METRO_SNAP, // Event METRO_SNAP_TRUE + STATE_TAB_FULLSCREEN, // Event METRO_SNAP_FALSE +#endif + STATE_TAB_FULLSCREEN, // Event WINDOW_CHANGE + }, + { // STATE_TAB_BROWSER_FULLSCREEN: + STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN + STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE +#if defined(OS_MACOSX) + // TODO(scheib) Mac exits browser mode too http://crbug.com/155642 + STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE +#else + STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE +#endif +#if defined(OS_WIN) + STATE_METRO_SNAP, // Event METRO_SNAP_TRUE + STATE_TAB_BROWSER_FULLSCREEN, // Event METRO_SNAP_FALSE +#endif + STATE_TAB_BROWSER_FULLSCREEN, // Event WINDOW_CHANGE + }, + // STATE_TO_NORMAL: + { STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN + // TODO(scheib) Should be a route back to TAB. http://crbug.com/154196 + STATE_TO_NORMAL, // Event TAB_FULLSCREEN_TRUE + STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE +#if defined(OS_WIN) + STATE_METRO_SNAP, // Event METRO_SNAP_TRUE + STATE_TO_NORMAL, // Event METRO_SNAP_FALSE +#endif + STATE_NORMAL, // Event WINDOW_CHANGE + }, + // STATE_TO_BROWSER_FULLSCREEN_NO_CHROME: + { STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN + // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196 + STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_TRUE + STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE +#if defined(OS_WIN) + STATE_METRO_SNAP, // Event METRO_SNAP_TRUE + STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event METRO_SNAP_FALSE +#endif + STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event WINDOW_CHANGE + }, + // STATE_TO_TAB_FULLSCREEN: + { // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196 + STATE_TO_TAB_FULLSCREEN, // Event TOGGLE_FULLSCREEN + STATE_TO_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE + // TODO(scheib) Should be a route back to NORMAL. http://crbug.com/154196 + STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE +#if defined(OS_WIN) + STATE_METRO_SNAP, // Event METRO_SNAP_TRUE + STATE_TO_TAB_FULLSCREEN, // Event METRO_SNAP_FALSE +#endif + STATE_TAB_FULLSCREEN, // Event WINDOW_CHANGE + }, + }; + CHECK_EQ(sizeof(transition_table_data), sizeof(transition_table_)); + memcpy(transition_table_, transition_table_data, + sizeof(transition_table_data)); + + // Verify that transition_table_ has been completely defined. + for (int source = 0; source < NUM_STATES; source++) { + for (int event = 0; event < NUM_EVENTS; event++) { + CHECK_NE(STATE_INVALID, transition_table_[source][event]); + CHECK_LE(0, transition_table_[source][event]); + CHECK_GT(NUM_STATES, transition_table_[source][event]); + } + } + + // Copy transition_table_ data into state_transitions_ table. + for (int source = 0; source < NUM_STATES; source++) { + for (int event = 0; event < NUM_EVENTS; event++) { + State destination = transition_table_[source][event]; + state_transitions_[source][destination].event = static_cast<Event>(event); + state_transitions_[source][destination].state = destination; + state_transitions_[source][destination].distance = 1; + } + } +} + +FullscreenControllerStateTest::~FullscreenControllerStateTest() { +} + +// static +const char* FullscreenControllerStateTest::GetStateString(State state) { + switch (state) { + case STATE_NORMAL: + return "STATE_NORMAL"; + case STATE_BROWSER_FULLSCREEN_NO_CHROME: + return "STATE_BROWSER_FULLSCREEN_NO_CHROME"; +#if defined(OS_WIN) + case STATE_METRO_SNAP: + return "STATE_METRO_SNAP"; +#endif + case STATE_TAB_FULLSCREEN: + return "STATE_TAB_FULLSCREEN"; + case STATE_TAB_BROWSER_FULLSCREEN: + return "STATE_TAB_BROWSER_FULLSCREEN"; + case STATE_TO_NORMAL: + return "STATE_TO_NORMAL"; + case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME: + return "STATE_TO_BROWSER_FULLSCREEN_NO_CHROME"; + case STATE_TO_TAB_FULLSCREEN: + return "STATE_TO_TAB_FULLSCREEN"; + case STATE_INVALID: + return "STATE_INVALID"; + default: + NOTREACHED() << "No string for state " << state; + return "State-Unknown"; + } +} + +// static +const char* FullscreenControllerStateTest::GetEventString(Event event) { + switch (event) { + case TOGGLE_FULLSCREEN: + return "TOGGLE_FULLSCREEN"; + case TAB_FULLSCREEN_TRUE: + return "TAB_FULLSCREEN_TRUE"; + case TAB_FULLSCREEN_FALSE: + return "TAB_FULLSCREEN_FALSE"; +#if defined(OS_WIN) + case METRO_SNAP_TRUE: + return "METRO_SNAP_TRUE"; + case METRO_SNAP_FALSE: + return "METRO_SNAP_FALSE"; +#endif + case WINDOW_CHANGE: + return "WINDOW_CHANGE"; + case EVENT_INVALID: + return "EVENT_INVALID"; + default: + NOTREACHED() << "No string for event " << event; + return "Event-Unknown"; + } +} + +void FullscreenControllerStateTest::TransitionToState(State final_state) { + int max_steps = NUM_STATES; + while (max_steps-- && TransitionAStepTowardState(final_state)) + continue; + ASSERT_GE(max_steps, 0) << "TransitionToState was unable to achieve desired " + << "target state. TransitionAStepTowardState iterated too many times." + << GetAndClearDebugLog(); + ASSERT_EQ(final_state, state_) << "TransitionToState was unable to achieve " + << "desired target state. TransitionAStepTowardState returned false." + << GetAndClearDebugLog(); +} + +bool FullscreenControllerStateTest::TransitionAStepTowardState( + State destination_state) { + State source_state = state_; + if (source_state == destination_state) + return false; + + StateTransitionInfo next = NextTransitionInShortestPath(source_state, + destination_state, + NUM_STATES); + if (next.state == STATE_INVALID) { + NOTREACHED() << "TransitionAStepTowardState unable to transition. " + << "NextTransitionInShortestPath(" + << GetStateString(source_state) << ", " + << GetStateString(destination_state) << ") returned STATE_INVALID." + << GetAndClearDebugLog(); + return false; + } + + return InvokeEvent(next.event); +} + +const char* FullscreenControllerStateTest::GetWindowStateString() { + return NULL; +} + +bool FullscreenControllerStateTest::InvokeEvent(Event event) { + State source_state = state_; + State next_state = transition_table_[source_state][event]; + + // When simulating reentrant window change calls, expect the next state + // automatically. + if (reentrant_) + next_state = transition_table_[next_state][WINDOW_CHANGE]; + + debugging_log_ << " InvokeEvent(" << std::left + << std::setw(MAX_EVENT_NAME_LENGTH) << GetEventString(event) + << ") to " + << std::setw(MAX_STATE_NAME_LENGTH) << GetStateString(next_state); + + state_ = next_state; + + switch (event) { + case TOGGLE_FULLSCREEN: + GetFullscreenController()->ToggleFullscreenMode(); + break; + case TAB_FULLSCREEN_TRUE: + GetFullscreenController()->ToggleFullscreenModeForTab( + chrome::GetActiveWebContents(GetBrowser()), true); + break; + case TAB_FULLSCREEN_FALSE: + GetFullscreenController()->ToggleFullscreenModeForTab( + chrome::GetActiveWebContents(GetBrowser()), false); + break; +#if defined(OS_WIN) + case METRO_SNAP_TRUE: + GetFullscreenController()->SetMetroSnapMode(true); + break; + case METRO_SNAP_FALSE: + GetFullscreenController()->SetMetroSnapMode(false); + break; +#endif + case WINDOW_CHANGE: + ChangeWindowFullscreenState(); + break; + default: + NOTREACHED() << "InvokeEvent needs a handler for event " + << GetEventString(event) << GetAndClearDebugLog(); + return false; + } + + if (GetWindowStateString()) + debugging_log_ << " Window state now " << GetWindowStateString() << "\n"; + else + debugging_log_ << "\n"; + + VerifyWindowState(); + + return true; +} + +void FullscreenControllerStateTest::VerifyWindowState() { + switch (state_) { + case STATE_NORMAL: +#if defined(OS_MACOSX) + EXPECT_FALSE(GetBrowser()->window()->InPresentationMode()) + << GetAndClearDebugLog(); +#endif + EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser()) + << GetAndClearDebugLog(); + EXPECT_FALSE(GetFullscreenController()->IsFullscreenForTabOrPending()) + << GetAndClearDebugLog(); + EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) + << GetAndClearDebugLog(); + break; + case STATE_BROWSER_FULLSCREEN_NO_CHROME: +#if defined(OS_MACOSX) + EXPECT_FALSE(GetBrowser()->window()->InPresentationMode()) + << GetAndClearDebugLog(); +#endif + EXPECT_TRUE(GetFullscreenController()->IsFullscreenForBrowser()) + << GetAndClearDebugLog(); + EXPECT_FALSE(GetFullscreenController()->IsFullscreenForTabOrPending()) + << GetAndClearDebugLog(); + EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) + << GetAndClearDebugLog(); + break; +#if defined(OS_WIN) + case STATE_METRO_SNAP: + // No expectation for InPresentationMode. + + // TODO(scheib) IsFullscreenForBrowser and IsFullscreenForTabOrPending + // are returning true and false in interactive tests with real window. + // With only a single Metro Snap state in this test framework it isn't + // fair to try to have an expectation anyway. + // + // No expectation for IsFullscreenForBrowser. + // No expectation for IsFullscreenForTabOrPending. + EXPECT_TRUE(GetFullscreenController()->IsInMetroSnapMode()) + << GetAndClearDebugLog(); + break; +#endif + case STATE_TAB_FULLSCREEN: +#if defined(OS_MACOSX) + EXPECT_TRUE(GetBrowser()->window()->InPresentationMode()) + << GetAndClearDebugLog(); +#endif + EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser()) + << GetAndClearDebugLog(); + EXPECT_TRUE(GetFullscreenController()->IsFullscreenForTabOrPending()) + << GetAndClearDebugLog(); + EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) + << GetAndClearDebugLog(); + break; + case STATE_TAB_BROWSER_FULLSCREEN: +#if defined(OS_MACOSX) + EXPECT_TRUE(GetBrowser()->window()->InPresentationMode()) + << GetAndClearDebugLog(); +#endif +#if defined(OS_MACOSX) + // TODO(scheib) Mac is reporting incorrect IsFullscreenForBrowser(). + // e.g. in FullscreenControllerStateTest. + // STATE_BROWSER_FULLSCREEN_NO_CHROME__TAB_FULLSCREEN_TRUE + // At the end of ToggleFullscreenModeForTab + // tab_caused_fullscreen_ has incorrectly been set to true even + // though controller was already in browser fullscreen. + // http://crbug.com/155650 + EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser()) + << GetAndClearDebugLog(); +#else + EXPECT_TRUE(GetFullscreenController()->IsFullscreenForBrowser()) + << GetAndClearDebugLog(); +#endif + EXPECT_TRUE(GetFullscreenController()->IsFullscreenForTabOrPending()) + << GetAndClearDebugLog(); + EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) + << GetAndClearDebugLog(); + break; + case STATE_TO_NORMAL: +#if defined(OS_MACOSX) + EXPECT_FALSE(GetBrowser()->window()->InPresentationMode()) + << GetAndClearDebugLog(); +#endif + // No expectation for IsFullscreenForBrowser. + // No expectation for IsFullscreenForTabOrPending. + EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) + << GetAndClearDebugLog(); + break; + case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME: +#if defined(OS_MACOSX) + EXPECT_FALSE(GetBrowser()->window()->InPresentationMode()) + << GetAndClearDebugLog(); + EXPECT_TRUE(GetFullscreenController()->IsFullscreenForBrowser()) + << GetAndClearDebugLog(); +#else + EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser()) + << GetAndClearDebugLog(); +#endif + // No expectation for IsFullscreenForTabOrPending. + EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) + << GetAndClearDebugLog(); + break; + case STATE_TO_TAB_FULLSCREEN: +#if defined(OS_MACOSX) + // TODO(scheib) InPresentationMode returns false when invoking events: + // TAB_FULLSCREEN_TRUE, TOGGLE_FULLSCREEN. http://crbug.com/156645 + // It may be that a new testing state TO_TAB_BROWSER_FULLSCREEN + // would help work around this http://crbug.com/154196 + // Test with: STATE_TO_TAB_FULLSCREEN__TOGGLE_FULLSCREEN + // + // EXPECT_TRUE(GetBrowser()->window()->InPresentationMode()) + // << GetAndClearDebugLog(); +#endif + EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser()) + << GetAndClearDebugLog(); + EXPECT_TRUE(GetFullscreenController()->IsFullscreenForTabOrPending()) + << GetAndClearDebugLog(); + EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) + << GetAndClearDebugLog(); + break; + default: + NOTREACHED() << GetAndClearDebugLog(); + } +} + +void FullscreenControllerStateTest::TestTransitionsForEachState() { + for (int reentrant = 0; reentrant <= 1; reentrant++) { + for (int source_int = 0; source_int < NUM_STATES; source_int++) { + for (int event1_int = 0; event1_int < NUM_EVENTS; event1_int++) { + State state = static_cast<State>(source_int); + Event event1 = static_cast<Event>(event1_int); + + // Early out if skipping all tests for this state, reduces log noise. + if (ShouldSkipTest(state, event1, !!reentrant)) + continue; + + for (int event2_int = 0; event2_int < NUM_EVENTS; event2_int++) { + for (int event3_int = 0; event3_int < NUM_EVENTS; event3_int++) { + Event event2 = static_cast<Event>(event2_int); + Event event3 = static_cast<Event>(event3_int); + + // Test each state and each event. + ASSERT_NO_FATAL_FAILURE(TestStateAndEvent(state, + event1, + !!reentrant)) + << GetAndClearDebugLog(); + + // Then, add an additional event to the sequence. + if (ShouldSkipStateAndEventPair(state_, event2)) + continue; + ASSERT_TRUE(InvokeEvent(event2)) << GetAndClearDebugLog(); + + // Then, add an additional event to the sequence. + if (ShouldSkipStateAndEventPair(state_, event3)) + continue; + ASSERT_TRUE(InvokeEvent(event3)) << GetAndClearDebugLog(); + } + } + } + } + } +} + +FullscreenControllerStateTest::StateTransitionInfo + FullscreenControllerStateTest::NextTransitionInShortestPath( + State source, State destination, int search_limit) { + if (search_limit == 0) + return StateTransitionInfo(); // Return a default (invalid) state. + + if (state_transitions_[source][destination].state == STATE_INVALID) { + // Don't know the next state yet, do a depth first search. + StateTransitionInfo result; + + // Consider all states reachable via each event from the source state. + for (int event_int = 0; event_int < NUM_EVENTS; event_int++) { + Event event = static_cast<Event>(event_int); + State next_state_candidate = transition_table_[source][event]; + + if (ShouldSkipStateAndEventPair(source, event)) + continue; + + // Recurse. + StateTransitionInfo candidate = NextTransitionInShortestPath( + next_state_candidate, destination, search_limit - 1); + + if (candidate.distance + 1 < result.distance) { + result.event = event; + result.state = next_state_candidate; + result.distance = candidate.distance + 1; + } + } + + // Cache result so that a search is not required next time. + state_transitions_[source][destination] = result; + } + + return state_transitions_[source][destination]; +} + +std::string FullscreenControllerStateTest::GetAndClearDebugLog() { + debugging_log_ << "(End of Debugging Log)\n"; + std::string output_log = "\nDebugging Log:\n" + debugging_log_.str(); + debugging_log_.str(""); + return output_log; +} + +bool FullscreenControllerStateTest::ShouldSkipStateAndEventPair(State state, + Event event) { + // TODO(scheib) Toggling Tab fullscreen while pending Tab or + // Browser fullscreen is broken currently http://crbug.com/154196 + if ((state == STATE_TO_BROWSER_FULLSCREEN_NO_CHROME || + state == STATE_TO_TAB_FULLSCREEN) && + (event == TAB_FULLSCREEN_TRUE || event == TAB_FULLSCREEN_FALSE)) + return true; + if (state == STATE_TO_NORMAL && event == TAB_FULLSCREEN_TRUE) + return true; + + return false; +} + +bool FullscreenControllerStateTest::ShouldSkipTest(State state, + Event event, + bool reentrant) { +#if defined(OS_WIN) + // FullscreenController verifies that WindowFullscreenStateChanged is + // always reentrant on Windows. It will fail if we mock asynchronous calls. + if (!reentrant) { + debugging_log_ << "\nSkipping non-reentrant test on Windows.\n"; + return true; + } +#else + if (reentrant) { + debugging_log_ << "\nSkipping reentrant test on non-Windows.\n"; + return true; + } +#endif + + // When testing reentrancy there are states the fullscreen controller + // will be unable to remain in, as they will progress due to the + // reentrant window change call. Skip states that will be instantly + // exited by the reentrant call. + if (reentrant && (transition_table_[state][WINDOW_CHANGE] != state)) { + debugging_log_ << "\nSkipping reentrant test for transitory source state " + << GetStateString(state) << ".\n"; + return true; + } + + if (ShouldSkipStateAndEventPair(state, event)) { + debugging_log_ << "\nSkipping test due to ShouldSkipStateAndEventPair(" + << GetStateString(state) << ", " + << GetEventString(event) << ").\n"; + LOG(INFO) << "Skipping test due to ShouldSkipStateAndEventPair(" + << GetStateString(state) << ", " + << GetEventString(event) << ")."; + return true; + } + + return false; +} + +void FullscreenControllerStateTest::TestStateAndEvent(State state, + Event event, + bool reentrant) { + if (ShouldSkipTest(state, event, reentrant)) + return; + + debugging_log_ << "\nTest transition from state " + << GetStateString(state) + << (reentrant ? " with reentrant calls.\n" : ".\n"); + reentrant_ = reentrant; + + debugging_log_ << " First, from " + << GetStateString(state_) << "\n"; + ASSERT_NO_FATAL_FAILURE(TransitionToState(state)) + << GetAndClearDebugLog(); + + debugging_log_ << " Then,\n"; + ASSERT_TRUE(InvokeEvent(event)) << GetAndClearDebugLog(); +} + +FullscreenController* FullscreenControllerStateTest::GetFullscreenController() { + return GetBrowser()->fullscreen_controller(); +} + diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller_state_test.h b/chrome/browser/ui/fullscreen/fullscreen_controller_state_test.h new file mode 100644 index 0000000..14dc0de --- /dev/null +++ b/chrome/browser/ui/fullscreen/fullscreen_controller_state_test.h @@ -0,0 +1,143 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_STATE_TEST_H_ +#define CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_STATE_TEST_H_ + +#include <sstream> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "build/build_config.h" + +class Browser; +class FullscreenController; + +// Test fixture testing Fullscreen Controller through its states. -------------- +class FullscreenControllerStateTest { + public: + enum State { + // The window is not in fullscreen. + STATE_NORMAL, + // User-initiated fullscreen. On Mac, this is Lion-mode for 10.7+. On 10.6, + // this is synonymous with STATE_BROWSER_FULLSCREEN_WITH_CHROME. + STATE_BROWSER_FULLSCREEN_NO_CHROME, +#if defined(OS_WIN) + // Windows 8 Metro Snap mode, which puts the window at 20% screen-width. + // No TO_ state for Metro, as the windows implementation is only reentrant. + STATE_METRO_SNAP, +#endif + // HTML5 tab-initiated fullscreen. + STATE_TAB_FULLSCREEN, + // Both tab and browser fullscreen. + STATE_TAB_BROWSER_FULLSCREEN, + // TO_ states are asynchronous states waiting for window state change + // before transitioning to their named state. + STATE_TO_NORMAL, + STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, + STATE_TO_TAB_FULLSCREEN, + NUM_STATES, + STATE_INVALID, + }; + + enum Event { + // FullscreenController::ToggleFullscreenMode() + TOGGLE_FULLSCREEN, + // FullscreenController::ToggleFullscreenModeForTab(, true) + TAB_FULLSCREEN_TRUE, + // FullscreenController::ToggleFullscreenModeForTab(, false) + TAB_FULLSCREEN_FALSE, +#if defined(OS_WIN) + // FullscreenController::SetMetroSnapMode(true) + METRO_SNAP_TRUE, + // FullscreenController::SetMetroSnapMode(flase) + METRO_SNAP_FALSE, +#endif + // FullscreenController::ChangeWindowFullscreenState() + WINDOW_CHANGE, + NUM_EVENTS, + EVENT_INVALID, + }; + + static const int MAX_STATE_NAME_LENGTH = 37; + static const int MAX_EVENT_NAME_LENGTH = 20; + + FullscreenControllerStateTest(); + virtual ~FullscreenControllerStateTest(); + + static const char* GetStateString(State state); + static const char* GetEventString(Event event); + + // Causes Fullscreen Controller to transition to an arbitrary state. + void TransitionToState(State state); + // Makes one state change to approach |destination_state| via shortest path. + // Returns true if a state change is made. + // Repeated calls are needed to reach the destination. + bool TransitionAStepTowardState(State destination_state); + + virtual void ChangeWindowFullscreenState() {} + virtual const char* GetWindowStateString(); + + // Causes the |event| to occur and return true on success. + virtual bool InvokeEvent(Event event); + + // Checks that window state matches the expected controller state. + virtual void VerifyWindowState(); + + // Tests all states with all permutations of multiple events to detect + // lingering state issues that would bleed over to other states. + // I.E. for each state test all combinations of events E1, E2, E3. + // + // This produces coverage for event sequences that may happen normally but + // would not be exposed by traversing to each state via TransitionToState(). + // TransitionToState() always takes the same path even when multiple paths + // exist. + void TestTransitionsForEachState(); + + protected: + // Generated information about the transitions between states. + struct StateTransitionInfo { + StateTransitionInfo() + : event(EVENT_INVALID), + state(STATE_INVALID), + distance(NUM_STATES) {} + Event event; // The |Event| that will cause the state transition. + State state; // The adjacent |State| transitioned to; not the final state. + int distance; // Steps to final state. NUM_STATES represents unknown. + }; + + // Returns next transition info for shortest path from source to destination. + StateTransitionInfo NextTransitionInShortestPath(State source, + State destination, + int search_limit); + + std::string GetAndClearDebugLog(); + + // Avoids currently broken cases in the fullscreen controller. + virtual bool ShouldSkipStateAndEventPair(State state, Event event); + // Skips reentrant situations and calls ShouldSkipStateAndEventPair. + virtual bool ShouldSkipTest(State state, Event event, bool reentrant); + + // Runs one test of transitioning to a state and invoking an event. + virtual void TestStateAndEvent(State state, Event event, bool reentrant); + + virtual Browser* GetBrowser() = 0; + FullscreenController* GetFullscreenController(); + + State state_; + bool reentrant_; + + // Human defined |State| that results given each [state][event] pair. + State transition_table_[NUM_STATES][NUM_EVENTS]; + + // Generated information about the transitions between states [from][to]. + StateTransitionInfo state_transitions_[NUM_STATES][NUM_STATES]; + + // Log of operations reported on errors via GetAndClearDebugLog(). + std::ostringstream debugging_log_; + + DISALLOW_COPY_AND_ASSIGN(FullscreenControllerStateTest); +}; + +#endif // CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_STATE_TEST_H_ diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller_state_unittest.cc b/chrome/browser/ui/fullscreen/fullscreen_controller_state_unittest.cc new file mode 100644 index 0000000..160f3b3 --- /dev/null +++ b/chrome/browser/ui/fullscreen/fullscreen_controller_state_unittest.cc @@ -0,0 +1,457 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "build/build_config.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_tabstrip.h" +#include "chrome/browser/ui/fullscreen/fullscreen_controller.h" +#include "chrome/browser/ui/fullscreen/fullscreen_controller_state_test.h" +#include "chrome/test/base/browser_with_test_window_test.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/url_constants.h" +#include "testing/gtest/include/gtest/gtest.h" + +// The FullscreenControllerStateUnitTest unit test suite exhastively tests +// the FullscreenController through all permutations of events. The behavior +// of the BrowserWindow is mocked via FullscreenControllerTestWindow. +// +// FullscreenControllerStateInteractiveTest is an interactive test suite +// used to verify that the FullscreenControllerTestWindow models the behavior +// of actual windows accurately. The interactive tests are too flaky to run +// on infrastructure, and so those tests are disabled. Run them with: +// interactive_ui_tests +// --gtest_filter="FullscreenControllerStateInteractiveTest.*" +// --gtest_also_run_disabled_tests + +// A BrowserWindow used for testing FullscreenController. ---------------------- +class FullscreenControllerTestWindow : public TestBrowserWindow { + public: + // Simulate the window state with an enumeration. + enum WindowState { + NORMAL, + FULLSCREEN, + // No TO_ state for METRO_SNAP, the windows implementation is synchronous. + METRO_SNAP, + TO_NORMAL, + TO_FULLSCREEN, + }; + + FullscreenControllerTestWindow(); + virtual ~FullscreenControllerTestWindow() {} + + // BrowserWindow Interface: + virtual void EnterFullscreen(const GURL& url, + FullscreenExitBubbleType type) OVERRIDE; + virtual void EnterFullscreen(); + virtual void ExitFullscreen() OVERRIDE; + virtual bool IsFullscreen() const OVERRIDE; +#if defined(OS_WIN) + virtual void SetMetroSnapMode(bool enable) OVERRIDE; + virtual bool IsInMetroSnapMode() const OVERRIDE; +#endif +#if defined(OS_MACOSX) + virtual void EnterPresentationMode( + const GURL& url, + FullscreenExitBubbleType bubble_type) OVERRIDE; + virtual void ExitPresentationMode() OVERRIDE; + virtual bool InPresentationMode() OVERRIDE; +#endif + + static const char* GetWindowStateString(WindowState state); + WindowState state() const { return state_; } + void set_browser(Browser* browser) { browser_ = browser; } + void set_reentrant(bool value) { reentrant_ = value; } + bool reentrant() const { return reentrant_; } + + // Simulates the window changing state. + void ChangeWindowFullscreenState(); + // Calls ChangeWindowFullscreenState() if |reentrant_| is true. + void ChangeWindowFullscreenStateIfReentrant(); + + private: + WindowState state_; + bool mac_presentation_mode_; + Browser* browser_; + + // Causes reentrant calls to be made by calling + // browser_->WindowFullscreenStateChanged() from the BrowserWindow + // interface methods. + bool reentrant_; +}; + +FullscreenControllerTestWindow::FullscreenControllerTestWindow() + : state_(NORMAL), + mac_presentation_mode_(false), + browser_(NULL), + reentrant_(false) { +} + +void FullscreenControllerTestWindow::EnterFullscreen( + const GURL& url, FullscreenExitBubbleType type) { + EnterFullscreen(); +} + +void FullscreenControllerTestWindow::EnterFullscreen() { + if (!IsFullscreen()) { + state_ = TO_FULLSCREEN; + ChangeWindowFullscreenStateIfReentrant(); + } +} + +void FullscreenControllerTestWindow::ExitFullscreen() { + if (IsFullscreen()) { + state_ = TO_NORMAL; + mac_presentation_mode_ = false; + ChangeWindowFullscreenStateIfReentrant(); + } +} + +bool FullscreenControllerTestWindow::IsFullscreen() const { +#if defined(OS_MACOSX) + return state_ == FULLSCREEN || state_ == TO_FULLSCREEN; +#else + return state_ == FULLSCREEN || state_ == TO_NORMAL; +#endif +} + +#if defined(OS_WIN) +void FullscreenControllerTestWindow::SetMetroSnapMode(bool enable) { + if (enable != IsInMetroSnapMode()) { + if (enable) + state_ = METRO_SNAP; + else + state_ = NORMAL; + } + ChangeWindowFullscreenStateIfReentrant(); +} + +bool FullscreenControllerTestWindow::IsInMetroSnapMode() const { + return state_ == METRO_SNAP; +} +#endif + +#if defined(OS_MACOSX) +void FullscreenControllerTestWindow::EnterPresentationMode( + const GURL& url, + FullscreenExitBubbleType bubble_type) { + mac_presentation_mode_ = true; + EnterFullscreen(); +} + +void FullscreenControllerTestWindow::ExitPresentationMode() { + if (InPresentationMode()) { + mac_presentation_mode_ = false; + ExitFullscreen(); + } +} + +bool FullscreenControllerTestWindow::InPresentationMode() { + return mac_presentation_mode_; +} +#endif + +// static +const char* FullscreenControllerTestWindow::GetWindowStateString( + WindowState state) { + switch (state) { + case NORMAL: + return "NORMAL"; + case FULLSCREEN: + return "FULLSCREEN"; + case METRO_SNAP: + return "METRO_SNAP"; + case TO_FULLSCREEN: + return "TO_FULLSCREEN"; + case TO_NORMAL: + return "TO_NORMAL"; + default: + NOTREACHED() << "No string for state " << state; + return "WindowState-Unknown"; + } +} + +void FullscreenControllerTestWindow::ChangeWindowFullscreenState() { + // Several states result in "no operation" intentionally. The tests + // assume that all possible states and event pairs can be tested, even + // though window managers will not generate all of these. + switch (state_) { + case NORMAL: + break; + case FULLSCREEN: + break; + case METRO_SNAP: + break; + case TO_FULLSCREEN: + state_ = FULLSCREEN; + break; + case TO_NORMAL: + state_ = NORMAL; + break; + default: + NOTREACHED(); + } + // Emit a change event from every state to ensure the Fullscreen Controller + // handles it in all circumstances. + browser_->WindowFullscreenStateChanged(); +} + +void FullscreenControllerTestWindow::ChangeWindowFullscreenStateIfReentrant() { + if (reentrant_) + ChangeWindowFullscreenState(); +} + +// Unit test fixture testing Fullscreen Controller through its states. --------- +class FullscreenControllerStateUnitTest : public BrowserWithTestWindowTest, + public FullscreenControllerStateTest { + public: + FullscreenControllerStateUnitTest(); + + // FullscreenControllerStateTest: + virtual void SetUp() OVERRIDE; + virtual void ChangeWindowFullscreenState() OVERRIDE; + virtual const char* GetWindowStateString() OVERRIDE; + virtual void VerifyWindowState() OVERRIDE; + + protected: + // FullscreenControllerStateTest: + virtual bool ShouldSkipStateAndEventPair(State state, Event event) OVERRIDE; + virtual void TestStateAndEvent(State state, + Event event, + bool reentrant) OVERRIDE; + virtual Browser* GetBrowser() OVERRIDE; + FullscreenControllerTestWindow* window_; +}; + +FullscreenControllerStateUnitTest::FullscreenControllerStateUnitTest () + : window_(NULL) { +} + +void FullscreenControllerStateUnitTest::SetUp() { + window_ = new FullscreenControllerTestWindow(); + set_window(window_); // BrowserWithTestWindowTest takes ownership. + BrowserWithTestWindowTest::SetUp(); + window_->set_browser(browser()); +} + +void FullscreenControllerStateUnitTest::ChangeWindowFullscreenState() { + window_->ChangeWindowFullscreenState(); +} + +const char* FullscreenControllerStateUnitTest::GetWindowStateString() { + return FullscreenControllerTestWindow::GetWindowStateString(window_->state()); +} + +void FullscreenControllerStateUnitTest::VerifyWindowState() { + switch (state_) { + case STATE_NORMAL: + EXPECT_EQ(FullscreenControllerTestWindow::NORMAL, + window_->state()) << GetAndClearDebugLog(); + break; + case STATE_BROWSER_FULLSCREEN_NO_CHROME: + EXPECT_EQ(FullscreenControllerTestWindow::FULLSCREEN, + window_->state()) << GetAndClearDebugLog(); + break; +#if defined(OS_WIN) + case STATE_METRO_SNAP: + EXPECT_EQ(FullscreenControllerTestWindow::METRO_SNAP, + window_->state()) << GetAndClearDebugLog(); + break; +#endif + case STATE_TAB_FULLSCREEN: + EXPECT_EQ(FullscreenControllerTestWindow::FULLSCREEN, + window_->state()) << GetAndClearDebugLog(); + break; + case STATE_TAB_BROWSER_FULLSCREEN: + EXPECT_EQ(FullscreenControllerTestWindow::FULLSCREEN, + window_->state()) << GetAndClearDebugLog(); + break; + case STATE_TO_NORMAL: + EXPECT_EQ(FullscreenControllerTestWindow::TO_NORMAL, + window_->state()) << GetAndClearDebugLog(); + break; + case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME: + EXPECT_EQ(FullscreenControllerTestWindow::TO_FULLSCREEN, + window_->state()) << GetAndClearDebugLog(); + break; + case STATE_TO_TAB_FULLSCREEN: + EXPECT_EQ(FullscreenControllerTestWindow::TO_FULLSCREEN, + window_->state()) << GetAndClearDebugLog(); + break; + default: + NOTREACHED() << GetAndClearDebugLog(); + } + + FullscreenControllerStateTest::VerifyWindowState(); +} + +bool FullscreenControllerStateUnitTest::ShouldSkipStateAndEventPair( + State state, Event event) { +#if defined(OS_MACOSX) + // TODO(scheib) Toggle, Window Event, Toggle, Toggle on Mac as exposed by + // test *.STATE_TO_NORMAL__TOGGLE_FULLSCREEN runs interactively and exits to + // Normal. This doesn't appear to be the desired result, and would add + // too much complexity to mimic in our simple FullscreenControllerTestWindow. + // http://crbug.com/156968 + if ((state == STATE_TO_NORMAL || + state == STATE_TO_BROWSER_FULLSCREEN_NO_CHROME || + state == STATE_TO_TAB_FULLSCREEN) && + event == TOGGLE_FULLSCREEN) + return true; +#endif + + return FullscreenControllerStateTest::ShouldSkipStateAndEventPair(state, + event); +} + +void FullscreenControllerStateUnitTest::TestStateAndEvent(State state, + Event event, + bool reentrant) { + window_->set_reentrant(reentrant); + FullscreenControllerStateTest::TestStateAndEvent(state, event, reentrant); +} + +Browser* FullscreenControllerStateUnitTest::GetBrowser() { + return BrowserWithTestWindowTest::browser(); +} + +// Tests ----------------------------------------------------------------------- + +#define TEST_EVENT_INNER(state, event, reentrant, reentrant_id) \ + TEST_F(FullscreenControllerStateUnitTest, \ + state##__##event##reentrant_id) { \ + AddTab(browser(), GURL(chrome::kAboutBlankURL)); \ + ASSERT_NO_FATAL_FAILURE(TestStateAndEvent(state, event, reentrant)) \ + << GetAndClearDebugLog(); \ + } + // Progress of tests can be examined by inserting the following line: + // LOG(INFO) << GetAndClearDebugLog(); } + +#define TEST_EVENT(state, event) \ + TEST_EVENT_INNER(state, event, false, ); \ + TEST_EVENT_INNER(state, event, true, _Reentrant); + +// Individual tests for each pair of state and event: + +TEST_EVENT(STATE_NORMAL, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_NORMAL, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_NORMAL, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_NORMAL, METRO_SNAP_TRUE); +TEST_EVENT(STATE_NORMAL, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_NORMAL, WINDOW_CHANGE); + +TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, METRO_SNAP_TRUE); +TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, WINDOW_CHANGE); + +#if defined(OS_WIN) +TEST_EVENT(STATE_METRO_SNAP, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_METRO_SNAP, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_METRO_SNAP, TAB_FULLSCREEN_FALSE); +TEST_EVENT(STATE_METRO_SNAP, METRO_SNAP_TRUE); +TEST_EVENT(STATE_METRO_SNAP, METRO_SNAP_FALSE); +TEST_EVENT(STATE_METRO_SNAP, WINDOW_CHANGE); +#endif + +TEST_EVENT(STATE_TAB_FULLSCREEN, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_TAB_FULLSCREEN, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_TAB_FULLSCREEN, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_TAB_FULLSCREEN, METRO_SNAP_TRUE); +TEST_EVENT(STATE_TAB_FULLSCREEN, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_TAB_FULLSCREEN, WINDOW_CHANGE); + +TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, METRO_SNAP_TRUE); +TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, WINDOW_CHANGE); + +TEST_EVENT(STATE_TO_NORMAL, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_TO_NORMAL, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_TO_NORMAL, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_TO_NORMAL, METRO_SNAP_TRUE); +TEST_EVENT(STATE_TO_NORMAL, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_TO_NORMAL, WINDOW_CHANGE); + +TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, METRO_SNAP_TRUE); +TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, WINDOW_CHANGE); + +TEST_EVENT(STATE_TO_TAB_FULLSCREEN, TOGGLE_FULLSCREEN); +TEST_EVENT(STATE_TO_TAB_FULLSCREEN, TAB_FULLSCREEN_TRUE); +TEST_EVENT(STATE_TO_TAB_FULLSCREEN, TAB_FULLSCREEN_FALSE); +#if defined(OS_WIN) +TEST_EVENT(STATE_TO_TAB_FULLSCREEN, METRO_SNAP_TRUE); +TEST_EVENT(STATE_TO_TAB_FULLSCREEN, METRO_SNAP_FALSE); +#endif +TEST_EVENT(STATE_TO_TAB_FULLSCREEN, WINDOW_CHANGE); + +// Specific one-off tests for known issues: + +// TODO(scheib) Toggling Tab fullscreen while pending Tab or +// Browser fullscreen is broken currently http://crbug.com/154196 +TEST_F(FullscreenControllerStateUnitTest, + DISABLED_ToggleTabWhenPendingBrowser) { +#if !defined(OS_WIN) // Only possible without reentrancy + AddTab(browser(), GURL(chrome::kAboutBlankURL)); + ASSERT_NO_FATAL_FAILURE( + TransitionToState(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME)) + << GetAndClearDebugLog(); + + ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE)) << GetAndClearDebugLog(); + ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE)) << GetAndClearDebugLog(); + ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE)) << GetAndClearDebugLog(); +#endif +} + +// TODO(scheib) Toggling Tab fullscreen while pending Tab or +// Browser fullscreen is broken currently http://crbug.com/154196 +TEST_F(FullscreenControllerStateUnitTest, DISABLED_ToggleTabWhenPendingTab) { +#if !defined(OS_WIN) // Only possible without reentrancy + AddTab(browser(), GURL(chrome::kAboutBlankURL)); + ASSERT_NO_FATAL_FAILURE( + TransitionToState(STATE_TO_TAB_FULLSCREEN)) + << GetAndClearDebugLog(); + + ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE)) << GetAndClearDebugLog(); + ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE)) << GetAndClearDebugLog(); + ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE)) << GetAndClearDebugLog(); +#endif +} + +// Soak tests: + +// Tests all states with all permutations of multiple events to detect lingering +// state issues that would bleed over to other states. +// I.E. for each state test all combinations of events E1, E2, E3. +// +// This produces coverage for event sequences that may happen normally but +// would not be exposed by traversing to each state via TransitionToState(). +// TransitionToState() always takes the same path even when multiple paths +// exist. +TEST_F(FullscreenControllerStateUnitTest, TransitionsForEachState) { + // A tab is needed for tab fullscreen. + AddTab(browser(), GURL(chrome::kAboutBlankURL)); + TestTransitionsForEachState(); + // Progress of test can be examined via LOG(INFO) << GetAndClearDebugLog(); +} + diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller_test.cc b/chrome/browser/ui/fullscreen/fullscreen_controller_test.cc index da86e2a..7be9a0b 100644 --- a/chrome/browser/ui/fullscreen/fullscreen_controller_test.cc +++ b/chrome/browser/ui/fullscreen/fullscreen_controller_test.cc @@ -90,16 +90,6 @@ void FullscreenControllerTest::DenyCurrentFullscreenOrMouseLockRequest() { browser()->fullscreen_controller()->OnDenyFullscreenPermission(type); } -void FullscreenControllerTest::AddTabAtIndexAndWait(int index, const GURL& url, - content::PageTransition transition) { - content::TestNavigationObserver observer( - content::NotificationService::AllSources(), NULL, 1); - - AddTabAtIndex(index, url, transition); - - observer.Wait(); -} - void FullscreenControllerTest::GoBack() { content::TestNavigationObserver observer( content::NotificationService::AllSources(), NULL, 1); diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller_test.h b/chrome/browser/ui/fullscreen/fullscreen_controller_test.h index eee66d9..cdc4730 100644 --- a/chrome/browser/ui/fullscreen/fullscreen_controller_test.h +++ b/chrome/browser/ui/fullscreen/fullscreen_controller_test.h @@ -51,8 +51,6 @@ class FullscreenControllerTest : public InProcessBrowserTest { bool IsFullscreenBubbleDisplayingButtons(); void AcceptCurrentFullscreenOrMouseLockRequest(); void DenyCurrentFullscreenOrMouseLockRequest(); - void AddTabAtIndexAndWait(int index, const GURL& url, - content::PageTransition transition); void GoBack(); void Reload(); static const char kFullscreenMouseLockHTML[]; diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller_unittest.cc b/chrome/browser/ui/fullscreen/fullscreen_controller_unittest.cc deleted file mode 100644 index b296122..0000000 --- a/chrome/browser/ui/fullscreen/fullscreen_controller_unittest.cc +++ /dev/null @@ -1,969 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <memory.h> - -#include <iomanip> -#include <iostream> -#include <sstream> - -#include "build/build_config.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_tabstrip.h" -#include "chrome/browser/ui/fullscreen/fullscreen_controller.h" -#include "chrome/test/base/browser_with_test_window_test.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/url_constants.h" -#include "testing/gtest/include/gtest/gtest.h" - -// A BrowserWindow used for testing FullscreenController. ---------------------- -class FullscreenControllerTestWindow : public TestBrowserWindow { - public: - // Simulate the window state with an enumeration. - enum WindowState { - NORMAL, - FULLSCREEN, - // No TO_ state for METRO_SNAP, the windows implementation is synchronous. - METRO_SNAP, - TO_NORMAL, - TO_FULLSCREEN, - }; - - FullscreenControllerTestWindow(); - virtual ~FullscreenControllerTestWindow() {} - - // BrowserWindow Interface: - virtual void EnterFullscreen(const GURL& url, - FullscreenExitBubbleType type) OVERRIDE; - virtual void EnterFullscreen(); - virtual void ExitFullscreen() OVERRIDE; - virtual bool IsFullscreen() const OVERRIDE; -#if defined(OS_WIN) - virtual void SetMetroSnapMode(bool enable) OVERRIDE; - virtual bool IsInMetroSnapMode() const OVERRIDE; -#endif -#if defined(OS_MACOSX) - virtual void EnterPresentationMode( - const GURL& url, - FullscreenExitBubbleType bubble_type) OVERRIDE; - virtual void ExitPresentationMode() OVERRIDE; - virtual bool InPresentationMode() OVERRIDE; -#endif - - static const char* GetWindowStateString(WindowState state); - WindowState state() const { return state_; } - void set_browser(Browser* browser) { browser_ = browser; } - void set_reentrant(bool value) { reentrant_ = value; } - bool reentrant() const { return reentrant_; } - - // Simulates the window changing state. - void ChangeWindowFullscreenState(); - // Calls ChangeWindowFullscreenState() if |reentrant_| is true. - void ChangeWindowFullscreenStateIfReentrant(); - - private: - WindowState state_; - bool mac_presentation_mode_; - Browser* browser_; - - // Causes reentrant calls to be made by calling - // browser_->WindowFullscreenStateChanged() from the BrowserWindow - // interface methods. - bool reentrant_; -}; - -FullscreenControllerTestWindow::FullscreenControllerTestWindow() - : state_(NORMAL), - mac_presentation_mode_(false), - browser_(NULL), - reentrant_(false) { -} - -void FullscreenControllerTestWindow::EnterFullscreen( - const GURL& url, FullscreenExitBubbleType type) { - EnterFullscreen(); -} - -void FullscreenControllerTestWindow::EnterFullscreen() { - if (!IsFullscreen()) { - state_ = TO_FULLSCREEN; - ChangeWindowFullscreenStateIfReentrant(); - } -} - -void FullscreenControllerTestWindow::ExitFullscreen() { - if (IsFullscreen()) { - state_ = TO_NORMAL; - mac_presentation_mode_ = false; - ChangeWindowFullscreenStateIfReentrant(); - } -} - -bool FullscreenControllerTestWindow::IsFullscreen() const { - return state_ == FULLSCREEN || state_ == TO_NORMAL; -} - -#if defined(OS_WIN) -void FullscreenControllerTestWindow::SetMetroSnapMode(bool enable) { - if (enable != IsInMetroSnapMode()) { - if (enable) - state_ = METRO_SNAP; - else - state_ = NORMAL; - } - ChangeWindowFullscreenStateIfReentrant(); -} - -bool FullscreenControllerTestWindow::IsInMetroSnapMode() const { - return state_ == METRO_SNAP; -} -#endif - -#if defined(OS_MACOSX) -void FullscreenControllerTestWindow::EnterPresentationMode( - const GURL& url, - FullscreenExitBubbleType bubble_type) { - mac_presentation_mode_ = true; - EnterFullscreen(); -} - -void FullscreenControllerTestWindow::ExitPresentationMode() { - if (InPresentationMode()) { - mac_presentation_mode_ = false; - ExitFullscreen(); - } -} - -bool FullscreenControllerTestWindow::InPresentationMode() { - return mac_presentation_mode_; -} -#endif - -// static -const char* FullscreenControllerTestWindow::GetWindowStateString( - WindowState state) { - switch (state) { - case NORMAL: - return "NORMAL"; - case FULLSCREEN: - return "FULLSCREEN"; - case METRO_SNAP: - return "METRO_SNAP"; - case TO_FULLSCREEN: - return "TO_FULLSCREEN"; - case TO_NORMAL: - return "TO_NORMAL"; - default: - NOTREACHED() << "No string for state " << state; - return "WindowState-Unknown"; - } -} - -void FullscreenControllerTestWindow::ChangeWindowFullscreenState() { - // Several states result in "no operation" intentionally. The tests - // assume that all possible states and event pairs can be tested, even - // though window managers will not generate all of these. - switch (state_) { - case NORMAL: - break; - case FULLSCREEN: - break; - case METRO_SNAP: - break; - case TO_FULLSCREEN: - state_ = FULLSCREEN; - break; - case TO_NORMAL: - state_ = NORMAL; - break; - default: - NOTREACHED(); - } - // Emit a change event from every state to ensure the Fullscreen Controller - // handles it in all circumstances. - browser_->WindowFullscreenStateChanged(); -} - -void FullscreenControllerTestWindow::ChangeWindowFullscreenStateIfReentrant() { - if (reentrant_) - ChangeWindowFullscreenState(); -} - -// Unit test fixture for testing Fullscreen Controller. ------------------------ -class FullscreenControllerUnitTest : public BrowserWithTestWindowTest { - public: - enum State { - // The window is not in fullscreen. - STATE_NORMAL, - // User-initiated fullscreen. On Mac, this is Lion-mode for 10.7+. On 10.6, - // this is synonymous with STATE_BROWSER_FULLSCREEN_WITH_CHROME. - STATE_BROWSER_FULLSCREEN_NO_CHROME, -#if defined(OS_WIN) - // Windows 8 Metro Snap mode, which puts the window at 20% screen-width. - // No TO_ state for Metro, as the windows implementation is only reentrant. - STATE_METRO_SNAP, -#endif - // HTML5 tab-initiated fullscreen. - STATE_TAB_FULLSCREEN, - // Both tab and browser fullscreen. - STATE_TAB_BROWSER_FULLSCREEN, - // TO_ states are asynchronous states waiting for window state change - // before transitioning to their named state. - STATE_TO_NORMAL, - STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, - STATE_TO_TAB_FULLSCREEN, - NUM_STATES, - STATE_INVALID, - }; - - enum Event { - // FullscreenController::ToggleFullscreenMode() - TOGGLE_FULLSCREEN, - // FullscreenController::ToggleFullscreenModeForTab(, true) - TAB_FULLSCREEN_TRUE, - // FullscreenController::ToggleFullscreenModeForTab(, false) - TAB_FULLSCREEN_FALSE, -#if defined(OS_WIN) - // FullscreenController::SetMetroSnapMode(true) - METRO_SNAP_TRUE, - // FullscreenController::SetMetroSnapMode(flase) - METRO_SNAP_FALSE, -#endif - // FullscreenController::ChangeWindowFullscreenState() - WINDOW_CHANGE, - NUM_EVENTS, - EVENT_INVALID, - }; - - static const int MAX_STATE_NAME_LENGTH = 37; - static const int MAX_EVENT_NAME_LENGTH = 20; - - virtual void SetUp() OVERRIDE; - - static const char* GetStateString(State state); - static const char* GetEventString(Event event); - - // Causes Fullscreen Controller to transition to an arbitrary state. - void TransitionToState(State state); - // Makes one state change to approach |destination_state| via shortest path. - // Returns true if a state change is made. - // Repeated calls are needed to reach the destination. - bool TransitionAStepTowardState(State destination_state); - - // Causes the |event| to occur and return true on success. - bool InvokeEvent(Event event); - - // Checks that window state matches the expected controller state. - void VerifyWindowState(); - - protected: - // Generated information about the transitions between states. - struct StateTransitionInfo { - StateTransitionInfo() - : event(EVENT_INVALID), - state(STATE_INVALID), - distance(NUM_STATES) {} - Event event; // The |Event| that will cause the state transition. - State state; // The adjacent |State| transitioned to; not the final state. - int distance; // Steps to final state. NUM_STATES represents unknown. - }; - - // Returns next transition info for shortest path from source to destination. - StateTransitionInfo NextTransitionInShortestPath(State source, - State destination, - int search_limit); - - std::string GetAndClearDebugLog(); - - // Avoids currently broken cases in the fullscreen controller. - bool ShouldSkipStateAndEventPair(State state, Event event); - // Skips reentrant situations and calls ShouldSkipStateAndEventPair. - bool ShouldSkipTest(State state, Event event, bool reentrant); - - // Runs one test of transitioning to a state and invoking an event. - void TestStateAndEvent(State state, Event event, bool reentrant); - - FullscreenControllerTestWindow* window_; - FullscreenController* fullscreen_controller_; - State state_; - - // Human defined |State| that results given each [state][event] pair. - State transition_table_[NUM_STATES][NUM_EVENTS]; - - // Generated information about the transitions between states [from][to]. - StateTransitionInfo state_transitions_[NUM_STATES][NUM_STATES]; - - // Log of operations reported on errors via GetAndClearDebugLog(). - std::ostringstream debugging_log_; -}; - -void FullscreenControllerUnitTest::SetUp() { - window_ = new FullscreenControllerTestWindow(); - set_window(window_); // BrowserWithTestWindowTest takes ownership. - BrowserWithTestWindowTest::SetUp(); - window_->set_browser(browser()); - fullscreen_controller_ = browser()->fullscreen_controller(); - state_ = STATE_NORMAL; - - // Human specified state machine data. - // For each state, for each event, define the resulting state. - State transition_table_data[][NUM_EVENTS] = { - { // STATE_NORMAL: - STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN - STATE_TO_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE - STATE_NORMAL, // Event TAB_FULLSCREEN_FALSE -#if defined(OS_WIN) - STATE_METRO_SNAP, // Event METRO_SNAP_TRUE - STATE_NORMAL, // Event METRO_SNAP_FALSE -#endif - STATE_NORMAL, // Event WINDOW_CHANGE - }, - { // STATE_BROWSER_FULLSCREEN_NO_CHROME: - STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN - STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE - STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE -#if defined(OS_WIN) - STATE_METRO_SNAP, // Event METRO_SNAP_TRUE - STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event METRO_SNAP_FALSE -#endif - STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event WINDOW_CHANGE - }, -#if defined(OS_WIN) - { // STATE_METRO_SNAP: - STATE_METRO_SNAP, // Event TOGGLE_FULLSCREEN - STATE_METRO_SNAP, // Event TAB_FULLSCREEN_TRUE - STATE_METRO_SNAP, // Event TAB_FULLSCREEN_FALSE - STATE_METRO_SNAP, // Event METRO_SNAP_TRUE - STATE_NORMAL, // Event METRO_SNAP_FALSE - STATE_METRO_SNAP, // Event WINDOW_CHANGE - }, -#endif - { // STATE_TAB_FULLSCREEN: - STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN - STATE_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE - STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE -#if defined(OS_WIN) - STATE_METRO_SNAP, // Event METRO_SNAP_TRUE - STATE_TAB_FULLSCREEN, // Event METRO_SNAP_FALSE -#endif - STATE_TAB_FULLSCREEN, // Event WINDOW_CHANGE - }, - { // STATE_TAB_BROWSER_FULLSCREEN: - STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN - STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE -#if defined(OS_MACOSX) - // TODO(scheib) Mac exits browser mode too http://crbug.com/155642 - STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE -#else - STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE -#endif -#if defined(OS_WIN) - STATE_METRO_SNAP, // Event METRO_SNAP_TRUE - STATE_TAB_BROWSER_FULLSCREEN, // Event METRO_SNAP_FALSE -#endif - STATE_TAB_BROWSER_FULLSCREEN, // Event WINDOW_CHANGE - }, - // STATE_TO_NORMAL: - { STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN - // TODO(scheib) Should be a route back to TAB. http://crbug.com/154196 - STATE_TO_NORMAL, // Event TAB_FULLSCREEN_TRUE - STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE -#if defined(OS_WIN) - STATE_METRO_SNAP, // Event METRO_SNAP_TRUE - STATE_TO_NORMAL, // Event METRO_SNAP_FALSE -#endif - STATE_NORMAL, // Event WINDOW_CHANGE - }, - // STATE_TO_BROWSER_FULLSCREEN_NO_CHROME: - { STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN - // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196 - STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_TRUE - STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE -#if defined(OS_WIN) - STATE_METRO_SNAP, // Event METRO_SNAP_TRUE - STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event METRO_SNAP_FALSE -#endif - STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event WINDOW_CHANGE - }, - // STATE_TO_TAB_FULLSCREEN: - { // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196 - STATE_TO_TAB_FULLSCREEN, // Event TOGGLE_FULLSCREEN - STATE_TO_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE - // TODO(scheib) Should be a route back to NORMAL. http://crbug.com/154196 - STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE -#if defined(OS_WIN) - STATE_METRO_SNAP, // Event METRO_SNAP_TRUE - STATE_TO_TAB_FULLSCREEN, // Event METRO_SNAP_FALSE -#endif - STATE_TAB_FULLSCREEN, // Event WINDOW_CHANGE - }, - }; - ASSERT_EQ(sizeof(transition_table_data), sizeof(transition_table_)); - memcpy(transition_table_, transition_table_data, - sizeof(transition_table_data)); - - // Verify that transition_table_ has been completely defined. - for (int source = 0; source < NUM_STATES; source++) { - for (int event = 0; event < NUM_EVENTS; event++) { - ASSERT_NE(STATE_INVALID, transition_table_[source][event]); - ASSERT_LE(0, transition_table_[source][event]); - ASSERT_GT(NUM_STATES, transition_table_[source][event]); - } - } - - // Copy transition_table_ data into state_transitions_ table. - for (int source = 0; source < NUM_STATES; source++) { - for (int event = 0; event < NUM_EVENTS; event++) { - State destination = transition_table_[source][event]; - state_transitions_[source][destination].event = static_cast<Event>(event); - state_transitions_[source][destination].state = destination; - state_transitions_[source][destination].distance = 1; - } - } -} - -// static -const char* FullscreenControllerUnitTest::GetStateString(State state) { - switch (state) { - case STATE_NORMAL: - return "STATE_NORMAL"; - case STATE_BROWSER_FULLSCREEN_NO_CHROME: - return "STATE_BROWSER_FULLSCREEN_NO_CHROME"; -#if defined(OS_WIN) - case STATE_METRO_SNAP: - return "STATE_METRO_SNAP"; -#endif - case STATE_TAB_FULLSCREEN: - return "STATE_TAB_FULLSCREEN"; - case STATE_TAB_BROWSER_FULLSCREEN: - return "STATE_TAB_BROWSER_FULLSCREEN"; - case STATE_TO_NORMAL: - return "STATE_TO_NORMAL"; - case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME: - return "STATE_TO_BROWSER_FULLSCREEN_NO_CHROME"; - case STATE_TO_TAB_FULLSCREEN: - return "STATE_TO_TAB_FULLSCREEN"; - case STATE_INVALID: - return "STATE_INVALID"; - default: - NOTREACHED() << "No string for state " << state; - return "State-Unknown"; - } -} - -// static -const char* FullscreenControllerUnitTest::GetEventString(Event event) { - switch (event) { - case TOGGLE_FULLSCREEN: - return "TOGGLE_FULLSCREEN"; - case TAB_FULLSCREEN_TRUE: - return "TAB_FULLSCREEN_TRUE"; - case TAB_FULLSCREEN_FALSE: - return "TAB_FULLSCREEN_FALSE"; -#if defined(OS_WIN) - case METRO_SNAP_TRUE: - return "METRO_SNAP_TRUE"; - case METRO_SNAP_FALSE: - return "METRO_SNAP_FALSE"; -#endif - case WINDOW_CHANGE: - return "WINDOW_CHANGE"; - case EVENT_INVALID: - return "EVENT_INVALID"; - default: - NOTREACHED() << "No string for event " << event; - return "Event-Unknown"; - } -} - -void FullscreenControllerUnitTest::TransitionToState(State final_state) { - int max_steps = NUM_STATES; - while (max_steps-- && TransitionAStepTowardState(final_state)) - continue; - ASSERT_GE(max_steps, 0) << "TransitionToState was unable to achieve desired " - << "target state. TransitionAStepTowardState iterated too many times." - << GetAndClearDebugLog(); - ASSERT_EQ(final_state, state_) << "TransitionToState was unable to achieve " - << "desired target state. TransitionAStepTowardState returned false." - << GetAndClearDebugLog(); -} - -bool FullscreenControllerUnitTest::TransitionAStepTowardState( - State destination_state) { - State source_state = state_; - if (source_state == destination_state) - return false; - - StateTransitionInfo next = NextTransitionInShortestPath(source_state, - destination_state, - NUM_STATES); - if (next.state == STATE_INVALID) { - NOTREACHED() << "TransitionAStepTowardState unable to transition. " - << "NextTransitionInShortestPath(" - << GetStateString(source_state) << ", " - << GetStateString(destination_state) << ") returned STATE_INVALID." - << GetAndClearDebugLog(); - return false; - } - - return InvokeEvent(next.event); -} - -bool FullscreenControllerUnitTest::InvokeEvent(Event event) { - State source_state = state_; - State next_state = transition_table_[source_state][event]; - - // When simulating reentrant window change calls, expect the next state - // automatically. - if (window_->reentrant()) - next_state = transition_table_[next_state][WINDOW_CHANGE]; - - debugging_log_ << " InvokeEvent(" << std::left - << std::setw(MAX_EVENT_NAME_LENGTH) << GetEventString(event) - << ") to " - << std::setw(MAX_STATE_NAME_LENGTH) << GetStateString(next_state) - << " "; - - state_ = next_state; - - switch (event) { - case TOGGLE_FULLSCREEN: - fullscreen_controller_->ToggleFullscreenMode(); - break; - case TAB_FULLSCREEN_TRUE: - fullscreen_controller_->ToggleFullscreenModeForTab( - chrome::GetActiveWebContents(browser()), true); - break; - case TAB_FULLSCREEN_FALSE: - fullscreen_controller_->ToggleFullscreenModeForTab( - chrome::GetActiveWebContents(browser()), false); - break; -#if defined(OS_WIN) - case METRO_SNAP_TRUE: - fullscreen_controller_->SetMetroSnapMode(true); - break; - case METRO_SNAP_FALSE: - fullscreen_controller_->SetMetroSnapMode(false); - break; -#endif - case WINDOW_CHANGE: - window_->ChangeWindowFullscreenState(); - break; - default: - NOTREACHED() << "InvokeEvent needs a handler for event " - << GetEventString(event) << GetAndClearDebugLog(); - return false; - } - - debugging_log_ << "Window state now " - << FullscreenControllerTestWindow::GetWindowStateString(window_->state()) - << std::endl; - - VerifyWindowState(); - - return true; -} - -void FullscreenControllerUnitTest::VerifyWindowState() { - switch (state_) { - case STATE_NORMAL: - EXPECT_EQ(FullscreenControllerTestWindow::NORMAL, - window_->state()) << GetAndClearDebugLog(); -#if defined(OS_MACOSX) - EXPECT_FALSE(window_->InPresentationMode()) - << GetAndClearDebugLog(); -#endif - EXPECT_FALSE(fullscreen_controller_->IsFullscreenForBrowser()) - << GetAndClearDebugLog(); - EXPECT_FALSE(fullscreen_controller_->IsFullscreenForTabOrPending()) - << GetAndClearDebugLog(); - EXPECT_FALSE(fullscreen_controller_->IsInMetroSnapMode()) - << GetAndClearDebugLog(); - break; - case STATE_BROWSER_FULLSCREEN_NO_CHROME: - EXPECT_EQ(FullscreenControllerTestWindow::FULLSCREEN, - window_->state()) << GetAndClearDebugLog(); -#if defined(OS_MACOSX) - EXPECT_FALSE(window_->InPresentationMode()) - << GetAndClearDebugLog(); -#endif - EXPECT_TRUE(fullscreen_controller_->IsFullscreenForBrowser()) - << GetAndClearDebugLog(); - EXPECT_FALSE(fullscreen_controller_->IsFullscreenForTabOrPending()) - << GetAndClearDebugLog(); - EXPECT_FALSE(fullscreen_controller_->IsInMetroSnapMode()) - << GetAndClearDebugLog(); - break; -#if defined(OS_WIN) - case STATE_METRO_SNAP: - EXPECT_EQ(FullscreenControllerTestWindow::METRO_SNAP, - window_->state()) << GetAndClearDebugLog(); - // No expectation for InPresentationMode. - EXPECT_FALSE(fullscreen_controller_->IsFullscreenForBrowser()) - << GetAndClearDebugLog(); - EXPECT_FALSE(fullscreen_controller_->IsFullscreenForTabOrPending()) - << GetAndClearDebugLog(); - EXPECT_TRUE(fullscreen_controller_->IsInMetroSnapMode()) - << GetAndClearDebugLog(); - break; -#endif - case STATE_TAB_FULLSCREEN: - EXPECT_EQ(FullscreenControllerTestWindow::FULLSCREEN, - window_->state()) << GetAndClearDebugLog(); -#if defined(OS_MACOSX) - EXPECT_TRUE(window_->InPresentationMode()) - << GetAndClearDebugLog(); -#endif - EXPECT_FALSE(fullscreen_controller_->IsFullscreenForBrowser()) - << GetAndClearDebugLog(); - EXPECT_TRUE(fullscreen_controller_->IsFullscreenForTabOrPending()) - << GetAndClearDebugLog(); - EXPECT_FALSE(fullscreen_controller_->IsInMetroSnapMode()) - << GetAndClearDebugLog(); - break; - case STATE_TAB_BROWSER_FULLSCREEN: - EXPECT_EQ(FullscreenControllerTestWindow::FULLSCREEN, - window_->state()) << GetAndClearDebugLog(); -#if defined(OS_MACOSX) - EXPECT_TRUE(window_->InPresentationMode()) - << GetAndClearDebugLog(); -#endif -#if defined(OS_MACOSX) - // TODO(scheib) Mac is reporting incorrect IsFullscreenForBrowser(). - // e.g. in FullscreenControllerUnitTest. - // STATE_BROWSER_FULLSCREEN_NO_CHROME_TAB_FULLSCREEN_TRUE - // At the end of ToggleFullscreenModeForTab - // tab_caused_fullscreen_ has incorrectly been set to true even - // though controller was already in browser fullscreen. - // http://crbug.com/155650 - EXPECT_FALSE(fullscreen_controller_->IsFullscreenForBrowser()) - << GetAndClearDebugLog(); -#else - EXPECT_TRUE(fullscreen_controller_->IsFullscreenForBrowser()) - << GetAndClearDebugLog(); -#endif - EXPECT_TRUE(fullscreen_controller_->IsFullscreenForTabOrPending()) - << GetAndClearDebugLog(); - EXPECT_FALSE(fullscreen_controller_->IsInMetroSnapMode()) - << GetAndClearDebugLog(); - break; - case STATE_TO_NORMAL: - EXPECT_EQ(FullscreenControllerTestWindow::TO_NORMAL, - window_->state()) << GetAndClearDebugLog(); -#if defined(OS_MACOSX) - EXPECT_FALSE(window_->InPresentationMode()) - << GetAndClearDebugLog(); -#endif - // No expectation for IsFullscreenForBrowser. - // No expectation for IsFullscreenForTabOrPending. - EXPECT_FALSE(fullscreen_controller_->IsInMetroSnapMode()) - << GetAndClearDebugLog(); - break; - case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME: - EXPECT_EQ(FullscreenControllerTestWindow::TO_FULLSCREEN, - window_->state()) << GetAndClearDebugLog(); -#if defined(OS_MACOSX) - EXPECT_FALSE(window_->InPresentationMode()) - << GetAndClearDebugLog(); -#endif - EXPECT_FALSE(fullscreen_controller_->IsFullscreenForBrowser()) - << GetAndClearDebugLog(); - // No expectation for IsFullscreenForTabOrPending. - EXPECT_FALSE(fullscreen_controller_->IsInMetroSnapMode()) - << GetAndClearDebugLog(); - break; - case STATE_TO_TAB_FULLSCREEN: - EXPECT_EQ(FullscreenControllerTestWindow::TO_FULLSCREEN, - window_->state()) << GetAndClearDebugLog(); -#if defined(OS_MACOSX) - EXPECT_TRUE(window_->InPresentationMode()) - << GetAndClearDebugLog(); -#endif - EXPECT_FALSE(fullscreen_controller_->IsFullscreenForBrowser()) - << GetAndClearDebugLog(); - EXPECT_TRUE(fullscreen_controller_->IsFullscreenForTabOrPending()) - << GetAndClearDebugLog(); - EXPECT_FALSE(fullscreen_controller_->IsInMetroSnapMode()) - << GetAndClearDebugLog(); - break; - default: - NOTREACHED() << GetAndClearDebugLog(); - } -} - -FullscreenControllerUnitTest::StateTransitionInfo - FullscreenControllerUnitTest::NextTransitionInShortestPath( - State source, State destination, int search_limit) { - if (search_limit == 0) - return StateTransitionInfo(); // Return a default (invalid) state. - - if (state_transitions_[source][destination].state == STATE_INVALID) { - // Don't know the next state yet, do a depth first search. - StateTransitionInfo result; - - // Consider all states reachable via each event from the source state. - for (int event_int = 0; event_int < NUM_EVENTS; event_int++) { - Event event = static_cast<Event>(event_int); - State next_state_candidate = transition_table_[source][event]; - - if (ShouldSkipStateAndEventPair(source, event)) - continue; - - // Recurse. - StateTransitionInfo candidate = NextTransitionInShortestPath( - next_state_candidate, destination, search_limit - 1); - - if (candidate.distance + 1 < result.distance) { - result.event = event; - result.state = next_state_candidate; - result.distance = candidate.distance + 1; - } - } - - // Cache result so that a search is not required next time. - state_transitions_[source][destination] = result; - } - - return state_transitions_[source][destination]; -} - -std::string FullscreenControllerUnitTest::GetAndClearDebugLog() { - debugging_log_ << "(end of log)\n"; - std::string output_log = "\nDebugging Log:\n" + debugging_log_.str(); - debugging_log_.str(""); - return output_log; -} - -bool FullscreenControllerUnitTest::ShouldSkipStateAndEventPair(State state, - Event event) { - // TODO(scheib) Toggling Tab fullscreen while pending Tab or - // Browser fullscreen is broken currently http://crbug.com/154196 - if ((state == STATE_TO_BROWSER_FULLSCREEN_NO_CHROME || - state == STATE_TO_TAB_FULLSCREEN) && - (event == TAB_FULLSCREEN_TRUE || event == TAB_FULLSCREEN_FALSE)) - return true; - if (state == STATE_TO_NORMAL && event == TAB_FULLSCREEN_TRUE) - return true; - - return false; -} - -bool FullscreenControllerUnitTest::ShouldSkipTest(State state, - Event event, - bool reentrant) { -#if defined(OS_WIN) - // FullscreenController verifies that WindowFullscreenStateChanged is - // always reentrant on Windows. It will fail if we mock asynchronous calls. - if (!reentrant) { - debugging_log_ << "\nSkipping non-reentrant test on Windows.\n"; - return true; - } -#endif - - // When testing reentrancy there are states the fullscreen controller - // will be unable to remain in, as they will progress due to the - // reentrant window change call. Skip states that will be instantly - // exited by the reentrant call. - if (reentrant && (transition_table_[state][WINDOW_CHANGE] != state)) { - debugging_log_ << "\nSkipping reentrant test for transitory source state " - << GetStateString(state) << ".\n"; - return true; - } - - return ShouldSkipStateAndEventPair(state, event); -} - -void FullscreenControllerUnitTest::TestStateAndEvent(State state, - Event event, - bool reentrant) { - if (ShouldSkipTest(state, event, reentrant)) - return; - - debugging_log_ << "\nTest transition from state " - << GetStateString(state) - << (reentrant ? " with reentrant calls.\n" : ".\n"); - window_->set_reentrant(reentrant); - - debugging_log_ << " First, from " - << GetStateString(state_) << "\n"; - ASSERT_NO_FATAL_FAILURE(TransitionToState(state)) - << GetAndClearDebugLog(); - - debugging_log_ << " Then,\n"; - ASSERT_TRUE(InvokeEvent(event)) << GetAndClearDebugLog(); -} - - -// Tests ----------------------------------------------------------------------- - -#define TEST_EVENT_INNER(state, event, reentrant, reentrant_id) \ - TEST_F(FullscreenControllerUnitTest, state##_##event##reentrant_id) { \ - AddTab(browser(), GURL(chrome::kAboutBlankURL)); \ - ASSERT_NO_FATAL_FAILURE(TestStateAndEvent(state, event, reentrant)) \ - << GetAndClearDebugLog(); \ - } - // Progress of tests can be examined by inserting the following line: - // LOG(INFO) << GetAndClearDebugLog(); } - -#define TEST_EVENT(state, event) \ - TEST_EVENT_INNER(state, event, false, ); \ - TEST_EVENT_INNER(state, event, true, _Reentrant); - -// Individual tests for each pair of state and event: - -TEST_EVENT(STATE_NORMAL, TOGGLE_FULLSCREEN); -TEST_EVENT(STATE_NORMAL, TAB_FULLSCREEN_TRUE); -TEST_EVENT(STATE_NORMAL, TAB_FULLSCREEN_FALSE); -#if defined(OS_WIN) -TEST_EVENT(STATE_NORMAL, METRO_SNAP_TRUE); -TEST_EVENT(STATE_NORMAL, METRO_SNAP_FALSE); -#endif -TEST_EVENT(STATE_NORMAL, WINDOW_CHANGE); - -TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, TOGGLE_FULLSCREEN); -TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, TAB_FULLSCREEN_TRUE); -TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, TAB_FULLSCREEN_FALSE); -#if defined(OS_WIN) -TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, METRO_SNAP_TRUE); -TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, METRO_SNAP_FALSE); -#endif -TEST_EVENT(STATE_BROWSER_FULLSCREEN_NO_CHROME, WINDOW_CHANGE); - -#if defined(OS_WIN) -TEST_EVENT(STATE_METRO_SNAP, TOGGLE_FULLSCREEN); -TEST_EVENT(STATE_METRO_SNAP, TAB_FULLSCREEN_TRUE); -TEST_EVENT(STATE_METRO_SNAP, TAB_FULLSCREEN_FALSE); -TEST_EVENT(STATE_METRO_SNAP, METRO_SNAP_TRUE); -TEST_EVENT(STATE_METRO_SNAP, METRO_SNAP_FALSE); -TEST_EVENT(STATE_METRO_SNAP, WINDOW_CHANGE); -#endif - -TEST_EVENT(STATE_TAB_FULLSCREEN, TOGGLE_FULLSCREEN); -TEST_EVENT(STATE_TAB_FULLSCREEN, TAB_FULLSCREEN_TRUE); -TEST_EVENT(STATE_TAB_FULLSCREEN, TAB_FULLSCREEN_FALSE); -#if defined(OS_WIN) -TEST_EVENT(STATE_TAB_FULLSCREEN, METRO_SNAP_TRUE); -TEST_EVENT(STATE_TAB_FULLSCREEN, METRO_SNAP_FALSE); -#endif -TEST_EVENT(STATE_TAB_FULLSCREEN, WINDOW_CHANGE); - -TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, TOGGLE_FULLSCREEN); -TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, TAB_FULLSCREEN_TRUE); -TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, TAB_FULLSCREEN_FALSE); -#if defined(OS_WIN) -TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, METRO_SNAP_TRUE); -TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, METRO_SNAP_FALSE); -#endif -TEST_EVENT(STATE_TAB_BROWSER_FULLSCREEN, WINDOW_CHANGE); - -TEST_EVENT(STATE_TO_NORMAL, TOGGLE_FULLSCREEN); -TEST_EVENT(STATE_TO_NORMAL, TAB_FULLSCREEN_TRUE); -TEST_EVENT(STATE_TO_NORMAL, TAB_FULLSCREEN_FALSE); -#if defined(OS_WIN) -TEST_EVENT(STATE_TO_NORMAL, METRO_SNAP_TRUE); -TEST_EVENT(STATE_TO_NORMAL, METRO_SNAP_FALSE); -#endif -TEST_EVENT(STATE_TO_NORMAL, WINDOW_CHANGE); - -TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, TOGGLE_FULLSCREEN); -TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, TAB_FULLSCREEN_TRUE); -TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, TAB_FULLSCREEN_FALSE); -#if defined(OS_WIN) -TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, METRO_SNAP_TRUE); -TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, METRO_SNAP_FALSE); -#endif -TEST_EVENT(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, WINDOW_CHANGE); - -TEST_EVENT(STATE_TO_TAB_FULLSCREEN, TOGGLE_FULLSCREEN); -TEST_EVENT(STATE_TO_TAB_FULLSCREEN, TAB_FULLSCREEN_TRUE); -TEST_EVENT(STATE_TO_TAB_FULLSCREEN, TAB_FULLSCREEN_FALSE); -#if defined(OS_WIN) -TEST_EVENT(STATE_TO_TAB_FULLSCREEN, METRO_SNAP_TRUE); -TEST_EVENT(STATE_TO_TAB_FULLSCREEN, METRO_SNAP_FALSE); -#endif -TEST_EVENT(STATE_TO_TAB_FULLSCREEN, WINDOW_CHANGE); - -// Specific one-off tests for known issues: - -// TODO(scheib) Toggling Tab fullscreen while pending Tab or -// Browser fullscreen is broken currently http://crbug.com/154196 -TEST_F(FullscreenControllerUnitTest, DISABLED_ToggleTabWhenPendingBrowser) { -#if !defined(OS_WIN) // Only possible without reentrancy - AddTab(browser(), GURL(chrome::kAboutBlankURL)); - ASSERT_NO_FATAL_FAILURE( - TransitionToState(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME)) - << GetAndClearDebugLog(); - - ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE)) << GetAndClearDebugLog(); - ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE)) << GetAndClearDebugLog(); - ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE)) << GetAndClearDebugLog(); -#endif -} - -// TODO(scheib) Toggling Tab fullscreen while pending Tab or -// Browser fullscreen is broken currently http://crbug.com/154196 -TEST_F(FullscreenControllerUnitTest, DISABLED_ToggleTabWhenPendingTab) { -#if !defined(OS_WIN) // Only possible without reentrancy - AddTab(browser(), GURL(chrome::kAboutBlankURL)); - ASSERT_NO_FATAL_FAILURE( - TransitionToState(STATE_TO_TAB_FULLSCREEN)) - << GetAndClearDebugLog(); - - ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE)) << GetAndClearDebugLog(); - ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE)) << GetAndClearDebugLog(); - ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE)) << GetAndClearDebugLog(); -#endif -} - -// Soak tests: - -// Tests all states with all permutations of multiple events to detect lingering -// state issues that would bleed over to other states. -// I.E. for each state test all combinations of events E1, E2, E3. -// -// This produces coverage for event sequences that may happen normally but -// would not be exposed by traversing to each state via TransitionToState(). -// TransitionToState() always takes the same path even when multiple paths -// exist. -TEST_F(FullscreenControllerUnitTest, TransitionsForEachState) { - // A tab is needed for tab fullscreen. - AddTab(browser(), GURL(chrome::kAboutBlankURL)); - for (int reentrant = 0; reentrant <= 1; reentrant++) { - for (int source_int = 0; source_int < NUM_STATES; source_int++) { - for (int event1_int = 0; event1_int < NUM_EVENTS; event1_int++) { - State state = static_cast<State>(source_int); - Event event1 = static_cast<Event>(event1_int); - - // Early out if skipping all tests for this state, reduces log noise. - if (ShouldSkipTest(state, event1, !!reentrant)) - continue; - - for (int event2_int = 0; event2_int < NUM_EVENTS; event2_int++) { - for (int event3_int = 0; event3_int < NUM_EVENTS; event3_int++) { - Event event2 = static_cast<Event>(event2_int); - Event event3 = static_cast<Event>(event3_int); - - // Test each state and each event. - ASSERT_NO_FATAL_FAILURE(TestStateAndEvent(state, - event1, - !!reentrant)) - << GetAndClearDebugLog(); - - // Then, add an additional event to the sequence. - if (ShouldSkipStateAndEventPair(state_, event2)) - continue; - ASSERT_TRUE(InvokeEvent(event2)) << GetAndClearDebugLog(); - - // Then, add an additional event to the sequence. - if (ShouldSkipStateAndEventPair(state_, event3)) - continue; - ASSERT_TRUE(InvokeEvent(event3)) << GetAndClearDebugLog(); - } - } - } - } - } - // Progress of test can be examined via LOG(INFO) << GetAndClearDebugLog(); -} - diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 8d62ac5..b633f33 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -185,6 +185,8 @@ 'browser/ui/cocoa/run_loop_testing.mm', 'browser/ui/cocoa/test/ui_test_utils_mac.mm', 'browser/ui/find_bar/find_bar_host_unittest_util.h', + 'browser/ui/fullscreen/fullscreen_controller_state_test.cc', + 'browser/ui/fullscreen/fullscreen_controller_state_test.h', 'browser/ui/fullscreen/fullscreen_controller_test.cc', 'browser/ui/fullscreen/fullscreen_controller_test.h', 'browser/ui/gtk/find_bar_host_unittest_util_gtk.cc', @@ -511,6 +513,7 @@ 'browser/task_manager/task_manager_browsertest_util.cc', 'browser/ui/browser_focus_uitest.cc', 'browser/ui/fullscreen/fullscreen_controller_interactive_browsertest.cc', + 'browser/ui/fullscreen/fullscreen_controller_state_interactive_browsertest.cc', 'browser/ui/gtk/bookmarks/bookmark_bar_gtk_interactive_uitest.cc', 'browser/ui/omnibox/action_box_browsertest.cc', 'browser/ui/omnibox/omnibox_view_browsertest.cc', @@ -1982,7 +1985,7 @@ 'browser/ui/content_settings/content_setting_bubble_model_unittest.cc', 'browser/ui/content_settings/content_setting_image_model_unittest.cc', 'browser/ui/find_bar/find_backend_unittest.cc', - 'browser/ui/fullscreen/fullscreen_controller_unittest.cc', + 'browser/ui/fullscreen/fullscreen_controller_state_unittest.cc', 'browser/ui/global_error/global_error_service_unittest.cc', 'browser/ui/gtk/accelerators_gtk_unittest.cc', 'browser/ui/gtk/bookmarks/bookmark_bar_gtk_unittest.cc', @@ -2680,6 +2683,7 @@ 'browser/ui/bookmarks/bookmark_context_menu_controller_unittest.cc', 'browser/ui/bookmarks/bookmark_prompt_controller_unittest.cc', 'browser/ui/browser_command_controller_unittest.cc', + 'browser/ui/fullscreen/fullscreen_controller_state_unittest.cc', 'browser/ui/fullscreen/fullscreen_controller_unittest.cc', 'browser/ui/search/search_delegate_unittest.cc', 'browser/ui/tab_contents/tab_contents_iterator_unittest.cc', diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc index 6b842dd..e135331 100644 --- a/chrome/test/base/in_process_browser_test.cc +++ b/chrome/test/base/in_process_browser_test.cc @@ -39,6 +39,7 @@ #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_browser_thread.h" #include "content/public/test/test_launcher.h" +#include "content/public/test/test_navigation_observer.h" #include "net/base/mock_host_resolver.h" #include "net/test/test_server.h" #include "ui/compositor/compositor_switches.h" @@ -212,10 +213,15 @@ void InProcessBrowserTest::AddTabAtIndexToBrowser( int index, const GURL& url, content::PageTransition transition) { + content::TestNavigationObserver observer( + content::NotificationService::AllSources(), NULL, 1); + chrome::NavigateParams params(browser, url, transition); params.tabstrip_index = index; params.disposition = NEW_FOREGROUND_TAB; chrome::Navigate(¶ms); + + observer.Wait(); } void InProcessBrowserTest::AddTabAtIndex( |