1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/path_service.h"
6#include "base/run_loop.h"
7#include "base/strings/utf_string_conversions.h"
8#include "chrome/browser/extensions/extension_browsertest.h"
9#include "chrome/browser/profiles/profile.h"
10#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
11#include "chrome/browser/ui/app_list/app_list_service.h"
12#include "chrome/browser/ui/app_list/test/chrome_app_list_test_support.h"
13#include "chrome/browser/ui/browser.h"
14#include "chrome/browser/ui/browser_finder.h"
15#include "chrome/browser/ui/host_desktop.h"
16#include "chrome/common/chrome_paths.h"
17#include "chrome/test/base/in_process_browser_test.h"
18#include "ui/app_list/app_list_model.h"
19#include "ui/app_list/search_box_model.h"
20#include "ui/app_list/search_result.h"
21#include "ui/app_list/search_result_observer.h"
22#include "ui/base/models/list_model_observer.h"
23
24// Browser Test for AppListController that runs on all platforms supporting
25// app_list.
26typedef InProcessBrowserTest AppListControllerBrowserTest;
27
28// Test the CreateNewWindow function of the controller delegate.
29IN_PROC_BROWSER_TEST_F(AppListControllerBrowserTest, CreateNewWindow) {
30  const chrome::HostDesktopType desktop = chrome::GetActiveDesktop();
31  AppListService* service = test::GetAppListService();
32  AppListControllerDelegate* controller(service->GetControllerDelegate());
33  ASSERT_TRUE(controller);
34
35  EXPECT_EQ(1U, chrome::GetBrowserCount(browser()->profile(), desktop));
36  EXPECT_EQ(0U, chrome::GetBrowserCount(
37      browser()->profile()->GetOffTheRecordProfile(), desktop));
38
39  controller->CreateNewWindow(browser()->profile(), false);
40  EXPECT_EQ(2U, chrome::GetBrowserCount(browser()->profile(), desktop));
41
42  controller->CreateNewWindow(browser()->profile(), true);
43  EXPECT_EQ(1U, chrome::GetBrowserCount(
44      browser()->profile()->GetOffTheRecordProfile(), desktop));
45}
46
47// Browser Test for AppListController that observes search result changes.
48class AppListControllerSearchResultsBrowserTest
49    : public ExtensionBrowserTest,
50      public app_list::SearchResultObserver,
51      public ui::ListModelObserver {
52 public:
53  AppListControllerSearchResultsBrowserTest()
54      : observed_result_(NULL),
55        item_uninstall_count_(0),
56        observed_results_list_(NULL) {}
57
58  void WatchResultsLookingForItem(
59      app_list::AppListModel::SearchResults* search_results,
60      const std::string& extension_name) {
61    EXPECT_FALSE(observed_results_list_);
62    observed_results_list_ = search_results;
63    observed_results_list_->AddObserver(this);
64    item_to_observe_ = base::ASCIIToUTF16(extension_name);
65  }
66
67  void StopWatchingResults() {
68    EXPECT_TRUE(observed_results_list_);
69    observed_results_list_->RemoveObserver(this);
70  }
71
72 protected:
73  void AttemptToLocateItem() {
74    if (observed_result_) {
75      observed_result_->RemoveObserver(this);
76      observed_result_ = NULL;
77    }
78
79    for (size_t i = 0; i < observed_results_list_->item_count(); ++i) {
80      if (observed_results_list_->GetItemAt(i)->title() != item_to_observe_)
81        continue;
82
83      // Ensure there is at most one.
84      EXPECT_FALSE(observed_result_);
85      observed_result_ = observed_results_list_->GetItemAt(i);
86    }
87
88    if (observed_result_)
89      observed_result_->AddObserver(this);
90  }
91
92  // Overridden from SearchResultObserver:
93  virtual void OnIconChanged() OVERRIDE {}
94  virtual void OnActionsChanged() OVERRIDE {}
95  virtual void OnIsInstallingChanged() OVERRIDE {}
96  virtual void OnPercentDownloadedChanged() OVERRIDE {}
97  virtual void OnItemInstalled() OVERRIDE {}
98  virtual void OnItemUninstalled() OVERRIDE {
99    ++item_uninstall_count_;
100    EXPECT_TRUE(observed_result_);
101  }
102
103  // Overridden from ui::ListModelObserver:
104  virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE {
105    AttemptToLocateItem();
106  }
107  virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE {
108    AttemptToLocateItem();
109  }
110  virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE {}
111  virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE {}
112
113  app_list::SearchResult* observed_result_;
114  int item_uninstall_count_;
115
116 private:
117  base::string16 item_to_observe_;
118  app_list::AppListModel::SearchResults* observed_results_list_;
119
120  DISALLOW_COPY_AND_ASSIGN(AppListControllerSearchResultsBrowserTest);
121};
122
123
124// Flaky on Mac. https://crbug.com/415264
125#if defined(OS_MACOSX)
126#define MAYBE_UninstallSearchResult DISABLED_UninstallSearchResult
127#else
128#define MAYBE_UninstallSearchResult UninstallSearchResult
129#endif
130// Test showing search results, and uninstalling one of them while displayed.
131IN_PROC_BROWSER_TEST_F(AppListControllerSearchResultsBrowserTest,
132                       MAYBE_UninstallSearchResult) {
133  base::FilePath test_extension_path;
134  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_extension_path));
135  test_extension_path = test_extension_path.AppendASCII("extensions")
136      .AppendASCII("platform_apps")
137      .AppendASCII("minimal");
138  const extensions::Extension* extension =
139      InstallExtension(test_extension_path,
140                       1 /* expected_change: new install */);
141  ASSERT_TRUE(extension);
142
143  AppListService* service = test::GetAppListService();
144  ASSERT_TRUE(service);
145  service->ShowForProfile(browser()->profile());
146
147  app_list::AppListModel* model = test::GetAppListModel(service);
148  ASSERT_TRUE(model);
149  WatchResultsLookingForItem(model->results(), extension->name());
150
151  // Ensure a search finds the extension.
152  EXPECT_FALSE(observed_result_);
153  model->search_box()->SetText(base::ASCIIToUTF16("minimal"));
154  EXPECT_TRUE(observed_result_);
155
156  // Ensure the UI is updated. This is via PostTask in views.
157  base::RunLoop().RunUntilIdle();
158
159  // Now uninstall and ensure this browser test observes it.
160  EXPECT_EQ(0, item_uninstall_count_);
161  UninstallExtension(extension->id());
162  EXPECT_EQ(1, item_uninstall_count_);
163
164  // Results should not be immediately refreshed. When they are, the item should
165  // be removed from the model.
166  EXPECT_TRUE(observed_result_);
167  base::RunLoop().RunUntilIdle();
168  EXPECT_FALSE(observed_result_);
169  StopWatchingResults();
170  service->DismissAppList();
171}
172