1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/extension_apitest.h"
6#include "chrome/browser/extensions/extension_service.h"
7#include "chrome/browser/extensions/extension_web_ui.h"
8#include "chrome/browser/prefs/pref_service.h"
9#include "chrome/browser/prefs/scoped_user_pref_update.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/browser/ui/browser.h"
12#include "chrome/browser/ui/browser_list.h"
13#include "chrome/common/url_constants.h"
14#include "chrome/test/ui_test_utils.h"
15#include "content/browser/tab_contents/tab_contents.h"
16
17class ExtensionOverrideTest : public ExtensionApiTest {
18 protected:
19  bool CheckHistoryOverridesContainsNoDupes() {
20    // There should be no duplicate entries in the preferences.
21    const DictionaryValue* overrides =
22        browser()->profile()->GetPrefs()->GetDictionary(
23            ExtensionWebUI::kExtensionURLOverrides);
24
25    ListValue* values = NULL;
26    if (!overrides->GetList("history", &values))
27      return false;
28
29    std::set<std::string> seen_overrides;
30    for (size_t i = 0; i < values->GetSize(); ++i) {
31      std::string value;
32      if (!values->GetString(i, &value))
33        return false;
34
35      if (seen_overrides.find(value) != seen_overrides.end())
36        return false;
37
38      seen_overrides.insert(value);
39    }
40
41    return true;
42  }
43
44#if defined(TOUCH_UI)
45  // Navigate to the keyboard page, and ensure we have arrived at an
46  // extension URL.
47  void NavigateToKeyboard() {
48    ui_test_utils::NavigateToURL(browser(), GURL("chrome://keyboard/"));
49    TabContents* tab = browser()->GetSelectedTabContents();
50    ASSERT_TRUE(tab->controller().GetActiveEntry());
51    EXPECT_TRUE(tab->controller().GetActiveEntry()->url().
52                SchemeIs(chrome::kExtensionScheme));
53  }
54#endif
55};
56
57IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, OverrideNewtab) {
58  ASSERT_TRUE(RunExtensionTest("override/newtab")) << message_;
59  {
60    ResultCatcher catcher;
61    // Navigate to the new tab page.  The overridden new tab page
62    // will call chrome.test.notifyPass() .
63    ui_test_utils::NavigateToURL(browser(), GURL("chrome://newtab/"));
64    TabContents* tab = browser()->GetSelectedTabContents();
65    ASSERT_TRUE(tab->controller().GetActiveEntry());
66    EXPECT_TRUE(tab->controller().GetActiveEntry()->url().
67                SchemeIs(chrome::kExtensionScheme));
68
69    ASSERT_TRUE(catcher.GetNextResult());
70  }
71
72  // TODO(erikkay) Load a second extension with the same override.
73  // Verify behavior, then unload the first and verify behavior, etc.
74}
75
76#if defined(OS_MACOSX)
77// Hangy: http://crbug.com/70511
78#define MAYBE_OverrideNewtabIncognito DISABLED_OverrideNewtabIncognito
79#else
80#define MAYBE_OverrideNewtabIncognito OverrideNewtabIncognito
81#endif
82IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, MAYBE_OverrideNewtabIncognito) {
83  ASSERT_TRUE(RunExtensionTest("override/newtab")) << message_;
84
85  // Navigate an incognito tab to the new tab page.  We should get the actual
86  // new tab page because we can't load chrome-extension URLs in incognito.
87  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
88                                     GURL("chrome://newtab/"));
89  Browser* otr_browser = BrowserList::FindBrowserWithType(
90      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
91      false);
92  TabContents* tab = otr_browser->GetSelectedTabContents();
93  ASSERT_TRUE(tab->controller().GetActiveEntry());
94  EXPECT_FALSE(tab->controller().GetActiveEntry()->url().
95               SchemeIs(chrome::kExtensionScheme));
96}
97
98// Times out consistently on Win, http://crbug.com/45173.
99#if defined(OS_WIN)
100#define MAYBE_OverrideHistory DISABLED_OverrideHistory
101#else
102#define MAYBE_OverrideHistory OverrideHistory
103#endif  // defined(OS_WIN)
104
105IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, MAYBE_OverrideHistory) {
106  ASSERT_TRUE(RunExtensionTest("override/history")) << message_;
107  {
108    ResultCatcher catcher;
109    // Navigate to the history page.  The overridden history page
110    // will call chrome.test.notifyPass() .
111    ui_test_utils::NavigateToURL(browser(), GURL("chrome://history/"));
112    ASSERT_TRUE(catcher.GetNextResult());
113  }
114}
115
116// Regression test for http://crbug.com/41442.
117IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, ShouldNotCreateDuplicateEntries) {
118  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("override/history")));
119
120  // Simulate several LoadExtension() calls happening over the lifetime of
121  // a preferences file without corresponding UnloadExtension() calls.
122  for (size_t i = 0; i < 3; ++i) {
123    ExtensionWebUI::RegisterChromeURLOverrides(
124        browser()->profile(),
125        browser()->profile()->GetExtensionService()->extensions()->back()->
126            GetChromeURLOverrides());
127  }
128
129  ASSERT_TRUE(CheckHistoryOverridesContainsNoDupes());
130}
131
132IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, ShouldCleanUpDuplicateEntries) {
133  // Simulate several LoadExtension() calls happening over the lifetime of
134  // a preferences file without corresponding UnloadExtension() calls. This is
135  // the same as the above test, except for that it is testing the case where
136  // the file already contains dupes when an extension is loaded.
137  ListValue* list = new ListValue();
138  for (size_t i = 0; i < 3; ++i)
139    list->Append(Value::CreateStringValue("http://www.google.com/"));
140
141  {
142    DictionaryPrefUpdate update(browser()->profile()->GetPrefs(),
143                                ExtensionWebUI::kExtensionURLOverrides);
144    update.Get()->Set("history", list);
145  }
146
147  ASSERT_FALSE(CheckHistoryOverridesContainsNoDupes());
148
149  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("override/history")));
150
151  ASSERT_TRUE(CheckHistoryOverridesContainsNoDupes());
152}
153
154#if defined(TOUCH_UI)
155IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, OverrideKeyboard) {
156  ASSERT_TRUE(RunExtensionTest("override/keyboard")) << message_;
157  {
158    ResultCatcher catcher;
159    NavigateToKeyboard();
160    ASSERT_TRUE(catcher.GetNextResult());
161  }
162
163  // Load the failing version.  This should take precedence.
164  ASSERT_TRUE(LoadExtension(
165      test_data_dir_.AppendASCII("override").AppendASCII("keyboard_fails")));
166  {
167    ResultCatcher catcher;
168    NavigateToKeyboard();
169    ASSERT_FALSE(catcher.GetNextResult());
170  }
171
172  // Unload the failing version.  We should be back to passing now.
173  const ExtensionList *extensions =
174      browser()->profile()->GetExtensionService()->extensions();
175  UnloadExtension((*extensions->rbegin())->id());
176  {
177    ResultCatcher catcher;
178    NavigateToKeyboard();
179    ASSERT_TRUE(catcher.GetNextResult());
180  }
181}
182#endif
183