Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / tabs / tabs_test.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5
6 #include <string>
7
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/values.h"
14 #include "chrome/browser/extensions/api/tabs/tabs_api.h"
15 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
16 #include "chrome/browser/extensions/extension_function_test_utils.h"
17 #include "chrome/browser/extensions/extension_tab_util.h"
18 #include "chrome/browser/prefs/incognito_mode_prefs.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_commands.h"
22 #include "chrome/browser/ui/browser_window.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
24 #include "chrome/test/base/in_process_browser_test.h"
25 #include "chrome/test/base/ui_test_utils.h"
26 #include "content/public/common/page_zoom.h"
27 #include "content/public/common/url_constants.h"
28 #include "extensions/common/manifest_constants.h"
29 #include "extensions/common/test_util.h"
30 #include "net/test/spawned_test_server/spawned_test_server.h"
31 #include "ui/gfx/rect.h"
32
33 namespace extensions {
34
35 namespace keys = tabs_constants;
36 namespace utils = extension_function_test_utils;
37
38 namespace {
39
40 class ExtensionTabsTest : public InProcessBrowserTest {
41 };
42
43 }
44
45 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetWindow) {
46   int window_id = ExtensionTabUtil::GetWindowId(browser());
47
48   // Invalid window ID error.
49   scoped_refptr<WindowsGetFunction> function = new WindowsGetFunction();
50   scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
51   function->set_extension(extension.get());
52   EXPECT_TRUE(MatchPattern(
53       utils::RunFunctionAndReturnError(
54           function.get(),
55           base::StringPrintf("[%u]", window_id + 1),
56           browser()),
57       keys::kWindowNotFoundError));
58
59   // Basic window details.
60   gfx::Rect bounds;
61   if (browser()->window()->IsMinimized())
62     bounds = browser()->window()->GetRestoredBounds();
63   else
64     bounds = browser()->window()->GetBounds();
65
66   function = new WindowsGetFunction();
67   function->set_extension(extension.get());
68   scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
69       utils::RunFunctionAndReturnSingleResult(
70           function.get(),
71           base::StringPrintf("[%u]", window_id),
72           browser())));
73   EXPECT_EQ(window_id, utils::GetInteger(result.get(), "id"));
74   EXPECT_FALSE(utils::GetBoolean(result.get(), "incognito"));
75   EXPECT_EQ("normal", utils::GetString(result.get(), "type"));
76   EXPECT_EQ(bounds.x(), utils::GetInteger(result.get(), "left"));
77   EXPECT_EQ(bounds.y(), utils::GetInteger(result.get(), "top"));
78   EXPECT_EQ(bounds.width(), utils::GetInteger(result.get(), "width"));
79   EXPECT_EQ(bounds.height(), utils::GetInteger(result.get(), "height"));
80
81   // With "populate" enabled.
82   function = new WindowsGetFunction();
83   function->set_extension(extension.get());
84   result.reset(utils::ToDictionary(
85       utils::RunFunctionAndReturnSingleResult(
86           function.get(),
87           base::StringPrintf("[%u, {\"populate\": true}]", window_id),
88           browser())));
89
90   EXPECT_EQ(window_id, utils::GetInteger(result.get(), "id"));
91   // "populate" was enabled so tabs should be populated.
92   base::ListValue* tabs = NULL;
93   EXPECT_TRUE(result.get()->GetList(keys::kTabsKey, &tabs));
94
95   // TODO(aa): Can't assume window is focused. On mac, calling Activate() from a
96   // browser test doesn't seem to do anything, so can't test the opposite
97   // either.
98   EXPECT_EQ(browser()->window()->IsActive(),
99             utils::GetBoolean(result.get(), "focused"));
100
101   // TODO(aa): Minimized and maximized dimensions. Is there a way to set
102   // minimize/maximize programmatically?
103
104   // Popup.
105   Browser* popup_browser = new Browser(
106       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(),
107                             browser()->host_desktop_type()));
108   function = new WindowsGetFunction();
109   function->set_extension(extension.get());
110   result.reset(utils::ToDictionary(
111       utils::RunFunctionAndReturnSingleResult(
112           function.get(),
113           base::StringPrintf(
114               "[%u]", ExtensionTabUtil::GetWindowId(popup_browser)),
115           browser())));
116   EXPECT_EQ("popup", utils::GetString(result.get(), "type"));
117
118   // Incognito.
119   Browser* incognito_browser = CreateIncognitoBrowser();
120   int incognito_window_id = ExtensionTabUtil::GetWindowId(incognito_browser);
121
122   // Without "include_incognito".
123   function = new WindowsGetFunction();
124   function->set_extension(extension.get());
125   EXPECT_TRUE(MatchPattern(
126       utils::RunFunctionAndReturnError(
127           function.get(),
128           base::StringPrintf("[%u]", incognito_window_id),
129           browser()),
130       keys::kWindowNotFoundError));
131
132   // With "include_incognito".
133   function = new WindowsGetFunction();
134   function->set_extension(extension.get());
135   result.reset(utils::ToDictionary(
136       utils::RunFunctionAndReturnSingleResult(
137           function.get(),
138           base::StringPrintf("[%u]", incognito_window_id),
139           browser(),
140           utils::INCLUDE_INCOGNITO)));
141   EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito"));
142 }
143
144 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetCurrentWindow) {
145   int window_id = ExtensionTabUtil::GetWindowId(browser());
146   Browser* new_browser = CreateBrowser(browser()->profile());
147   int new_id = ExtensionTabUtil::GetWindowId(new_browser);
148
149   // Get the current window using new_browser.
150   scoped_refptr<WindowsGetCurrentFunction> function =
151       new WindowsGetCurrentFunction();
152   scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
153   function->set_extension(extension.get());
154   scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
155       utils::RunFunctionAndReturnSingleResult(function.get(),
156                                               "[]",
157                                               new_browser)));
158
159   // The id should match the window id of the browser instance that was passed
160   // to RunFunctionAndReturnSingleResult.
161   EXPECT_EQ(new_id, utils::GetInteger(result.get(), "id"));
162   base::ListValue* tabs = NULL;
163   EXPECT_FALSE(result.get()->GetList(keys::kTabsKey, &tabs));
164
165   // Get the current window using the old window and make the tabs populated.
166   function = new WindowsGetCurrentFunction();
167   function->set_extension(extension.get());
168   result.reset(utils::ToDictionary(
169       utils::RunFunctionAndReturnSingleResult(function.get(),
170                                               "[{\"populate\": true}]",
171                                               browser())));
172
173   // The id should match the window id of the browser instance that was passed
174   // to RunFunctionAndReturnSingleResult.
175   EXPECT_EQ(window_id, utils::GetInteger(result.get(), "id"));
176   // "populate" was enabled so tabs should be populated.
177   EXPECT_TRUE(result.get()->GetList(keys::kTabsKey, &tabs));
178 }
179
180 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetAllWindows) {
181   const size_t NUM_WINDOWS = 5;
182   std::set<int> window_ids;
183   std::set<int> result_ids;
184   window_ids.insert(ExtensionTabUtil::GetWindowId(browser()));
185
186   for (size_t i = 0; i < NUM_WINDOWS - 1; ++i) {
187     Browser* new_browser = CreateBrowser(browser()->profile());
188     window_ids.insert(ExtensionTabUtil::GetWindowId(new_browser));
189   }
190
191   scoped_refptr<WindowsGetAllFunction> function = new WindowsGetAllFunction();
192   scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
193   function->set_extension(extension.get());
194   scoped_ptr<base::ListValue> result(utils::ToList(
195       utils::RunFunctionAndReturnSingleResult(function.get(),
196                                               "[]",
197                                               browser())));
198
199   base::ListValue* windows = result.get();
200   EXPECT_EQ(NUM_WINDOWS, windows->GetSize());
201   for (size_t i = 0; i < NUM_WINDOWS; ++i) {
202     base::DictionaryValue* result_window = NULL;
203     EXPECT_TRUE(windows->GetDictionary(i, &result_window));
204     result_ids.insert(utils::GetInteger(result_window, "id"));
205
206     // "populate" was not passed in so tabs are not populated.
207     base::ListValue* tabs = NULL;
208     EXPECT_FALSE(result_window->GetList(keys::kTabsKey, &tabs));
209   }
210   // The returned ids should contain all the current browser instance ids.
211   EXPECT_EQ(window_ids, result_ids);
212
213   result_ids.clear();
214   function = new WindowsGetAllFunction();
215   function->set_extension(extension.get());
216   result.reset(utils::ToList(
217       utils::RunFunctionAndReturnSingleResult(function.get(),
218                                               "[{\"populate\": true}]",
219                                               browser())));
220
221   windows = result.get();
222   EXPECT_EQ(NUM_WINDOWS, windows->GetSize());
223   for (size_t i = 0; i < windows->GetSize(); ++i) {
224     base::DictionaryValue* result_window = NULL;
225     EXPECT_TRUE(windows->GetDictionary(i, &result_window));
226     result_ids.insert(utils::GetInteger(result_window, "id"));
227
228     // "populate" was enabled so tabs should be populated.
229     base::ListValue* tabs = NULL;
230     EXPECT_TRUE(result_window->GetList(keys::kTabsKey, &tabs));
231   }
232   // The returned ids should contain all the current browser instance ids.
233   EXPECT_EQ(window_ids, result_ids);
234 }
235
236 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, UpdateNoPermissions) {
237   // The test empty extension has no permissions, therefore it should not get
238   // tab data in the function result.
239   scoped_refptr<TabsUpdateFunction> update_tab_function(
240       new TabsUpdateFunction());
241   scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
242   update_tab_function->set_extension(empty_extension.get());
243   // Without a callback the function will not generate a result.
244   update_tab_function->set_has_callback(true);
245
246   scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
247       utils::RunFunctionAndReturnSingleResult(
248           update_tab_function.get(),
249           "[null, {\"url\": \"about:blank\", \"pinned\": true}]",
250           browser())));
251   // The url is stripped since the extension does not have tab permissions.
252   EXPECT_FALSE(result->HasKey("url"));
253   EXPECT_TRUE(utils::GetBoolean(result.get(), "pinned"));
254 }
255
256 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,
257                        DefaultToIncognitoWhenItIsForced) {
258   static const char kArgsWithoutExplicitIncognitoParam[] =
259       "[{\"url\": \"about:blank\"}]";
260   // Force Incognito mode.
261   IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
262                                       IncognitoModePrefs::FORCED);
263   // Run without an explicit "incognito" param.
264   scoped_refptr<WindowsCreateFunction> function(new WindowsCreateFunction());
265   scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
266   function->set_extension(extension.get());
267   scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
268       utils::RunFunctionAndReturnSingleResult(
269           function.get(),
270           kArgsWithoutExplicitIncognitoParam,
271           browser(),
272           utils::INCLUDE_INCOGNITO)));
273
274   // Make sure it is a new(different) window.
275   EXPECT_NE(ExtensionTabUtil::GetWindowId(browser()),
276             utils::GetInteger(result.get(), "id"));
277   // ... and it is incognito.
278   EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito"));
279
280   // Now try creating a window from incognito window.
281   Browser* incognito_browser = CreateIncognitoBrowser();
282   // Run without an explicit "incognito" param.
283   function = new WindowsCreateFunction();
284   function->set_extension(extension.get());
285   result.reset(utils::ToDictionary(
286       utils::RunFunctionAndReturnSingleResult(
287           function.get(),
288           kArgsWithoutExplicitIncognitoParam,
289           incognito_browser,
290           utils::INCLUDE_INCOGNITO)));
291   // Make sure it is a new(different) window.
292   EXPECT_NE(ExtensionTabUtil::GetWindowId(incognito_browser),
293             utils::GetInteger(result.get(), "id"));
294   // ... and it is incognito.
295   EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito"));
296 }
297
298 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,
299                        DefaultToIncognitoWhenItIsForcedAndNoArgs) {
300   static const char kEmptyArgs[] = "[]";
301   // Force Incognito mode.
302   IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
303                                       IncognitoModePrefs::FORCED);
304   // Run without an explicit "incognito" param.
305   scoped_refptr<WindowsCreateFunction> function = new WindowsCreateFunction();
306   scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
307   function->set_extension(extension.get());
308   scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
309       utils::RunFunctionAndReturnSingleResult(function.get(),
310                                               kEmptyArgs,
311                                               browser(),
312                                               utils::INCLUDE_INCOGNITO)));
313
314   // Make sure it is a new(different) window.
315   EXPECT_NE(ExtensionTabUtil::GetWindowId(browser()),
316             utils::GetInteger(result.get(), "id"));
317   // ... and it is incognito.
318   EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito"));
319
320   // Now try creating a window from incognito window.
321   Browser* incognito_browser = CreateIncognitoBrowser();
322   // Run without an explicit "incognito" param.
323   function = new WindowsCreateFunction();
324   function->set_extension(extension.get());
325   result.reset(utils::ToDictionary(
326       utils::RunFunctionAndReturnSingleResult(function.get(),
327                                               kEmptyArgs,
328                                               incognito_browser,
329                                               utils::INCLUDE_INCOGNITO)));
330   // Make sure it is a new(different) window.
331   EXPECT_NE(ExtensionTabUtil::GetWindowId(incognito_browser),
332             utils::GetInteger(result.get(), "id"));
333   // ... and it is incognito.
334   EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito"));
335 }
336
337 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,
338                        DontCreateNormalWindowWhenIncognitoForced) {
339   static const char kArgsWithExplicitIncognitoParam[] =
340       "[{\"url\": \"about:blank\", \"incognito\": false }]";
341   // Force Incognito mode.
342   IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
343                                       IncognitoModePrefs::FORCED);
344
345   // Run with an explicit "incognito" param.
346   scoped_refptr<WindowsCreateFunction> function = new WindowsCreateFunction();
347   scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
348   function->set_extension(extension.get());
349   EXPECT_TRUE(MatchPattern(
350       utils::RunFunctionAndReturnError(function.get(),
351                                        kArgsWithExplicitIncognitoParam,
352                                        browser()),
353       keys::kIncognitoModeIsForced));
354
355   // Now try opening a normal window from incognito window.
356   Browser* incognito_browser = CreateIncognitoBrowser();
357   // Run with an explicit "incognito" param.
358   function = new WindowsCreateFunction();
359   function->set_extension(extension.get());
360   EXPECT_TRUE(MatchPattern(
361       utils::RunFunctionAndReturnError(function.get(),
362                                        kArgsWithExplicitIncognitoParam,
363                                        incognito_browser),
364       keys::kIncognitoModeIsForced));
365 }
366
367 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,
368                        DontCreateIncognitoWindowWhenIncognitoDisabled) {
369   static const char kArgs[] =
370       "[{\"url\": \"about:blank\", \"incognito\": true }]";
371
372   Browser* incognito_browser = CreateIncognitoBrowser();
373   // Disable Incognito mode.
374   IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
375                                       IncognitoModePrefs::DISABLED);
376   // Run in normal window.
377   scoped_refptr<WindowsCreateFunction> function = new WindowsCreateFunction();
378   scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
379   function->set_extension(extension.get());
380   EXPECT_TRUE(MatchPattern(
381       utils::RunFunctionAndReturnError(function.get(),
382                                        kArgs,
383                                        browser()),
384       keys::kIncognitoModeIsDisabled));
385
386   // Run in incognito window.
387   function = new WindowsCreateFunction();
388   function->set_extension(extension.get());
389   EXPECT_TRUE(MatchPattern(
390       utils::RunFunctionAndReturnError(function.get(),
391                                        kArgs,
392                                        incognito_browser),
393       keys::kIncognitoModeIsDisabled));
394 }
395
396 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, QueryCurrentWindowTabs) {
397   const size_t kExtraWindows = 3;
398   for (size_t i = 0; i < kExtraWindows; ++i)
399     CreateBrowser(browser()->profile());
400
401   GURL url(url::kAboutBlankURL);
402   AddTabAtIndexToBrowser(browser(), 0, url, ui::PAGE_TRANSITION_LINK);
403   int window_id = ExtensionTabUtil::GetWindowId(browser());
404
405   // Get tabs in the 'current' window called from non-focused browser.
406   scoped_refptr<TabsQueryFunction> function = new TabsQueryFunction();
407   function->set_extension(test_util::CreateEmptyExtension().get());
408   scoped_ptr<base::ListValue> result(utils::ToList(
409       utils::RunFunctionAndReturnSingleResult(function.get(),
410                                               "[{\"currentWindow\":true}]",
411                                               browser())));
412
413   base::ListValue* result_tabs = result.get();
414   // We should have one initial tab and one added tab.
415   EXPECT_EQ(2u, result_tabs->GetSize());
416   for (size_t i = 0; i < result_tabs->GetSize(); ++i) {
417     base::DictionaryValue* result_tab = NULL;
418     EXPECT_TRUE(result_tabs->GetDictionary(i, &result_tab));
419     EXPECT_EQ(window_id, utils::GetInteger(result_tab, keys::kWindowIdKey));
420   }
421
422   // Get tabs NOT in the 'current' window called from non-focused browser.
423   function = new TabsQueryFunction();
424   function->set_extension(test_util::CreateEmptyExtension().get());
425   result.reset(utils::ToList(
426       utils::RunFunctionAndReturnSingleResult(function.get(),
427                                               "[{\"currentWindow\":false}]",
428                                               browser())));
429
430   result_tabs = result.get();
431   // We should have one tab for each extra window.
432   EXPECT_EQ(kExtraWindows, result_tabs->GetSize());
433   for (size_t i = 0; i < kExtraWindows; ++i) {
434     base::DictionaryValue* result_tab = NULL;
435     EXPECT_TRUE(result_tabs->GetDictionary(i, &result_tab));
436     EXPECT_NE(window_id, utils::GetInteger(result_tab, keys::kWindowIdKey));
437   }
438 }
439
440 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DontCreateTabInClosingPopupWindow) {
441   // Test creates new popup window, closes it right away and then tries to open
442   // a new tab in it. Tab should not be opened in the popup window, but in a
443   // tabbed browser window.
444   Browser* popup_browser = new Browser(
445       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(),
446                             browser()->host_desktop_type()));
447   int window_id = ExtensionTabUtil::GetWindowId(popup_browser);
448   chrome::CloseWindow(popup_browser);
449
450   scoped_refptr<TabsCreateFunction> create_tab_function(
451       new TabsCreateFunction());
452   create_tab_function->set_extension(test_util::CreateEmptyExtension().get());
453   // Without a callback the function will not generate a result.
454   create_tab_function->set_has_callback(true);
455
456   static const char kNewBlankTabArgs[] =
457       "[{\"url\": \"about:blank\", \"windowId\": %u}]";
458
459   scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
460       utils::RunFunctionAndReturnSingleResult(
461           create_tab_function.get(),
462           base::StringPrintf(kNewBlankTabArgs, window_id),
463           browser())));
464
465   EXPECT_NE(window_id, utils::GetInteger(result.get(), "windowId"));
466 }
467
468 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, InvalidUpdateWindowState) {
469   int window_id = ExtensionTabUtil::GetWindowId(browser());
470
471   static const char kArgsMinimizedWithFocus[] =
472       "[%u, {\"state\": \"minimized\", \"focused\": true}]";
473   scoped_refptr<WindowsUpdateFunction> function = new WindowsUpdateFunction();
474   scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
475   function->set_extension(extension.get());
476   EXPECT_TRUE(MatchPattern(
477       utils::RunFunctionAndReturnError(
478           function.get(),
479           base::StringPrintf(kArgsMinimizedWithFocus, window_id),
480           browser()),
481       keys::kInvalidWindowStateError));
482
483   static const char kArgsMaximizedWithoutFocus[] =
484       "[%u, {\"state\": \"maximized\", \"focused\": false}]";
485   function = new WindowsUpdateFunction();
486   function->set_extension(extension.get());
487   EXPECT_TRUE(MatchPattern(
488       utils::RunFunctionAndReturnError(
489           function.get(),
490           base::StringPrintf(kArgsMaximizedWithoutFocus, window_id),
491           browser()),
492       keys::kInvalidWindowStateError));
493
494   static const char kArgsMinimizedWithBounds[] =
495       "[%u, {\"state\": \"minimized\", \"width\": 500}]";
496   function = new WindowsUpdateFunction();
497   function->set_extension(extension.get());
498   EXPECT_TRUE(MatchPattern(
499       utils::RunFunctionAndReturnError(
500           function.get(),
501           base::StringPrintf(kArgsMinimizedWithBounds, window_id),
502           browser()),
503       keys::kInvalidWindowStateError));
504
505   static const char kArgsMaximizedWithBounds[] =
506       "[%u, {\"state\": \"maximized\", \"width\": 500}]";
507   function = new WindowsUpdateFunction();
508   function->set_extension(extension.get());
509   EXPECT_TRUE(MatchPattern(
510       utils::RunFunctionAndReturnError(
511           function.get(),
512           base::StringPrintf(kArgsMaximizedWithBounds, window_id),
513           browser()),
514       keys::kInvalidWindowStateError));
515 }
516
517 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DuplicateTab) {
518   content::OpenURLParams params(GURL(url::kAboutBlankURL),
519                                 content::Referrer(),
520                                 NEW_FOREGROUND_TAB,
521                                 ui::PAGE_TRANSITION_LINK,
522                                 false);
523   content::WebContents* web_contents = browser()->OpenURL(params);
524   int tab_id = ExtensionTabUtil::GetTabId(web_contents);
525   int window_id = ExtensionTabUtil::GetWindowIdOfTab(web_contents);
526   int tab_index = -1;
527   TabStripModel* tab_strip;
528   ExtensionTabUtil::GetTabStripModel(web_contents, &tab_strip, &tab_index);
529
530   scoped_refptr<TabsDuplicateFunction> duplicate_tab_function(
531       new TabsDuplicateFunction());
532   scoped_ptr<base::DictionaryValue> test_extension_value(
533       utils::ParseDictionary(
534       "{\"name\": \"Test\", \"version\": \"1.0\", \"permissions\": [\"tabs\"]}"
535       ));
536   scoped_refptr<Extension> empty_tab_extension(
537       utils::CreateExtension(test_extension_value.get()));
538   duplicate_tab_function->set_extension(empty_tab_extension.get());
539   duplicate_tab_function->set_has_callback(true);
540
541   scoped_ptr<base::DictionaryValue> duplicate_result(utils::ToDictionary(
542       utils::RunFunctionAndReturnSingleResult(
543           duplicate_tab_function.get(), base::StringPrintf("[%u]", tab_id),
544           browser())));
545
546   int duplicate_tab_id = utils::GetInteger(duplicate_result.get(), "id");
547   int duplicate_tab_window_id = utils::GetInteger(duplicate_result.get(),
548                                                   "windowId");
549   int duplicate_tab_index = utils::GetInteger(duplicate_result.get(), "index");
550   EXPECT_EQ(base::Value::TYPE_DICTIONARY, duplicate_result->GetType());
551   // Duplicate tab id should be different from the original tab id.
552   EXPECT_NE(tab_id, duplicate_tab_id);
553   EXPECT_EQ(window_id, duplicate_tab_window_id);
554   EXPECT_EQ(tab_index + 1, duplicate_tab_index);
555   // The test empty tab extension has tabs permissions, therefore
556   // |duplicate_result| should contain url, title, and faviconUrl
557   // in the function result.
558   EXPECT_TRUE(utils::HasPrivacySensitiveFields(duplicate_result.get()));
559 }
560
561 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DuplicateTabNoPermission) {
562   content::OpenURLParams params(GURL(url::kAboutBlankURL),
563                                 content::Referrer(),
564                                 NEW_FOREGROUND_TAB,
565                                 ui::PAGE_TRANSITION_LINK,
566                                 false);
567   content::WebContents* web_contents = browser()->OpenURL(params);
568   int tab_id = ExtensionTabUtil::GetTabId(web_contents);
569   int window_id = ExtensionTabUtil::GetWindowIdOfTab(web_contents);
570   int tab_index = -1;
571   TabStripModel* tab_strip;
572   ExtensionTabUtil::GetTabStripModel(web_contents, &tab_strip, &tab_index);
573
574   scoped_refptr<TabsDuplicateFunction> duplicate_tab_function(
575       new TabsDuplicateFunction());
576   scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
577   duplicate_tab_function->set_extension(empty_extension.get());
578   duplicate_tab_function->set_has_callback(true);
579
580   scoped_ptr<base::DictionaryValue> duplicate_result(utils::ToDictionary(
581       utils::RunFunctionAndReturnSingleResult(
582           duplicate_tab_function.get(), base::StringPrintf("[%u]", tab_id),
583           browser())));
584
585   int duplicate_tab_id = utils::GetInteger(duplicate_result.get(), "id");
586   int duplicate_tab_window_id = utils::GetInteger(duplicate_result.get(),
587                                                   "windowId");
588   int duplicate_tab_index = utils::GetInteger(duplicate_result.get(), "index");
589   EXPECT_EQ(base::Value::TYPE_DICTIONARY, duplicate_result->GetType());
590   // Duplicate tab id should be different from the original tab id.
591   EXPECT_NE(tab_id, duplicate_tab_id);
592   EXPECT_EQ(window_id, duplicate_tab_window_id);
593   EXPECT_EQ(tab_index + 1, duplicate_tab_index);
594   // The test empty extension has no permissions, therefore |duplicate_result|
595   // should not contain url, title, and faviconUrl in the function result.
596   EXPECT_FALSE(utils::HasPrivacySensitiveFields(duplicate_result.get()));
597 }
598
599 // Tester class for the tabs.zoom* api functions.
600 class ExtensionTabsZoomTest : public ExtensionTabsTest {
601  public:
602   virtual void SetUpOnMainThread() OVERRIDE;
603
604   // Runs chrome.tabs.setZoom().
605   bool RunSetZoom(int tab_id, double zoom_factor);
606
607   // Runs chrome.tabs.getZoom().
608   testing::AssertionResult RunGetZoom(int tab_id, double* zoom_factor);
609
610   // Runs chrome.tabs.setZoomSettings().
611   bool RunSetZoomSettings(int tab_id, const char* mode, const char* scope);
612
613   // Runs chrome.tabs.getZoomSettings().
614   testing::AssertionResult RunGetZoomSettings(int tab_id,
615                                               std::string* mode,
616                                               std::string* scope);
617
618   // Runs chrome.tabs.setZoom(), expecting an error.
619   std::string RunSetZoomExpectError(int tab_id,
620                                     double zoom_factor);
621
622   // Runs chrome.tabs.setZoomSettings(), expecting an error.
623   std::string RunSetZoomSettingsExpectError(int tab_id,
624                                             const char* mode,
625                                             const char* scope);
626
627   content::WebContents* OpenUrlAndWaitForLoad(const GURL& url);
628
629  private:
630   scoped_refptr<Extension> extension_;
631 };
632
633 void ExtensionTabsZoomTest::SetUpOnMainThread() {
634   ExtensionTabsTest::SetUpOnMainThread();
635   extension_ = test_util::CreateEmptyExtension();
636 }
637
638 bool ExtensionTabsZoomTest::RunSetZoom(int tab_id, double zoom_factor) {
639   scoped_refptr<TabsSetZoomFunction> set_zoom_function(
640       new TabsSetZoomFunction());
641   set_zoom_function->set_extension(extension_.get());
642   set_zoom_function->set_has_callback(true);
643
644   return utils::RunFunction(
645       set_zoom_function.get(),
646       base::StringPrintf("[%u, %lf]", tab_id, zoom_factor),
647       browser(),
648       extension_function_test_utils::NONE);
649 }
650
651 testing::AssertionResult ExtensionTabsZoomTest::RunGetZoom(
652     int tab_id,
653     double* zoom_factor) {
654   scoped_refptr<TabsGetZoomFunction> get_zoom_function(
655       new TabsGetZoomFunction());
656   get_zoom_function->set_extension(extension_.get());
657   get_zoom_function->set_has_callback(true);
658
659   scoped_ptr<base::Value> get_zoom_result(
660       utils::RunFunctionAndReturnSingleResult(
661           get_zoom_function.get(),
662           base::StringPrintf("[%u]", tab_id),
663           browser()));
664
665   if (!get_zoom_result)
666     return testing::AssertionFailure() << "no result";
667   if (!get_zoom_result->GetAsDouble(zoom_factor))
668     return testing::AssertionFailure() << "result was not a double";
669
670   return testing::AssertionSuccess();
671 }
672
673 bool ExtensionTabsZoomTest::RunSetZoomSettings(int tab_id,
674                                                const char* mode,
675                                                const char* scope) {
676   scoped_refptr<TabsSetZoomSettingsFunction> set_zoom_settings_function(
677       new TabsSetZoomSettingsFunction());
678   set_zoom_settings_function->set_extension(extension_.get());
679
680   std::string args;
681   if (scope) {
682     args = base::StringPrintf("[%u, {\"mode\": \"%s\", \"scope\": \"%s\"}]",
683                               tab_id, mode, scope);
684   } else {
685     args = base::StringPrintf("[%u, {\"mode\": \"%s\"}]", tab_id, mode);
686   }
687
688   return utils::RunFunction(set_zoom_settings_function.get(),
689                             args,
690                             browser(),
691                             extension_function_test_utils::NONE);
692 }
693
694 testing::AssertionResult ExtensionTabsZoomTest::RunGetZoomSettings(
695     int tab_id,
696     std::string* mode,
697     std::string* scope) {
698   DCHECK(mode);
699   DCHECK(scope);
700   scoped_refptr<TabsGetZoomSettingsFunction> get_zoom_settings_function(
701       new TabsGetZoomSettingsFunction());
702   get_zoom_settings_function->set_extension(extension_.get());
703   get_zoom_settings_function->set_has_callback(true);
704
705   scoped_ptr<base::DictionaryValue> get_zoom_settings_result(
706       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
707           get_zoom_settings_function.get(),
708           base::StringPrintf("[%u]", tab_id),
709           browser())));
710
711   if (!get_zoom_settings_result)
712     return testing::AssertionFailure() << "no result";
713
714   *mode = utils::GetString(get_zoom_settings_result.get(), "mode");
715   *scope = utils::GetString(get_zoom_settings_result.get(), "scope");
716
717   return testing::AssertionSuccess();
718 }
719
720 std::string ExtensionTabsZoomTest::RunSetZoomExpectError(int tab_id,
721                                                          double zoom_factor) {
722   scoped_refptr<TabsSetZoomFunction> set_zoom_function(
723       new TabsSetZoomFunction());
724   set_zoom_function->set_extension(extension_.get());
725   set_zoom_function->set_has_callback(true);
726
727   return utils::RunFunctionAndReturnError(
728       set_zoom_function.get(),
729       base::StringPrintf("[%u, %lf]", tab_id, zoom_factor),
730       browser());
731 }
732
733 std::string ExtensionTabsZoomTest::RunSetZoomSettingsExpectError(
734     int tab_id,
735     const char* mode,
736     const char* scope) {
737   scoped_refptr<TabsSetZoomSettingsFunction> set_zoom_settings_function(
738       new TabsSetZoomSettingsFunction());
739   set_zoom_settings_function->set_extension(extension_.get());
740
741   return utils::RunFunctionAndReturnError(set_zoom_settings_function.get(),
742                                           base::StringPrintf(
743                                               "[%u, {\"mode\": \"%s\", "
744                                               "\"scope\": \"%s\"}]",
745                                               tab_id,
746                                               mode,
747                                               scope),
748                                           browser());
749 }
750
751 content::WebContents* ExtensionTabsZoomTest::OpenUrlAndWaitForLoad(
752     const GURL& url) {
753   ui_test_utils::NavigateToURLWithDisposition(
754       browser(),
755       url,
756       NEW_FOREGROUND_TAB,
757       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
758   return  browser()->tab_strip_model()->GetActiveWebContents();
759 }
760
761 namespace {
762
763 double GetZoomLevel(const content::WebContents* web_contents) {
764   return ZoomController::FromWebContents(web_contents)->GetZoomLevel();
765 }
766
767 content::OpenURLParams GetOpenParams(const char* url) {
768   return content::OpenURLParams(GURL(url),
769                                 content::Referrer(),
770                                 NEW_FOREGROUND_TAB,
771                                 ui::PAGE_TRANSITION_LINK,
772                                 false);
773 }
774
775 }  // namespace
776
777 IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest, SetAndGetZoom) {
778   content::OpenURLParams params(GetOpenParams(url::kAboutBlankURL));
779   content::WebContents* web_contents = OpenUrlAndWaitForLoad(params.url);
780   int tab_id = ExtensionTabUtil::GetTabId(web_contents);
781
782   // Test default values before we set anything.
783   double zoom_factor = -1;
784   EXPECT_TRUE(RunGetZoom(tab_id, &zoom_factor));
785   EXPECT_EQ(1.0, zoom_factor);
786
787   // Test chrome.tabs.setZoom().
788   const double kZoomLevel = 0.8;
789   EXPECT_TRUE(RunSetZoom(tab_id, kZoomLevel));
790   EXPECT_EQ(kZoomLevel,
791             content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents)));
792
793   // Test chrome.tabs.getZoom().
794   zoom_factor = -1;
795   EXPECT_TRUE(RunGetZoom(tab_id, &zoom_factor));
796   EXPECT_EQ(kZoomLevel, zoom_factor);
797 }
798
799 IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest, ZoomSettings) {
800   // In this test we need two URLs that (1) represent real pages (i.e. they
801   // load without causing an error page load), (2) have different domains, and
802   // (3) are zoomable by the extension API (this last condition rules out
803   // chrome:// urls). We achieve this by noting that about:blank meets these
804   // requirements, allowing us to spin up a spawned http server on localhost to
805   // get the other domain.
806   net::SpawnedTestServer http_server(
807       net::SpawnedTestServer::TYPE_HTTP,
808       net::SpawnedTestServer::kLocalhost,
809       base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
810   ASSERT_TRUE(http_server.Start());
811
812   GURL url_A = http_server.GetURL("files/simple.html");
813   GURL url_B("about:blank");
814
815   // Tabs A1 and A2 are navigated to the same origin, while B is navigated
816   // to a different one.
817   content::WebContents* web_contents_A1 = OpenUrlAndWaitForLoad(url_A);
818   content::WebContents* web_contents_A2 = OpenUrlAndWaitForLoad(url_A);
819   content::WebContents* web_contents_B = OpenUrlAndWaitForLoad(url_B);
820
821   int tab_id_A1 = ExtensionTabUtil::GetTabId(web_contents_A1);
822   int tab_id_A2 = ExtensionTabUtil::GetTabId(web_contents_A2);
823   int tab_id_B = ExtensionTabUtil::GetTabId(web_contents_B);
824
825   ASSERT_FLOAT_EQ(
826       1.f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1)));
827   ASSERT_FLOAT_EQ(
828       1.f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2)));
829   ASSERT_FLOAT_EQ(
830       1.f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_B)));
831
832   // Test per-origin automatic zoom settings.
833   EXPECT_TRUE(RunSetZoom(tab_id_B, 1.f));
834   EXPECT_TRUE(RunSetZoom(tab_id_A2, 1.1f));
835   EXPECT_FLOAT_EQ(
836       1.1f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1)));
837   EXPECT_FLOAT_EQ(
838       1.1f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2)));
839   EXPECT_FLOAT_EQ(1.f,
840                   content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_B)));
841
842   // Test per-tab automatic zoom settings.
843   EXPECT_TRUE(RunSetZoomSettings(tab_id_A1, "automatic", "per-tab"));
844   EXPECT_TRUE(RunSetZoom(tab_id_A1, 1.2f));
845   EXPECT_FLOAT_EQ(
846       1.2f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1)));
847   EXPECT_FLOAT_EQ(
848       1.1f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2)));
849
850   // Test 'manual' mode.
851   EXPECT_TRUE(RunSetZoomSettings(tab_id_A1, "manual", NULL));
852   EXPECT_TRUE(RunSetZoom(tab_id_A1, 1.3f));
853   EXPECT_FLOAT_EQ(
854       1.3f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1)));
855   EXPECT_FLOAT_EQ(
856       1.1f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2)));
857
858   // Test 'disabled' mode, which will reset A1's zoom to 1.f.
859   EXPECT_TRUE(RunSetZoomSettings(tab_id_A1, "disabled", NULL));
860   std::string error = RunSetZoomExpectError(tab_id_A1, 1.4f);
861   EXPECT_TRUE(MatchPattern(error, keys::kCannotZoomDisabledTabError));
862   EXPECT_FLOAT_EQ(
863       1.f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1)));
864   // We should still be able to zoom A2 though.
865   EXPECT_TRUE(RunSetZoom(tab_id_A2, 1.4f));
866   EXPECT_FLOAT_EQ(
867       1.4f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2)));
868 }
869
870 IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest, GetZoomSettings) {
871   content::OpenURLParams params(GetOpenParams(url::kAboutBlankURL));
872   content::WebContents* web_contents = OpenUrlAndWaitForLoad(params.url);
873   int tab_id = ExtensionTabUtil::GetTabId(web_contents);
874
875   std::string mode;
876   std::string scope;
877
878   EXPECT_TRUE(RunGetZoomSettings(tab_id, &mode, &scope));
879   EXPECT_EQ("automatic", mode);
880   EXPECT_EQ("per-origin", scope);
881
882   EXPECT_TRUE(RunSetZoomSettings(tab_id, "automatic", "per-tab"));
883   EXPECT_TRUE(RunGetZoomSettings(tab_id, &mode, &scope));
884
885   EXPECT_EQ("automatic", mode);
886   EXPECT_EQ("per-tab", scope);
887
888   std::string error =
889       RunSetZoomSettingsExpectError(tab_id, "manual", "per-origin");
890   EXPECT_TRUE(MatchPattern(error,
891                            keys::kPerOriginOnlyInAutomaticError));
892   error =
893       RunSetZoomSettingsExpectError(tab_id, "disabled", "per-origin");
894   EXPECT_TRUE(MatchPattern(error,
895                            keys::kPerOriginOnlyInAutomaticError));
896 }
897
898 IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest, CannotZoomInvalidTab) {
899   content::OpenURLParams params(GetOpenParams(url::kAboutBlankURL));
900   content::WebContents* web_contents = OpenUrlAndWaitForLoad(params.url);
901   int tab_id = ExtensionTabUtil::GetTabId(web_contents);
902
903   int bogus_id = tab_id + 100;
904   std::string error = RunSetZoomExpectError(bogus_id, 3.14159);
905   EXPECT_TRUE(MatchPattern(error, keys::kTabNotFoundError));
906
907   error = RunSetZoomSettingsExpectError(bogus_id, "manual", "per-tab");
908   EXPECT_TRUE(MatchPattern(error, keys::kTabNotFoundError));
909
910   const char kNewTestTabArgs[] = "chrome://version";
911   params = GetOpenParams(kNewTestTabArgs);
912   web_contents = browser()->OpenURL(params);
913   tab_id = ExtensionTabUtil::GetTabId(web_contents);
914
915   // Test chrome.tabs.setZoom().
916   error = RunSetZoomExpectError(tab_id, 3.14159);
917   EXPECT_TRUE(MatchPattern(error, manifest_errors::kCannotAccessChromeUrl));
918
919   // chrome.tabs.setZoomSettings().
920   error = RunSetZoomSettingsExpectError(tab_id, "manual", "per-tab");
921   EXPECT_TRUE(MatchPattern(error, manifest_errors::kCannotAccessChromeUrl));
922 }
923
924 }  // namespace extensions