15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "apps/launcher.h"
62385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "apps/native_app_window.h"
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "apps/shell_window.h"
84311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch#include "apps/shell_window_registry.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
10a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/command_line.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/file_util.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/files/scoped_temp_dir.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/stl_util.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/test/test_timeouts.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/app/chrome_command_ids.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/automation/automation_util.h"
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/devtools/devtools_window.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/permissions/permissions_api.h"
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/extensions/component_loader.h"
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/extensions/event_names.h"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/extensions/event_router.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_browsertest.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_prefs.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_test_message_listener.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/platform_app_browsertest_util.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/tab_contents/render_view_context_menu.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/extensions/application_launch.h"
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
38a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "chrome/test/base/test_switches.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/base/ui_test_utils.h"
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "components/user_prefs/pref_registry_syncable.h"
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "components/web_modal/web_contents_modal_dialog_manager.h"
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/devtools_agent_host.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h"
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/render_widget_host_view.h"
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_contents_view.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/test/test_utils.h"
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/test/embedded_test_server/embedded_test_server.h"
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing apps::ShellWindow;
514311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdochusing apps::ShellWindowRegistry;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using web_modal::WebContentsModalDialogManager;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Non-abstract RenderViewContextMenu class.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PlatformAppContextMenu : public RenderViewContextMenu {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PlatformAppContextMenu(WebContents* web_contents,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const content::ContextMenuParams& params)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : RenderViewContextMenu(web_contents, params) {}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool HasCommandWithId(int command_id) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return menu_model_.GetIndexOfCommandId(command_id) != -1;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // RenderViewContextMenu implementation.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetAcceleratorForCommandId(
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int command_id,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::Accelerator* accelerator) OVERRIDE {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void PlatformInit() OVERRIDE {}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void PlatformCancel() OVERRIDE {}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class keeps track of tabs as they are added to the browser. It will be
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "done" (i.e. won't block on Wait()) once |observations| tabs have been added.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TabsAddedNotificationObserver
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public content::WindowedNotificationObserver {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit TabsAddedNotificationObserver(size_t observations)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : content::WindowedNotificationObserver(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            chrome::NOTIFICATION_TAB_ADDED,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            content::NotificationService::AllSources()),
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        observations_(observations) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Observe(int type,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const content::NotificationSource& source,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const content::NotificationDetails& details) OVERRIDE {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observed_tabs_.push_back(
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::Details<WebContents>(details).ptr());
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (observed_tabs_.size() == observations_)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::WindowedNotificationObserver::Observe(type, source, details);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::vector<content::WebContents*>& tabs() { return observed_tabs_; }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t observations_;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<content::WebContents*> observed_tabs_;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TabsAddedNotificationObserver);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool CopyTestDataAndSetCommandLineArg(
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::FilePath& test_data_file,
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::FilePath& temp_dir,
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const char* filename) {
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath path = temp_dir.AppendASCII(
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      filename).NormalizePathSeparators();
1177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!(base::CopyFile(test_data_file, path)))
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CommandLine* command_line = CommandLine::ForCurrentProcess();
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  command_line->AppendArgPath(path);
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kTestFilePath[] = "platform_apps/launch_files/test.txt";
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that CreateShellWindow doesn't crash if you close it straight away.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LauncherPlatformAppBrowserTest relies on this behaviour, but is only run for
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ash, so we test that it works here.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, CreateAndCloseShellWindow) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension = LoadAndLaunchPlatformApp("minimal");
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ShellWindow* window = CreateShellWindow(extension);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseShellWindow(window);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that platform apps received the "launch" event when launched.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OnLaunchedEvent) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch")) << message_;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that platform apps cannot use certain disabled window properties, but
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// can override them and then use them.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisabledWindowProperties) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/disabled_window_properties"))
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << message_;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, EmptyContextMenu) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionTestMessageListener launched_listener("Launched", false);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadAndLaunchPlatformApp("minimal");
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The empty app doesn't add any context menu items, so its menu should
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // only include the developer tools.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContents* web_contents = GetFirstShellWindowWebContents();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(web_contents);
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  content::ContextMenuParams params;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<PlatformAppContextMenu> menu;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu.reset(new PlatformAppContextMenu(web_contents, params));
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->Init();
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenu) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionTestMessageListener launched_listener("Launched", false);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadAndLaunchPlatformApp("context_menu");
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wait for the extension to tell us it's initialized its context menus and
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // launched a window.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The context_menu app has two context menu items. These, along with a
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // separator and the developer tools, is all that should be in the menu.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContents* web_contents = GetFirstShellWindowWebContents();
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(web_contents);
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  content::ContextMenuParams params;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<PlatformAppContextMenu> menu;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu.reset(new PlatformAppContextMenu(web_contents, params));
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->Init();
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + 1));
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, InstalledAppWithContextMenu) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionTestMessageListener launched_listener("Launched", false);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InstallAndLaunchPlatformApp("context_menu");
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wait for the extension to tell us it's initialized its context menus and
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // launched a window.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The context_menu app has two context menu items. For an installed app
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // these are all that should be in the menu.
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContents* web_contents = GetFirstShellWindowWebContents();
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(web_contents);
21190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  content::ContextMenuParams params;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<PlatformAppContextMenu> menu;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu.reset(new PlatformAppContextMenu(web_contents, params));
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->Init();
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + 1));
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuTextField) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionTestMessageListener launched_listener("Launched", false);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadAndLaunchPlatformApp("context_menu");
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wait for the extension to tell us it's initialized its context menus and
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // launched a window.
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The context_menu app has one context menu item. This, along with a
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // separator and the developer tools, is all that should be in the menu.
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContents* web_contents = GetFirstShellWindowWebContents();
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(web_contents);
23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  content::ContextMenuParams params;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.is_editable = true;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<PlatformAppContextMenu> menu;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu.reset(new PlatformAppContextMenu(web_contents, params));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->Init();
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuSelection) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionTestMessageListener launched_listener("Launched", false);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadAndLaunchPlatformApp("context_menu");
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wait for the extension to tell us it's initialized its context menus and
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // launched a window.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The context_menu app has one context menu item. This, along with a
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // separator and the developer tools, is all that should be in the menu.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContents* web_contents = GetFirstShellWindowWebContents();
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(web_contents);
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  content::ContextMenuParams params;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.selection_text = ASCIIToUTF16("Hello World");
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<PlatformAppContextMenu> menu;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu.reset(new PlatformAppContextMenu(web_contents, params));
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->Init();
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuClicked) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionTestMessageListener launched_listener("Launched", false);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadAndLaunchPlatformApp("context_menu_click");
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wait for the extension to tell us it's initialized its context menus and
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // launched a window.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test that the menu item shows up
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContents* web_contents = GetFirstShellWindowWebContents();
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(web_contents);
29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  content::ContextMenuParams params;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.page_url = GURL("http://foo.bar");
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<PlatformAppContextMenu> menu;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu.reset(new PlatformAppContextMenu(web_contents, params));
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->Init();
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Execute the menu item
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionTestMessageListener onclicked_listener("onClicked fired for id1",
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  false);
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  menu->ExecuteCommand(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST, 0);
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(onclicked_listener.WaitUntilSatisfied());
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowNavigation) {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TabsAddedNotificationObserver observer(2);
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ASSERT_TRUE(StartEmbeddedTestServer());
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/navigation")) << message_;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observer.Wait();
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(2U, observer.tabs().size());
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(std::string(chrome::kExtensionInvalidRequestURL),
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            observer.tabs()[0]->GetURL().spec());
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ("http://chromium.org/",
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            observer.tabs()[1]->GetURL().spec());
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Iframes) {
323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ASSERT_TRUE(StartEmbeddedTestServer());
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/iframes")) << message_;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that localStorage and WebSQL are disabled for platform apps.
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowStorage) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/storage")) << message_;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Restrictions) {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/restrictions")) << message_;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that platform apps can use the chrome.app.window.* API.
337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// It is flaky: http://crbug.com/223467
338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DISABLED_WindowsApi) {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/windows_api")) << message_;
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that extensions can't use platform-app-only APIs.
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, PlatformAppsOnly) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunExtensionTestIgnoreManifestWarnings(
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "platform_apps/apps_only")) << message_;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that platform apps have isolated storage by default.
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Isolation) {
350eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ASSERT_TRUE(StartEmbeddedTestServer());
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Load a (non-app) page under the "localhost" origin that sets a cookie.
353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  GURL set_cookie_url = embedded_test_server()->GetURL(
354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      "/extensions/platform_apps/isolation/set_cookie.html");
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL::Replacements replace_host;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string host_str("localhost");  // Must stay in scope with replace_host.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  replace_host.SetHostStr(host_str);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_cookie_url = set_cookie_url.ReplaceComponents(replace_host);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui_test_utils::NavigateToURLWithDisposition(
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser(), set_cookie_url,
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure the cookie is set.
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int cookie_size;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string cookie_value;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  automation_util::GetCookies(
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_cookie_url,
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      browser()->tab_strip_model()->GetWebContentsAt(0),
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &cookie_size,
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &cookie_value);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ("testCookie=1", cookie_value);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Let the platform app request the same URL, and make sure that it doesn't
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // see the cookie.
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/isolation")) << message_;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
379868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// See crbug.com/248441
380868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#if defined(OS_WIN)
381868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#define MAYBE_ExtensionWindowingApis DISABLED_ExtensionWindowingApis
382868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#else
383868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#define MAYBE_ExtensionWindowingApis ExtensionWindowingApis
384868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif
385868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
386868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_ExtensionWindowingApis) {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initially there should be just the one browser window visible to the
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // extensions API.
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension = LoadExtension(
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      test_data_dir_.AppendASCII("common/background_page"));
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And no shell windows.
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(0U, GetShellWindowCount());
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Launch a platform app that shows a window.
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionTestMessageListener launched_listener("Launched", false);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadAndLaunchPlatformApp("minimal");
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(1U, GetShellWindowCount());
40190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ShellWindowRegistry::ShellWindowList shell_windows =
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ShellWindowRegistry::Get(browser()->profile())->shell_windows();
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int shell_window_id = (*shell_windows.begin())->session_id().id();
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // But it's not visible to the extensions API, it still thinks there's just
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // one browser window.
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It can't look it up by ID either
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(RunGetWindowFunctionForExtension(shell_window_id, extension));
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The app can also only see one window (its own).
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(jeremya): add an extension function to get a shell window by ID, and
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to get a list of all the shell windows, so we can test this.
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Launch another platform app that also shows a window.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionTestMessageListener launched_listener2("Launched", false);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadAndLaunchPlatformApp("context_menu");
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(launched_listener2.WaitUntilSatisfied());
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There are two total shell windows, but each app can only see its own.
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(2U, GetShellWindowCount());
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(jeremya): as above, this requires more extension functions.
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ChromeOS does not support passing arguments on the command line, so the tests
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that rely on this functionality are disabled.
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_CHROMEOS)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that command line parameters get passed through to platform apps
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// via launchData correctly when launching with a file.
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(benwells/jeremya): tests need a way to specify a handler ID.
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFile) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetCommandLineArg(kTestFilePath);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file"))
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << message_;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that relative paths can be passed through to the platform app.
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This test doesn't use the normal test infrastructure as it needs to open
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the application differently to all other platform app tests, by setting
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the chrome::AppLaunchParams.current_directory field.
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithRelativeFile) {
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Setup the command line
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClearCommandLineArgs();
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine* command_line = CommandLine::ForCurrentProcess();
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath relative_test_doc =
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::FilePath::FromUTF8Unsafe(kTestFilePath);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  relative_test_doc = relative_test_doc.NormalizePathSeparators();
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_line->AppendArgPath(relative_test_doc);
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Load the extension
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResultCatcher catcher;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension = LoadExtension(
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      test_data_dir_.AppendASCII("platform_apps/launch_file"));
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(extension);
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run the test
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome::AppLaunchParams params(browser()->profile(), extension,
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 extension_misc::LAUNCH_NONE, NEW_WINDOW);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.command_line = CommandLine::ForCurrentProcess();
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.current_directory = test_data_dir_;
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome::OpenApplication(params);
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!catcher.GetNextResult()) {
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_ = catcher.message();
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(0);
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Tests that launch data is sent through if the file extension matches.
470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileExtension) {
471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetCommandLineArg(kTestFilePath);
472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_by_extension"))
473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      << message_;
474c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
475c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Tests that launch data is sent through if the file extension and MIME type
477c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// both match.
478c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       LaunchWithFileExtensionAndMimeType) {
480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetCommandLineArg(kTestFilePath);
481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest(
482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "platform_apps/launch_file_by_extension_and_type")) << message_;
483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Tests that launch data is sent through for a file with no extension if a
486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// handler accepts "".
487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileWithoutExtension) {
488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetCommandLineArg("platform_apps/launch_files/test");
489c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_with_no_extension"))
490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      << message_;
491c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
492c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
493c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if !defined(OS_WIN)
494c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Tests that launch data is sent through for a file with an empty extension if
495c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// a handler accepts "".
496c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileEmptyExtension) {
497c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ScopedTempDir temp_dir;
498c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
499c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ClearCommandLineArgs();
500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(CopyTestDataAndSetCommandLineArg(
501c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      test_data_dir_.AppendASCII(kTestFilePath),
502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      temp_dir.path(),
503c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "test."));
504c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_with_no_extension"))
505c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      << message_;
506c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
507c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
508c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Tests that launch data is sent through for a file with an empty extension if
509c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// a handler accepts *.
510c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       LaunchWithFileEmptyExtensionAcceptAny) {
512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ScopedTempDir temp_dir;
513c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
514c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ClearCommandLineArgs();
515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(CopyTestDataAndSetCommandLineArg(
516c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      test_data_dir_.AppendASCII(kTestFilePath),
517c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      temp_dir.path(),
518c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "test."));
519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest(
520c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "platform_apps/launch_file_with_any_extension")) << message_;
521c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
522c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
523c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Tests that launch data is sent through for a file with no extension if a
525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// handler accepts *.
526c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       LaunchWithFileWithoutExtensionAcceptAny) {
528c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetCommandLineArg("platform_apps/launch_files/test");
529c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest(
530c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "platform_apps/launch_file_with_any_extension")) << message_;
531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
533c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Tests that launch data is sent through for a file with an extension if a
534c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// handler accepts *.
535c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
536c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       LaunchWithFileAcceptAnyExtension) {
537c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetCommandLineArg(kTestFilePath);
538c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest(
539c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "platform_apps/launch_file_with_any_extension")) << message_;
540c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
541c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
542c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Tests that no launch data is sent through if the file has the wrong
543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// extension.
544c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongExtension) {
545c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetCommandLineArg(kTestFilePath);
546c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_extension"))
547c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      << message_;
548c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
549c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
550c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Tests that no launch data is sent through if the file has no extension but
551c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// the handler requires a specific extension.
552c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongEmptyExtension) {
553c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetCommandLineArg("platform_apps/launch_files/test");
554c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_extension"))
555c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      << message_;
556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
557c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that no launch data is sent through if the file is of the wrong MIME
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// type.
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongType) {
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetCommandLineArg(kTestFilePath);
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_type"))
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << message_;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that no launch data is sent through if the platform app does not
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// provide an intent.
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNoIntent) {
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetCommandLineArg(kTestFilePath);
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_no_intent"))
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << message_;
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
574c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Tests that launch data is sent through with the MIME type set to
575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// application/octet-stream if the file MIME type cannot be read.
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoType) {
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetCommandLineArg("platform_apps/launch_files/test.unknownextension");
578c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest(
579c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "platform_apps/launch_application_octet_stream")) << message_;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that no launch data is sent through if the file does not exist.
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoFile) {
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetCommandLineArg("platform_apps/launch_files/doesnotexist.txt");
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << message_;
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that no launch data is sent through if the argument is a directory.
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithDirectory) {
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetCommandLineArg("platform_apps/launch_files");
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << message_;
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that no launch data is sent through if there are no arguments passed
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on the command line
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNothing) {
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClearCommandLineArgs();
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_nothing"))
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << message_;
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test that platform apps can use the chrome.fileSystem.getDisplayPath
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// function to get the native file system path of a file they are launched with.
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, GetDisplayPath) {
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetCommandLineArg(kTestFilePath);
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/get_display_path"))
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << message_;
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(OS_CHROMEOS)
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OpenLink) {
615eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ASSERT_TRUE(StartEmbeddedTestServer());
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::WindowedNotificationObserver observer(
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::NOTIFICATION_TAB_ADDED,
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<content::WebContentsDelegate>(browser()));
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadAndLaunchPlatformApp("open_link");
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observer.Wait();
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(2, browser()->tab_strip_model()->count());
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MutationEventsDisabled) {
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/mutation_events")) << message_;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test that windows created with an id will remember and restore their
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// geometry when opening new windows.
6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Originally disabled due to flakiness (see http://crbug.com/155459)
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// but now because a regression breaks the test (http://crbug.com/160343).
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(TOOLKIT_GTK)
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAYBE_ShellWindowRestorePosition DISABLED_ShellWindowRestorePosition
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define MAYBE_ShellWindowRestorePosition ShellWindowRestorePosition
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       MAYBE_ShellWindowRestorePosition) {
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/geometry"));
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
642b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// This appears to be unreliable on linux.
643b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// TODO(stevenjb): Investigate and enable
644b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#if defined(OS_LINUX) && !defined(USE_ASH)
645b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#define MAYBE_ShellWindowRestoreState DISABLED_ShellWindowRestoreState
646b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#else
647b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#define MAYBE_ShellWindowRestoreState ShellWindowRestoreState
648b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#endif
649b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
650b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                       MAYBE_ShellWindowRestoreState) {
651b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  ASSERT_TRUE(RunPlatformAppTest("platform_apps/restore_state"));
652b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
653b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
654eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochIN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
655eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                       ShellWindowAdjustBoundsToBeVisibleOnScreen) {
656eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const Extension* extension = LoadAndLaunchPlatformApp("minimal");
657eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ShellWindow* window = CreateShellWindow(extension);
658eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
659eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // The screen bounds didn't change, the cached bounds didn't need to adjust.
660eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Rect cached_bounds(80, 100, 400, 400);
661eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Rect cached_screen_bounds(0, 0, 1600, 900);
662eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Rect current_screen_bounds(0, 0, 1600, 900);
663eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Size minimum_size(200, 200);
664eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Rect bounds;
665eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(window,
666eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    cached_bounds,
667eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    cached_screen_bounds,
668eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    current_screen_bounds,
669eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    minimum_size,
670eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    &bounds);
671eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(bounds, cached_bounds);
672eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
673eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // We have an empty screen bounds, the cached bounds didn't need to adjust.
674eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Rect empty_screen_bounds;
675eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(window,
676eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    cached_bounds,
677eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    empty_screen_bounds,
678eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    current_screen_bounds,
679eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    minimum_size,
680eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    &bounds);
681eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(bounds, cached_bounds);
682eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
683eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Cached bounds is completely off the new screen bounds in horizontal
684eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // locations. Expect to reposition the bounds.
685eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Rect horizontal_out_of_screen_bounds(-800, 100, 400, 400);
686eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
687eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      window,
688eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      horizontal_out_of_screen_bounds,
689eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      gfx::Rect(-1366, 0, 1600, 900),
690eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      current_screen_bounds,
691eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      minimum_size,
692eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      &bounds);
693eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(bounds, gfx::Rect(0, 100, 400, 400));
694eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
695eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Cached bounds is completely off the new screen bounds in vertical
696eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // locations. Expect to reposition the bounds.
697eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Rect vertical_out_of_screen_bounds(10, 1000, 400, 400);
698eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
699eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      window,
700eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      vertical_out_of_screen_bounds,
701eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      gfx::Rect(-1366, 0, 1600, 900),
702eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      current_screen_bounds,
703eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      minimum_size,
704eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      &bounds);
705eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(bounds, gfx::Rect(10, 500, 400, 400));
706eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
707eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // From a large screen resulotion to a small one. Expect it fit on screen.
708eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Rect big_cache_bounds(10, 10, 1000, 1000);
709eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
710eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      window,
711eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      big_cache_bounds,
712eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      gfx::Rect(0, 0, 1600, 1000),
713eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      gfx::Rect(0, 0, 800, 600),
714eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      minimum_size,
715eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      &bounds);
716eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(bounds, gfx::Rect(0, 0, 800, 600));
717eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
718eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Don't resize the bounds smaller than minimum size, when the minimum size is
719eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // larger than the screen.
720eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
721eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      window,
722eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      big_cache_bounds,
723eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      gfx::Rect(0, 0, 1600, 1000),
724eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      gfx::Rect(0, 0, 800, 600),
725eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      gfx::Size(900, 900),
726eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      &bounds);
727eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(bounds, gfx::Rect(0, 0, 900, 900));
728eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
729eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PlatformAppDevToolsBrowserTest : public PlatformAppBrowserTest {
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum TestFlags {
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RELAUNCH = 0x1,
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HAS_ID = 0x2,
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Runs a test inside a harness that opens DevTools on a shell window.
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RunTestWithDevTools(const char* name, int test_flags);
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PlatformAppDevToolsBrowserTest::RunTestWithDevTools(
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* name, int test_flags) {
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using content::DevToolsAgentHost;
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionTestMessageListener launched_listener("Launched", false);
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension = LoadAndLaunchPlatformApp(name);
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(extension);
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ShellWindow* window = GetFirstShellWindow();
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(window);
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(window->window_key().empty(), (test_flags & HAS_ID) == 0);
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::RenderViewHost* rvh = window->web_contents()->GetRenderViewHost();
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(rvh);
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ensure no DevTools open for the ShellWindow, then open one.
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(DevToolsAgentHost::HasFor(rvh));
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DevToolsWindow* devtools_window = DevToolsWindow::OpenDevToolsWindow(rvh);
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::WindowedNotificationObserver loaded_observer(
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::NOTIFICATION_LOAD_STOP,
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<content::NavigationController>(
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &devtools_window->web_contents()->GetController()));
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  loaded_observer.Wait();
7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(DevToolsAgentHost::HasFor(rvh));
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (test_flags & RELAUNCH) {
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Close the ShellWindow, and ensure it is gone.
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseShellWindow(window);
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_FALSE(GetFirstShellWindow());
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Relaunch the app and get a new ShellWindow.
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::WindowedNotificationObserver app_loaded_observer(
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::NotificationService::AllSources());
7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                    extension,
7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                    extension_misc::LAUNCH_NONE,
7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                    NEW_WINDOW));
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    app_loaded_observer.Wait();
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window = GetFirstShellWindow();
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(window);
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // DevTools should have reopened with the relaunch.
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rvh = window->web_contents()->GetRenderViewHost();
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(rvh);
7852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(DevToolsAgentHost::HasFor(rvh));
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
791868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// http://crbug.com/246634
792868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#if defined(OS_CHROMEOS)
793868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#define MAYBE_ReOpenedWithID DISABLED_ReOpenedWithID
794868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#else
795868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#define MAYBE_ReOpenedWithID ReOpenedWithID
796868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif
797868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppDevToolsBrowserTest, MAYBE_ReOpenedWithID) {
798ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if defined(OS_WIN) && defined(USE_ASH)
799a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
800a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
801ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
802ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunTestWithDevTools("minimal_id", RELAUNCH | HAS_ID);
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
806868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// http://crbug.com/246999
8077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#if defined(OS_CHROMEOS) || defined(OS_WIN)
808868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#define MAYBE_ReOpenedWithURL DISABLED_ReOpenedWithURL
809868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#else
810868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#define MAYBE_ReOpenedWithURL ReOpenedWithURL
811868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif
812868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppDevToolsBrowserTest, MAYBE_ReOpenedWithURL) {
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunTestWithDevTools("minimal", RELAUNCH);
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test that showing a permission request as a constrained window works and is
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// correctly parented.
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAYBE_ConstrainedWindowRequest DISABLED_ConstrainedWindowRequest
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(sail): Enable this on other platforms once http://crbug.com/95455 is
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// fixed.
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAYBE_ConstrainedWindowRequest DISABLED_ConstrainedWindowRequest
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_ConstrainedWindowRequest) {
8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension =
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LoadAndLaunchPlatformApp("optional_permission_request");
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(extension) << "Failed to load extension.";
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContents* web_contents = GetFirstShellWindowWebContents();
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(web_contents);
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Verify that the shell window has a dialog attached.
8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebContentsModalDialogManager* web_contents_modal_dialog_manager =
8372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      WebContentsModalDialogManager::FromWebContents(web_contents);
8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(web_contents_modal_dialog_manager->IsShowingDialog());
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close the constrained window and wait for the reply to the permission
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // request.
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionTestMessageListener listener("PermissionRequestDone", false);
8432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebContentsModalDialogManager::TestApi test_api(
8442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      web_contents_modal_dialog_manager);
8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  test_api.CloseAllDialogs();
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(listener.WaitUntilSatisfied());
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests that an app calling chrome.runtime.reload will reload the app and
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// relaunch it if it was running.
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ReloadRelaunches) {
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionTestMessageListener launched_listener("Launched", true);
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension = LoadAndLaunchPlatformApp("reload");
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(extension);
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(GetFirstShellWindow());
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now tell the app to reload itself
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionTestMessageListener launched_listener2("Launched", false);
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  launched_listener.Reply("reload");
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(launched_listener2.WaitUntilSatisfied());
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(GetFirstShellWindow());
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
8662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Simple observer to check for NOTIFICATION_EXTENSION_INSTALLED events to
8682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ensure installation does or does not occur in certain scenarios.
8692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class CheckExtensionInstalledObserver : public content::NotificationObserver {
8702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
8712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckExtensionInstalledObserver() : seen_(false) {
8722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    registrar_.Add(this,
8732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   chrome::NOTIFICATION_EXTENSION_INSTALLED,
8742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   content::NotificationService::AllSources());
8752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool seen() const {
8782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return seen_;
8792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
8802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // NotificationObserver:
8822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void Observe(int type,
8832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       const content::NotificationSource& source,
8842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       const content::NotificationDetails& details) OVERRIDE {
8852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_FALSE(seen_);
8862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    seen_ = true;
8872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
8902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool seen_;
8912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::NotificationRegistrar registrar_;
8922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
8932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
8952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Component App Test 1 of 3: ensure that the initial load of a component
8972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// extension utilizing a background page (e.g. a v2 platform app) has its
8982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// background page run and is launchable. Waits for the Launched response from
8992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the script resource in the opened shell window.
9002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
9012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       PRE_PRE_ComponentAppBackgroundPage) {
9022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckExtensionInstalledObserver should_install;
9032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Ensure that we wait until the background page is run (to register the
9052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // OnLaunched listener) before trying to open the application. This is similar
9062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to LoadAndLaunchPlatformApp, but we want to load as a component extension.
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::WindowedNotificationObserver app_loaded_observer(
9082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
9092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content::NotificationService::AllSources());
9102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const Extension* extension = LoadExtensionAsComponent(
9122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
9132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(extension);
9142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  app_loaded_observer.Wait();
9162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(should_install.seen());
9172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionTestMessageListener launched_listener("Launched", false);
9192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
9202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  extension,
9212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  extension_misc::LAUNCH_NONE,
9222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  NEW_WINDOW));
9232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
9252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Component App Test 2 of 3: ensure an installed component app can be launched
9282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// on a subsequent browser start, without requiring any install/upgrade logic
9292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// to be run, then perform setup for step 3.
9302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
9312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       PRE_ComponentAppBackgroundPage) {
9322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Since the component app is now installed, re-adding it in the same profile
9342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // should not cause it to be re-installed. Instead, we wait for the OnLaunched
9352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // in a different observer (which would timeout if not the app was not
9362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // previously installed properly) and then check this observer to make sure it
9372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // never saw the NOTIFICATION_EXTENSION_INSTALLED event.
9382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckExtensionInstalledObserver should_not_install;
9392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const Extension* extension = LoadExtensionAsComponent(
9402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
9412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(extension);
9422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionTestMessageListener launched_listener("Launched", false);
9442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
9452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  extension,
9462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  extension_misc::LAUNCH_NONE,
9472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  NEW_WINDOW));
9482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
9502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(should_not_install.seen());
9512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Simulate a "downgrade" from version 2 in the test manifest.json to 1.
9532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionPrefs* extension_prefs =
9542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extensions::ExtensionSystem::Get(browser()->profile())->
9552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension_service()->extension_prefs();
9562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Clear the registered events to ensure they are updated.
95890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  extensions::ExtensionSystem::Get(browser()->profile())->event_router()->
95990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      SetRegisteredEvents(extension->id(), std::set<std::string>());
9602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
961ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DictionaryPrefUpdate update(extension_prefs->pref_service(),
962ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                              ExtensionPrefs::kExtensionsPref);
963ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DictionaryValue* dict = update.Get();
964ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  std::string key(extension->id());
965ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  key += ".manifest.version";
966ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  dict->SetString(key, "1");
9672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Component App Test 3 of 3: simulate a component extension upgrade that
9702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// re-adds the OnLaunched event, and allows the app to be launched.
9712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ComponentAppBackgroundPage) {
9722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckExtensionInstalledObserver should_install;
9732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Since we are forcing an upgrade, we need to wait for the load again.
9742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::WindowedNotificationObserver app_loaded_observer(
9752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
9762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content::NotificationService::AllSources());
9772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const Extension* extension = LoadExtensionAsComponent(
9792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
9802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(extension);
9812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  app_loaded_observer.Wait();
9822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(should_install.seen());
9832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionTestMessageListener launched_listener("Launched", false);
9852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
9862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  extension,
9872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  extension_misc::LAUNCH_NONE,
9882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  NEW_WINDOW));
9892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
9912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Flakes on Windows: http://crbug.com/171450
9942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN)
9952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define MAYBE_Messaging DISABLED_Messaging
9962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
9972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define MAYBE_Messaging Messaging
9982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
9992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_Messaging) {
10002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionApiTest::ResultCatcher result_catcher;
10012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LoadAndLaunchPlatformApp("messaging/app2");
10022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LoadAndLaunchPlatformApp("messaging/app1");
10032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(result_catcher.GetNextResult());
10042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(linux_aura) http://crbug.com/163931
10072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
10082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define MAYBE_WebContentsHasFocus DISABLED_WebContentsHasFocus
10092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
1010c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This test depends on focus and so needs to be in interactive_ui_tests.
1011c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// http://crbug.com/227041
1012c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#define MAYBE_WebContentsHasFocus DISABLED_WebContentsHasFocus
10132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
10142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_WebContentsHasFocus) {
10152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionTestMessageListener launched_listener("Launched", true);
10162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LoadAndLaunchPlatformApp("minimal");
10172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
10182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(1LU, GetShellWindowCount());
102090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ShellWindowRegistry::ShellWindowList shell_windows = ShellWindowRegistry::Get(
10212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      browser()->profile())->shell_windows();
10222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE((*shell_windows.begin())->web_contents()->
10232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetRenderWidgetHostView()->HasFocus());
10242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1026c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1027c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(OS_CHROMEOS)
1028c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1029c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class PlatformAppIncognitoBrowserTest : public PlatformAppBrowserTest,
1030c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        public ShellWindowRegistry::Observer {
1031c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
1032c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1033c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Tell chromeos to launch in Guest mode, aka incognito.
1034c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    command_line->AppendSwitch(switches::kIncognito);
1035c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    PlatformAppBrowserTest::SetUpCommandLine(command_line);
1036c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1037c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void SetUp() OVERRIDE {
1038c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Make sure the file manager actually gets loaded.
1039c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ComponentLoader::EnableBackgroundExtensionsForTesting();
1040c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    PlatformAppBrowserTest::SetUp();
1041c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1042c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1043c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // ShellWindowRegistry::Observer implementation.
1044b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  virtual void OnShellWindowAdded(ShellWindow* shell_window) OVERRIDE {
1045c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    opener_app_ids_.insert(shell_window->extension()->id());
1046c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1047b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  virtual void OnShellWindowIconChanged(ShellWindow* shell_window) OVERRIDE {}
1048b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  virtual void OnShellWindowRemoved(ShellWindow* shell_window) OVERRIDE {}
1049c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1050c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) protected:
1051c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // A set of ids of apps we've seen open a shell window.
1052c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::set<std::string> opener_app_ids_;
1053c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
1054c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1055c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(PlatformAppIncognitoBrowserTest, IncognitoComponentApp) {
1056c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Get the file manager app.
1057c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const Extension* file_manager = extension_service()->GetExtensionById(
1058c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "hhaomjibdihmijegdhdafkllkbggdgoj", false);
1059c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(file_manager != NULL);
1060c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Profile* incognito_profile = profile()->GetOffTheRecordProfile();
1061c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(incognito_profile != NULL);
1062c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1063c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Wait until the file manager has had a chance to register its listener
1064c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // for the launch event.
1065c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EventRouter* router = ExtensionSystem::Get(incognito_profile)->event_router();
1066c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(router != NULL);
1067c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  while (!router->ExtensionHasEventListener(file_manager->id(),
1068c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            event_names::kOnLaunched)) {
1069c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    content::RunAllPendingInMessageLoop();
1070c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1071c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1072c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Listen for new shell windows so we see the file manager app launch itself.
1073c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ShellWindowRegistry* registry = ShellWindowRegistry::Get(incognito_profile);
1074c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(registry != NULL);
1075c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  registry->AddObserver(this);
1076c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1077c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  chrome::AppLaunchParams params(incognito_profile, file_manager, 0);
1078c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  chrome::OpenApplication(params);
1079c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1080c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  while (!ContainsKey(opener_app_ids_, file_manager->id())) {
1081c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    content::RunAllPendingInMessageLoop();
1082c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1083c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1084c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1085c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif  // defined(OS_CHROMEOS)
1086c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1087c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
1089