| // 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 <string> |
| |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/prefs/pref_service.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/values.h" |
| #include "chrome/browser/extensions/api/tabs/tabs_api.h" |
| #include "chrome/browser/extensions/api/tabs/tabs_constants.h" |
| #include "chrome/browser/extensions/extension_function_test_utils.h" |
| #include "chrome/browser/extensions/extension_tab_util.h" |
| #include "chrome/browser/prefs/incognito_mode_prefs.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "content/public/common/page_zoom.h" |
| #include "content/public/common/url_constants.h" |
| #include "extensions/common/manifest_constants.h" |
| #include "extensions/common/test_util.h" |
| #include "net/test/spawned_test_server/spawned_test_server.h" |
| #include "ui/gfx/rect.h" |
| |
| namespace extensions { |
| |
| namespace keys = tabs_constants; |
| namespace utils = extension_function_test_utils; |
| |
| namespace { |
| |
| class ExtensionTabsTest : public InProcessBrowserTest { |
| }; |
| |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetWindow) { |
| int window_id = ExtensionTabUtil::GetWindowId(browser()); |
| |
| // Invalid window ID error. |
| scoped_refptr<WindowsGetFunction> function = new WindowsGetFunction(); |
| scoped_refptr<Extension> extension(test_util::CreateEmptyExtension()); |
| function->set_extension(extension.get()); |
| EXPECT_TRUE(MatchPattern( |
| utils::RunFunctionAndReturnError( |
| function.get(), |
| base::StringPrintf("[%u]", window_id + 1), |
| browser()), |
| keys::kWindowNotFoundError)); |
| |
| // Basic window details. |
| gfx::Rect bounds; |
| if (browser()->window()->IsMinimized()) |
| bounds = browser()->window()->GetRestoredBounds(); |
| else |
| bounds = browser()->window()->GetBounds(); |
| |
| function = new WindowsGetFunction(); |
| function->set_extension(extension.get()); |
| scoped_ptr<base::DictionaryValue> result(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult( |
| function.get(), |
| base::StringPrintf("[%u]", window_id), |
| browser()))); |
| EXPECT_EQ(window_id, utils::GetInteger(result.get(), "id")); |
| EXPECT_FALSE(utils::GetBoolean(result.get(), "incognito")); |
| EXPECT_EQ("normal", utils::GetString(result.get(), "type")); |
| EXPECT_EQ(bounds.x(), utils::GetInteger(result.get(), "left")); |
| EXPECT_EQ(bounds.y(), utils::GetInteger(result.get(), "top")); |
| EXPECT_EQ(bounds.width(), utils::GetInteger(result.get(), "width")); |
| EXPECT_EQ(bounds.height(), utils::GetInteger(result.get(), "height")); |
| |
| // With "populate" enabled. |
| function = new WindowsGetFunction(); |
| function->set_extension(extension.get()); |
| result.reset(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult( |
| function.get(), |
| base::StringPrintf("[%u, {\"populate\": true}]", window_id), |
| browser()))); |
| |
| EXPECT_EQ(window_id, utils::GetInteger(result.get(), "id")); |
| // "populate" was enabled so tabs should be populated. |
| base::ListValue* tabs = NULL; |
| EXPECT_TRUE(result.get()->GetList(keys::kTabsKey, &tabs)); |
| |
| // TODO(aa): Can't assume window is focused. On mac, calling Activate() from a |
| // browser test doesn't seem to do anything, so can't test the opposite |
| // either. |
| EXPECT_EQ(browser()->window()->IsActive(), |
| utils::GetBoolean(result.get(), "focused")); |
| |
| // TODO(aa): Minimized and maximized dimensions. Is there a way to set |
| // minimize/maximize programmatically? |
| |
| // Popup. |
| Browser* popup_browser = new Browser( |
| Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), |
| browser()->host_desktop_type())); |
| function = new WindowsGetFunction(); |
| function->set_extension(extension.get()); |
| result.reset(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult( |
| function.get(), |
| base::StringPrintf( |
| "[%u]", ExtensionTabUtil::GetWindowId(popup_browser)), |
| browser()))); |
| EXPECT_EQ("popup", utils::GetString(result.get(), "type")); |
| |
| // Incognito. |
| Browser* incognito_browser = CreateIncognitoBrowser(); |
| int incognito_window_id = ExtensionTabUtil::GetWindowId(incognito_browser); |
| |
| // Without "include_incognito". |
| function = new WindowsGetFunction(); |
| function->set_extension(extension.get()); |
| EXPECT_TRUE(MatchPattern( |
| utils::RunFunctionAndReturnError( |
| function.get(), |
| base::StringPrintf("[%u]", incognito_window_id), |
| browser()), |
| keys::kWindowNotFoundError)); |
| |
| // With "include_incognito". |
| function = new WindowsGetFunction(); |
| function->set_extension(extension.get()); |
| result.reset(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult( |
| function.get(), |
| base::StringPrintf("[%u]", incognito_window_id), |
| browser(), |
| utils::INCLUDE_INCOGNITO))); |
| EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetCurrentWindow) { |
| int window_id = ExtensionTabUtil::GetWindowId(browser()); |
| Browser* new_browser = CreateBrowser(browser()->profile()); |
| int new_id = ExtensionTabUtil::GetWindowId(new_browser); |
| |
| // Get the current window using new_browser. |
| scoped_refptr<WindowsGetCurrentFunction> function = |
| new WindowsGetCurrentFunction(); |
| scoped_refptr<Extension> extension(test_util::CreateEmptyExtension()); |
| function->set_extension(extension.get()); |
| scoped_ptr<base::DictionaryValue> result(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult(function.get(), |
| "[]", |
| new_browser))); |
| |
| // The id should match the window id of the browser instance that was passed |
| // to RunFunctionAndReturnSingleResult. |
| EXPECT_EQ(new_id, utils::GetInteger(result.get(), "id")); |
| base::ListValue* tabs = NULL; |
| EXPECT_FALSE(result.get()->GetList(keys::kTabsKey, &tabs)); |
| |
| // Get the current window using the old window and make the tabs populated. |
| function = new WindowsGetCurrentFunction(); |
| function->set_extension(extension.get()); |
| result.reset(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult(function.get(), |
| "[{\"populate\": true}]", |
| browser()))); |
| |
| // The id should match the window id of the browser instance that was passed |
| // to RunFunctionAndReturnSingleResult. |
| EXPECT_EQ(window_id, utils::GetInteger(result.get(), "id")); |
| // "populate" was enabled so tabs should be populated. |
| EXPECT_TRUE(result.get()->GetList(keys::kTabsKey, &tabs)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetAllWindows) { |
| const size_t NUM_WINDOWS = 5; |
| std::set<int> window_ids; |
| std::set<int> result_ids; |
| window_ids.insert(ExtensionTabUtil::GetWindowId(browser())); |
| |
| for (size_t i = 0; i < NUM_WINDOWS - 1; ++i) { |
| Browser* new_browser = CreateBrowser(browser()->profile()); |
| window_ids.insert(ExtensionTabUtil::GetWindowId(new_browser)); |
| } |
| |
| scoped_refptr<WindowsGetAllFunction> function = new WindowsGetAllFunction(); |
| scoped_refptr<Extension> extension(test_util::CreateEmptyExtension()); |
| function->set_extension(extension.get()); |
| scoped_ptr<base::ListValue> result(utils::ToList( |
| utils::RunFunctionAndReturnSingleResult(function.get(), |
| "[]", |
| browser()))); |
| |
| base::ListValue* windows = result.get(); |
| EXPECT_EQ(NUM_WINDOWS, windows->GetSize()); |
| for (size_t i = 0; i < NUM_WINDOWS; ++i) { |
| base::DictionaryValue* result_window = NULL; |
| EXPECT_TRUE(windows->GetDictionary(i, &result_window)); |
| result_ids.insert(utils::GetInteger(result_window, "id")); |
| |
| // "populate" was not passed in so tabs are not populated. |
| base::ListValue* tabs = NULL; |
| EXPECT_FALSE(result_window->GetList(keys::kTabsKey, &tabs)); |
| } |
| // The returned ids should contain all the current browser instance ids. |
| EXPECT_EQ(window_ids, result_ids); |
| |
| result_ids.clear(); |
| function = new WindowsGetAllFunction(); |
| function->set_extension(extension.get()); |
| result.reset(utils::ToList( |
| utils::RunFunctionAndReturnSingleResult(function.get(), |
| "[{\"populate\": true}]", |
| browser()))); |
| |
| windows = result.get(); |
| EXPECT_EQ(NUM_WINDOWS, windows->GetSize()); |
| for (size_t i = 0; i < windows->GetSize(); ++i) { |
| base::DictionaryValue* result_window = NULL; |
| EXPECT_TRUE(windows->GetDictionary(i, &result_window)); |
| result_ids.insert(utils::GetInteger(result_window, "id")); |
| |
| // "populate" was enabled so tabs should be populated. |
| base::ListValue* tabs = NULL; |
| EXPECT_TRUE(result_window->GetList(keys::kTabsKey, &tabs)); |
| } |
| // The returned ids should contain all the current browser instance ids. |
| EXPECT_EQ(window_ids, result_ids); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, UpdateNoPermissions) { |
| // The test empty extension has no permissions, therefore it should not get |
| // tab data in the function result. |
| scoped_refptr<TabsUpdateFunction> update_tab_function( |
| new TabsUpdateFunction()); |
| scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension()); |
| update_tab_function->set_extension(empty_extension.get()); |
| // Without a callback the function will not generate a result. |
| update_tab_function->set_has_callback(true); |
| |
| scoped_ptr<base::DictionaryValue> result(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult( |
| update_tab_function.get(), |
| "[null, {\"url\": \"about:blank\", \"pinned\": true}]", |
| browser()))); |
| // The url is stripped since the extension does not have tab permissions. |
| EXPECT_FALSE(result->HasKey("url")); |
| EXPECT_TRUE(utils::GetBoolean(result.get(), "pinned")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, |
| DefaultToIncognitoWhenItIsForced) { |
| static const char kArgsWithoutExplicitIncognitoParam[] = |
| "[{\"url\": \"about:blank\"}]"; |
| // Force Incognito mode. |
| IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(), |
| IncognitoModePrefs::FORCED); |
| // Run without an explicit "incognito" param. |
| scoped_refptr<WindowsCreateFunction> function(new WindowsCreateFunction()); |
| scoped_refptr<Extension> extension(test_util::CreateEmptyExtension()); |
| function->set_extension(extension.get()); |
| scoped_ptr<base::DictionaryValue> result(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult( |
| function.get(), |
| kArgsWithoutExplicitIncognitoParam, |
| browser(), |
| utils::INCLUDE_INCOGNITO))); |
| |
| // Make sure it is a new(different) window. |
| EXPECT_NE(ExtensionTabUtil::GetWindowId(browser()), |
| utils::GetInteger(result.get(), "id")); |
| // ... and it is incognito. |
| EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito")); |
| |
| // Now try creating a window from incognito window. |
| Browser* incognito_browser = CreateIncognitoBrowser(); |
| // Run without an explicit "incognito" param. |
| function = new WindowsCreateFunction(); |
| function->set_extension(extension.get()); |
| result.reset(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult( |
| function.get(), |
| kArgsWithoutExplicitIncognitoParam, |
| incognito_browser, |
| utils::INCLUDE_INCOGNITO))); |
| // Make sure it is a new(different) window. |
| EXPECT_NE(ExtensionTabUtil::GetWindowId(incognito_browser), |
| utils::GetInteger(result.get(), "id")); |
| // ... and it is incognito. |
| EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, |
| DefaultToIncognitoWhenItIsForcedAndNoArgs) { |
| static const char kEmptyArgs[] = "[]"; |
| // Force Incognito mode. |
| IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(), |
| IncognitoModePrefs::FORCED); |
| // Run without an explicit "incognito" param. |
| scoped_refptr<WindowsCreateFunction> function = new WindowsCreateFunction(); |
| scoped_refptr<Extension> extension(test_util::CreateEmptyExtension()); |
| function->set_extension(extension.get()); |
| scoped_ptr<base::DictionaryValue> result(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult(function.get(), |
| kEmptyArgs, |
| browser(), |
| utils::INCLUDE_INCOGNITO))); |
| |
| // Make sure it is a new(different) window. |
| EXPECT_NE(ExtensionTabUtil::GetWindowId(browser()), |
| utils::GetInteger(result.get(), "id")); |
| // ... and it is incognito. |
| EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito")); |
| |
| // Now try creating a window from incognito window. |
| Browser* incognito_browser = CreateIncognitoBrowser(); |
| // Run without an explicit "incognito" param. |
| function = new WindowsCreateFunction(); |
| function->set_extension(extension.get()); |
| result.reset(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult(function.get(), |
| kEmptyArgs, |
| incognito_browser, |
| utils::INCLUDE_INCOGNITO))); |
| // Make sure it is a new(different) window. |
| EXPECT_NE(ExtensionTabUtil::GetWindowId(incognito_browser), |
| utils::GetInteger(result.get(), "id")); |
| // ... and it is incognito. |
| EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, |
| DontCreateNormalWindowWhenIncognitoForced) { |
| static const char kArgsWithExplicitIncognitoParam[] = |
| "[{\"url\": \"about:blank\", \"incognito\": false }]"; |
| // Force Incognito mode. |
| IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(), |
| IncognitoModePrefs::FORCED); |
| |
| // Run with an explicit "incognito" param. |
| scoped_refptr<WindowsCreateFunction> function = new WindowsCreateFunction(); |
| scoped_refptr<Extension> extension(test_util::CreateEmptyExtension()); |
| function->set_extension(extension.get()); |
| EXPECT_TRUE(MatchPattern( |
| utils::RunFunctionAndReturnError(function.get(), |
| kArgsWithExplicitIncognitoParam, |
| browser()), |
| keys::kIncognitoModeIsForced)); |
| |
| // Now try opening a normal window from incognito window. |
| Browser* incognito_browser = CreateIncognitoBrowser(); |
| // Run with an explicit "incognito" param. |
| function = new WindowsCreateFunction(); |
| function->set_extension(extension.get()); |
| EXPECT_TRUE(MatchPattern( |
| utils::RunFunctionAndReturnError(function.get(), |
| kArgsWithExplicitIncognitoParam, |
| incognito_browser), |
| keys::kIncognitoModeIsForced)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, |
| DontCreateIncognitoWindowWhenIncognitoDisabled) { |
| static const char kArgs[] = |
| "[{\"url\": \"about:blank\", \"incognito\": true }]"; |
| |
| Browser* incognito_browser = CreateIncognitoBrowser(); |
| // Disable Incognito mode. |
| IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(), |
| IncognitoModePrefs::DISABLED); |
| // Run in normal window. |
| scoped_refptr<WindowsCreateFunction> function = new WindowsCreateFunction(); |
| scoped_refptr<Extension> extension(test_util::CreateEmptyExtension()); |
| function->set_extension(extension.get()); |
| EXPECT_TRUE(MatchPattern( |
| utils::RunFunctionAndReturnError(function.get(), |
| kArgs, |
| browser()), |
| keys::kIncognitoModeIsDisabled)); |
| |
| // Run in incognito window. |
| function = new WindowsCreateFunction(); |
| function->set_extension(extension.get()); |
| EXPECT_TRUE(MatchPattern( |
| utils::RunFunctionAndReturnError(function.get(), |
| kArgs, |
| incognito_browser), |
| keys::kIncognitoModeIsDisabled)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, QueryCurrentWindowTabs) { |
| const size_t kExtraWindows = 3; |
| for (size_t i = 0; i < kExtraWindows; ++i) |
| CreateBrowser(browser()->profile()); |
| |
| GURL url(url::kAboutBlankURL); |
| AddTabAtIndexToBrowser(browser(), 0, url, ui::PAGE_TRANSITION_LINK); |
| int window_id = ExtensionTabUtil::GetWindowId(browser()); |
| |
| // Get tabs in the 'current' window called from non-focused browser. |
| scoped_refptr<TabsQueryFunction> function = new TabsQueryFunction(); |
| function->set_extension(test_util::CreateEmptyExtension().get()); |
| scoped_ptr<base::ListValue> result(utils::ToList( |
| utils::RunFunctionAndReturnSingleResult(function.get(), |
| "[{\"currentWindow\":true}]", |
| browser()))); |
| |
| base::ListValue* result_tabs = result.get(); |
| // We should have one initial tab and one added tab. |
| EXPECT_EQ(2u, result_tabs->GetSize()); |
| for (size_t i = 0; i < result_tabs->GetSize(); ++i) { |
| base::DictionaryValue* result_tab = NULL; |
| EXPECT_TRUE(result_tabs->GetDictionary(i, &result_tab)); |
| EXPECT_EQ(window_id, utils::GetInteger(result_tab, keys::kWindowIdKey)); |
| } |
| |
| // Get tabs NOT in the 'current' window called from non-focused browser. |
| function = new TabsQueryFunction(); |
| function->set_extension(test_util::CreateEmptyExtension().get()); |
| result.reset(utils::ToList( |
| utils::RunFunctionAndReturnSingleResult(function.get(), |
| "[{\"currentWindow\":false}]", |
| browser()))); |
| |
| result_tabs = result.get(); |
| // We should have one tab for each extra window. |
| EXPECT_EQ(kExtraWindows, result_tabs->GetSize()); |
| for (size_t i = 0; i < kExtraWindows; ++i) { |
| base::DictionaryValue* result_tab = NULL; |
| EXPECT_TRUE(result_tabs->GetDictionary(i, &result_tab)); |
| EXPECT_NE(window_id, utils::GetInteger(result_tab, keys::kWindowIdKey)); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DontCreateTabInClosingPopupWindow) { |
| // Test creates new popup window, closes it right away and then tries to open |
| // a new tab in it. Tab should not be opened in the popup window, but in a |
| // tabbed browser window. |
| Browser* popup_browser = new Browser( |
| Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), |
| browser()->host_desktop_type())); |
| int window_id = ExtensionTabUtil::GetWindowId(popup_browser); |
| chrome::CloseWindow(popup_browser); |
| |
| scoped_refptr<TabsCreateFunction> create_tab_function( |
| new TabsCreateFunction()); |
| create_tab_function->set_extension(test_util::CreateEmptyExtension().get()); |
| // Without a callback the function will not generate a result. |
| create_tab_function->set_has_callback(true); |
| |
| static const char kNewBlankTabArgs[] = |
| "[{\"url\": \"about:blank\", \"windowId\": %u}]"; |
| |
| scoped_ptr<base::DictionaryValue> result(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult( |
| create_tab_function.get(), |
| base::StringPrintf(kNewBlankTabArgs, window_id), |
| browser()))); |
| |
| EXPECT_NE(window_id, utils::GetInteger(result.get(), "windowId")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, InvalidUpdateWindowState) { |
| int window_id = ExtensionTabUtil::GetWindowId(browser()); |
| |
| static const char kArgsMinimizedWithFocus[] = |
| "[%u, {\"state\": \"minimized\", \"focused\": true}]"; |
| scoped_refptr<WindowsUpdateFunction> function = new WindowsUpdateFunction(); |
| scoped_refptr<Extension> extension(test_util::CreateEmptyExtension()); |
| function->set_extension(extension.get()); |
| EXPECT_TRUE(MatchPattern( |
| utils::RunFunctionAndReturnError( |
| function.get(), |
| base::StringPrintf(kArgsMinimizedWithFocus, window_id), |
| browser()), |
| keys::kInvalidWindowStateError)); |
| |
| static const char kArgsMaximizedWithoutFocus[] = |
| "[%u, {\"state\": \"maximized\", \"focused\": false}]"; |
| function = new WindowsUpdateFunction(); |
| function->set_extension(extension.get()); |
| EXPECT_TRUE(MatchPattern( |
| utils::RunFunctionAndReturnError( |
| function.get(), |
| base::StringPrintf(kArgsMaximizedWithoutFocus, window_id), |
| browser()), |
| keys::kInvalidWindowStateError)); |
| |
| static const char kArgsMinimizedWithBounds[] = |
| "[%u, {\"state\": \"minimized\", \"width\": 500}]"; |
| function = new WindowsUpdateFunction(); |
| function->set_extension(extension.get()); |
| EXPECT_TRUE(MatchPattern( |
| utils::RunFunctionAndReturnError( |
| function.get(), |
| base::StringPrintf(kArgsMinimizedWithBounds, window_id), |
| browser()), |
| keys::kInvalidWindowStateError)); |
| |
| static const char kArgsMaximizedWithBounds[] = |
| "[%u, {\"state\": \"maximized\", \"width\": 500}]"; |
| function = new WindowsUpdateFunction(); |
| function->set_extension(extension.get()); |
| EXPECT_TRUE(MatchPattern( |
| utils::RunFunctionAndReturnError( |
| function.get(), |
| base::StringPrintf(kArgsMaximizedWithBounds, window_id), |
| browser()), |
| keys::kInvalidWindowStateError)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DuplicateTab) { |
| content::OpenURLParams params(GURL(url::kAboutBlankURL), |
| content::Referrer(), |
| NEW_FOREGROUND_TAB, |
| ui::PAGE_TRANSITION_LINK, |
| false); |
| content::WebContents* web_contents = browser()->OpenURL(params); |
| int tab_id = ExtensionTabUtil::GetTabId(web_contents); |
| int window_id = ExtensionTabUtil::GetWindowIdOfTab(web_contents); |
| int tab_index = -1; |
| TabStripModel* tab_strip; |
| ExtensionTabUtil::GetTabStripModel(web_contents, &tab_strip, &tab_index); |
| |
| scoped_refptr<TabsDuplicateFunction> duplicate_tab_function( |
| new TabsDuplicateFunction()); |
| scoped_ptr<base::DictionaryValue> test_extension_value( |
| utils::ParseDictionary( |
| "{\"name\": \"Test\", \"version\": \"1.0\", \"permissions\": [\"tabs\"]}" |
| )); |
| scoped_refptr<Extension> empty_tab_extension( |
| utils::CreateExtension(test_extension_value.get())); |
| duplicate_tab_function->set_extension(empty_tab_extension.get()); |
| duplicate_tab_function->set_has_callback(true); |
| |
| scoped_ptr<base::DictionaryValue> duplicate_result(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult( |
| duplicate_tab_function.get(), base::StringPrintf("[%u]", tab_id), |
| browser()))); |
| |
| int duplicate_tab_id = utils::GetInteger(duplicate_result.get(), "id"); |
| int duplicate_tab_window_id = utils::GetInteger(duplicate_result.get(), |
| "windowId"); |
| int duplicate_tab_index = utils::GetInteger(duplicate_result.get(), "index"); |
| EXPECT_EQ(base::Value::TYPE_DICTIONARY, duplicate_result->GetType()); |
| // Duplicate tab id should be different from the original tab id. |
| EXPECT_NE(tab_id, duplicate_tab_id); |
| EXPECT_EQ(window_id, duplicate_tab_window_id); |
| EXPECT_EQ(tab_index + 1, duplicate_tab_index); |
| // The test empty tab extension has tabs permissions, therefore |
| // |duplicate_result| should contain url, title, and faviconUrl |
| // in the function result. |
| EXPECT_TRUE(utils::HasPrivacySensitiveFields(duplicate_result.get())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DuplicateTabNoPermission) { |
| content::OpenURLParams params(GURL(url::kAboutBlankURL), |
| content::Referrer(), |
| NEW_FOREGROUND_TAB, |
| ui::PAGE_TRANSITION_LINK, |
| false); |
| content::WebContents* web_contents = browser()->OpenURL(params); |
| int tab_id = ExtensionTabUtil::GetTabId(web_contents); |
| int window_id = ExtensionTabUtil::GetWindowIdOfTab(web_contents); |
| int tab_index = -1; |
| TabStripModel* tab_strip; |
| ExtensionTabUtil::GetTabStripModel(web_contents, &tab_strip, &tab_index); |
| |
| scoped_refptr<TabsDuplicateFunction> duplicate_tab_function( |
| new TabsDuplicateFunction()); |
| scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension()); |
| duplicate_tab_function->set_extension(empty_extension.get()); |
| duplicate_tab_function->set_has_callback(true); |
| |
| scoped_ptr<base::DictionaryValue> duplicate_result(utils::ToDictionary( |
| utils::RunFunctionAndReturnSingleResult( |
| duplicate_tab_function.get(), base::StringPrintf("[%u]", tab_id), |
| browser()))); |
| |
| int duplicate_tab_id = utils::GetInteger(duplicate_result.get(), "id"); |
| int duplicate_tab_window_id = utils::GetInteger(duplicate_result.get(), |
| "windowId"); |
| int duplicate_tab_index = utils::GetInteger(duplicate_result.get(), "index"); |
| EXPECT_EQ(base::Value::TYPE_DICTIONARY, duplicate_result->GetType()); |
| // Duplicate tab id should be different from the original tab id. |
| EXPECT_NE(tab_id, duplicate_tab_id); |
| EXPECT_EQ(window_id, duplicate_tab_window_id); |
| EXPECT_EQ(tab_index + 1, duplicate_tab_index); |
| // The test empty extension has no permissions, therefore |duplicate_result| |
| // should not contain url, title, and faviconUrl in the function result. |
| EXPECT_FALSE(utils::HasPrivacySensitiveFields(duplicate_result.get())); |
| } |
| |
| // Tester class for the tabs.zoom* api functions. |
| class ExtensionTabsZoomTest : public ExtensionTabsTest { |
| public: |
| void SetUpOnMainThread() override; |
| |
| // Runs chrome.tabs.setZoom(). |
| bool RunSetZoom(int tab_id, double zoom_factor); |
| |
| // Runs chrome.tabs.getZoom(). |
| testing::AssertionResult RunGetZoom(int tab_id, double* zoom_factor); |
| |
| // Runs chrome.tabs.setZoomSettings(). |
| bool RunSetZoomSettings(int tab_id, const char* mode, const char* scope); |
| |
| // Runs chrome.tabs.getZoomSettings(). |
| testing::AssertionResult RunGetZoomSettings(int tab_id, |
| std::string* mode, |
| std::string* scope); |
| |
| // Runs chrome.tabs.setZoom(), expecting an error. |
| std::string RunSetZoomExpectError(int tab_id, |
| double zoom_factor); |
| |
| // Runs chrome.tabs.setZoomSettings(), expecting an error. |
| std::string RunSetZoomSettingsExpectError(int tab_id, |
| const char* mode, |
| const char* scope); |
| |
| content::WebContents* OpenUrlAndWaitForLoad(const GURL& url); |
| |
| private: |
| scoped_refptr<Extension> extension_; |
| }; |
| |
| void ExtensionTabsZoomTest::SetUpOnMainThread() { |
| ExtensionTabsTest::SetUpOnMainThread(); |
| extension_ = test_util::CreateEmptyExtension(); |
| } |
| |
| bool ExtensionTabsZoomTest::RunSetZoom(int tab_id, double zoom_factor) { |
| scoped_refptr<TabsSetZoomFunction> set_zoom_function( |
| new TabsSetZoomFunction()); |
| set_zoom_function->set_extension(extension_.get()); |
| set_zoom_function->set_has_callback(true); |
| |
| return utils::RunFunction( |
| set_zoom_function.get(), |
| base::StringPrintf("[%u, %lf]", tab_id, zoom_factor), |
| browser(), |
| extension_function_test_utils::NONE); |
| } |
| |
| testing::AssertionResult ExtensionTabsZoomTest::RunGetZoom( |
| int tab_id, |
| double* zoom_factor) { |
| scoped_refptr<TabsGetZoomFunction> get_zoom_function( |
| new TabsGetZoomFunction()); |
| get_zoom_function->set_extension(extension_.get()); |
| get_zoom_function->set_has_callback(true); |
| |
| scoped_ptr<base::Value> get_zoom_result( |
| utils::RunFunctionAndReturnSingleResult( |
| get_zoom_function.get(), |
| base::StringPrintf("[%u]", tab_id), |
| browser())); |
| |
| if (!get_zoom_result) |
| return testing::AssertionFailure() << "no result"; |
| if (!get_zoom_result->GetAsDouble(zoom_factor)) |
| return testing::AssertionFailure() << "result was not a double"; |
| |
| return testing::AssertionSuccess(); |
| } |
| |
| bool ExtensionTabsZoomTest::RunSetZoomSettings(int tab_id, |
| const char* mode, |
| const char* scope) { |
| scoped_refptr<TabsSetZoomSettingsFunction> set_zoom_settings_function( |
| new TabsSetZoomSettingsFunction()); |
| set_zoom_settings_function->set_extension(extension_.get()); |
| |
| std::string args; |
| if (scope) { |
| args = base::StringPrintf("[%u, {\"mode\": \"%s\", \"scope\": \"%s\"}]", |
| tab_id, mode, scope); |
| } else { |
| args = base::StringPrintf("[%u, {\"mode\": \"%s\"}]", tab_id, mode); |
| } |
| |
| return utils::RunFunction(set_zoom_settings_function.get(), |
| args, |
| browser(), |
| extension_function_test_utils::NONE); |
| } |
| |
| testing::AssertionResult ExtensionTabsZoomTest::RunGetZoomSettings( |
| int tab_id, |
| std::string* mode, |
| std::string* scope) { |
| DCHECK(mode); |
| DCHECK(scope); |
| scoped_refptr<TabsGetZoomSettingsFunction> get_zoom_settings_function( |
| new TabsGetZoomSettingsFunction()); |
| get_zoom_settings_function->set_extension(extension_.get()); |
| get_zoom_settings_function->set_has_callback(true); |
| |
| scoped_ptr<base::DictionaryValue> get_zoom_settings_result( |
| utils::ToDictionary(utils::RunFunctionAndReturnSingleResult( |
| get_zoom_settings_function.get(), |
| base::StringPrintf("[%u]", tab_id), |
| browser()))); |
| |
| if (!get_zoom_settings_result) |
| return testing::AssertionFailure() << "no result"; |
| |
| *mode = utils::GetString(get_zoom_settings_result.get(), "mode"); |
| *scope = utils::GetString(get_zoom_settings_result.get(), "scope"); |
| |
| return testing::AssertionSuccess(); |
| } |
| |
| std::string ExtensionTabsZoomTest::RunSetZoomExpectError(int tab_id, |
| double zoom_factor) { |
| scoped_refptr<TabsSetZoomFunction> set_zoom_function( |
| new TabsSetZoomFunction()); |
| set_zoom_function->set_extension(extension_.get()); |
| set_zoom_function->set_has_callback(true); |
| |
| return utils::RunFunctionAndReturnError( |
| set_zoom_function.get(), |
| base::StringPrintf("[%u, %lf]", tab_id, zoom_factor), |
| browser()); |
| } |
| |
| std::string ExtensionTabsZoomTest::RunSetZoomSettingsExpectError( |
| int tab_id, |
| const char* mode, |
| const char* scope) { |
| scoped_refptr<TabsSetZoomSettingsFunction> set_zoom_settings_function( |
| new TabsSetZoomSettingsFunction()); |
| set_zoom_settings_function->set_extension(extension_.get()); |
| |
| return utils::RunFunctionAndReturnError(set_zoom_settings_function.get(), |
| base::StringPrintf( |
| "[%u, {\"mode\": \"%s\", " |
| "\"scope\": \"%s\"}]", |
| tab_id, |
| mode, |
| scope), |
| browser()); |
| } |
| |
| content::WebContents* ExtensionTabsZoomTest::OpenUrlAndWaitForLoad( |
| const GURL& url) { |
| ui_test_utils::NavigateToURLWithDisposition( |
| browser(), |
| url, |
| NEW_FOREGROUND_TAB, |
| ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); |
| return browser()->tab_strip_model()->GetActiveWebContents(); |
| } |
| |
| namespace { |
| |
| double GetZoomLevel(const content::WebContents* web_contents) { |
| return ZoomController::FromWebContents(web_contents)->GetZoomLevel(); |
| } |
| |
| content::OpenURLParams GetOpenParams(const char* url) { |
| return content::OpenURLParams(GURL(url), |
| content::Referrer(), |
| NEW_FOREGROUND_TAB, |
| ui::PAGE_TRANSITION_LINK, |
| false); |
| } |
| |
| } // namespace |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest, SetAndGetZoom) { |
| content::OpenURLParams params(GetOpenParams(url::kAboutBlankURL)); |
| content::WebContents* web_contents = OpenUrlAndWaitForLoad(params.url); |
| int tab_id = ExtensionTabUtil::GetTabId(web_contents); |
| |
| // Test default values before we set anything. |
| double zoom_factor = -1; |
| EXPECT_TRUE(RunGetZoom(tab_id, &zoom_factor)); |
| EXPECT_EQ(1.0, zoom_factor); |
| |
| // Test chrome.tabs.setZoom(). |
| const double kZoomLevel = 0.8; |
| EXPECT_TRUE(RunSetZoom(tab_id, kZoomLevel)); |
| EXPECT_EQ(kZoomLevel, |
| content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents))); |
| |
| // Test chrome.tabs.getZoom(). |
| zoom_factor = -1; |
| EXPECT_TRUE(RunGetZoom(tab_id, &zoom_factor)); |
| EXPECT_EQ(kZoomLevel, zoom_factor); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest, ZoomSettings) { |
| // In this test we need two URLs that (1) represent real pages (i.e. they |
| // load without causing an error page load), (2) have different domains, and |
| // (3) are zoomable by the extension API (this last condition rules out |
| // chrome:// urls). We achieve this by noting that about:blank meets these |
| // requirements, allowing us to spin up a spawned http server on localhost to |
| // get the other domain. |
| net::SpawnedTestServer http_server( |
| net::SpawnedTestServer::TYPE_HTTP, |
| net::SpawnedTestServer::kLocalhost, |
| base::FilePath(FILE_PATH_LITERAL("chrome/test/data"))); |
| ASSERT_TRUE(http_server.Start()); |
| |
| GURL url_A = http_server.GetURL("files/simple.html"); |
| GURL url_B("about:blank"); |
| |
| // Tabs A1 and A2 are navigated to the same origin, while B is navigated |
| // to a different one. |
| content::WebContents* web_contents_A1 = OpenUrlAndWaitForLoad(url_A); |
| content::WebContents* web_contents_A2 = OpenUrlAndWaitForLoad(url_A); |
| content::WebContents* web_contents_B = OpenUrlAndWaitForLoad(url_B); |
| |
| int tab_id_A1 = ExtensionTabUtil::GetTabId(web_contents_A1); |
| int tab_id_A2 = ExtensionTabUtil::GetTabId(web_contents_A2); |
| int tab_id_B = ExtensionTabUtil::GetTabId(web_contents_B); |
| |
| ASSERT_FLOAT_EQ( |
| 1.f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1))); |
| ASSERT_FLOAT_EQ( |
| 1.f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2))); |
| ASSERT_FLOAT_EQ( |
| 1.f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_B))); |
| |
| // Test per-origin automatic zoom settings. |
| EXPECT_TRUE(RunSetZoom(tab_id_B, 1.f)); |
| EXPECT_TRUE(RunSetZoom(tab_id_A2, 1.1f)); |
| EXPECT_FLOAT_EQ( |
| 1.1f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1))); |
| EXPECT_FLOAT_EQ( |
| 1.1f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2))); |
| EXPECT_FLOAT_EQ(1.f, |
| content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_B))); |
| |
| // Test per-tab automatic zoom settings. |
| EXPECT_TRUE(RunSetZoomSettings(tab_id_A1, "automatic", "per-tab")); |
| EXPECT_TRUE(RunSetZoom(tab_id_A1, 1.2f)); |
| EXPECT_FLOAT_EQ( |
| 1.2f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1))); |
| EXPECT_FLOAT_EQ( |
| 1.1f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2))); |
| |
| // Test 'manual' mode. |
| EXPECT_TRUE(RunSetZoomSettings(tab_id_A1, "manual", NULL)); |
| EXPECT_TRUE(RunSetZoom(tab_id_A1, 1.3f)); |
| EXPECT_FLOAT_EQ( |
| 1.3f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1))); |
| EXPECT_FLOAT_EQ( |
| 1.1f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2))); |
| |
| // Test 'disabled' mode, which will reset A1's zoom to 1.f. |
| EXPECT_TRUE(RunSetZoomSettings(tab_id_A1, "disabled", NULL)); |
| std::string error = RunSetZoomExpectError(tab_id_A1, 1.4f); |
| EXPECT_TRUE(MatchPattern(error, keys::kCannotZoomDisabledTabError)); |
| EXPECT_FLOAT_EQ( |
| 1.f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1))); |
| // We should still be able to zoom A2 though. |
| EXPECT_TRUE(RunSetZoom(tab_id_A2, 1.4f)); |
| EXPECT_FLOAT_EQ( |
| 1.4f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2))); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest, GetZoomSettings) { |
| content::OpenURLParams params(GetOpenParams(url::kAboutBlankURL)); |
| content::WebContents* web_contents = OpenUrlAndWaitForLoad(params.url); |
| int tab_id = ExtensionTabUtil::GetTabId(web_contents); |
| |
| std::string mode; |
| std::string scope; |
| |
| EXPECT_TRUE(RunGetZoomSettings(tab_id, &mode, &scope)); |
| EXPECT_EQ("automatic", mode); |
| EXPECT_EQ("per-origin", scope); |
| |
| EXPECT_TRUE(RunSetZoomSettings(tab_id, "automatic", "per-tab")); |
| EXPECT_TRUE(RunGetZoomSettings(tab_id, &mode, &scope)); |
| |
| EXPECT_EQ("automatic", mode); |
| EXPECT_EQ("per-tab", scope); |
| |
| std::string error = |
| RunSetZoomSettingsExpectError(tab_id, "manual", "per-origin"); |
| EXPECT_TRUE(MatchPattern(error, |
| keys::kPerOriginOnlyInAutomaticError)); |
| error = |
| RunSetZoomSettingsExpectError(tab_id, "disabled", "per-origin"); |
| EXPECT_TRUE(MatchPattern(error, |
| keys::kPerOriginOnlyInAutomaticError)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest, CannotZoomInvalidTab) { |
| content::OpenURLParams params(GetOpenParams(url::kAboutBlankURL)); |
| content::WebContents* web_contents = OpenUrlAndWaitForLoad(params.url); |
| int tab_id = ExtensionTabUtil::GetTabId(web_contents); |
| |
| int bogus_id = tab_id + 100; |
| std::string error = RunSetZoomExpectError(bogus_id, 3.14159); |
| EXPECT_TRUE(MatchPattern(error, keys::kTabNotFoundError)); |
| |
| error = RunSetZoomSettingsExpectError(bogus_id, "manual", "per-tab"); |
| EXPECT_TRUE(MatchPattern(error, keys::kTabNotFoundError)); |
| |
| const char kNewTestTabArgs[] = "chrome://version"; |
| params = GetOpenParams(kNewTestTabArgs); |
| web_contents = browser()->OpenURL(params); |
| tab_id = ExtensionTabUtil::GetTabId(web_contents); |
| |
| // Test chrome.tabs.setZoom(). |
| error = RunSetZoomExpectError(tab_id, 3.14159); |
| EXPECT_TRUE(MatchPattern(error, manifest_errors::kCannotAccessChromeUrl)); |
| |
| // chrome.tabs.setZoomSettings(). |
| error = RunSetZoomSettingsExpectError(tab_id, "manual", "per-tab"); |
| EXPECT_TRUE(MatchPattern(error, manifest_errors::kCannotAccessChromeUrl)); |
| } |
| |
| } // namespace extensions |