1// Copyright 2014 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 "ui/app_list/views/app_list_view.h"
6
7#include "base/command_line.h"
8#include "base/run_loop.h"
9#include "base/strings/string_util.h"
10#include "base/strings/utf_string_conversions.h"
11#include "testing/gtest/include/gtest/gtest.h"
12#include "ui/app_list/app_list_switches.h"
13#include "ui/app_list/pagination_model.h"
14#include "ui/app_list/search_box_model.h"
15#include "ui/app_list/test/app_list_test_model.h"
16#include "ui/app_list/test/app_list_test_view_delegate.h"
17#include "ui/app_list/views/app_list_folder_view.h"
18#include "ui/app_list/views/app_list_main_view.h"
19#include "ui/app_list/views/apps_container_view.h"
20#include "ui/app_list/views/apps_grid_view.h"
21#include "ui/app_list/views/contents_switcher_view.h"
22#include "ui/app_list/views/contents_view.h"
23#include "ui/app_list/views/search_box_view.h"
24#include "ui/app_list/views/search_result_list_view.h"
25#include "ui/app_list/views/start_page_view.h"
26#include "ui/app_list/views/test/apps_grid_view_test_api.h"
27#include "ui/app_list/views/tile_item_view.h"
28#include "ui/views/controls/textfield/textfield.h"
29#include "ui/views/test/views_test_base.h"
30#include "ui/views/views_delegate.h"
31#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
32
33namespace app_list {
34namespace test {
35
36namespace {
37
38enum TestType {
39  TEST_TYPE_START = 0,
40  NORMAL = TEST_TYPE_START,
41  LANDSCAPE,
42  EXPERIMENTAL,
43  TEST_TYPE_END,
44};
45
46bool IsViewAtOrigin(views::View* view) {
47  return view->bounds().origin().IsOrigin();
48}
49
50size_t GetVisibleTileItemViews(const std::vector<TileItemView*>& tiles) {
51  size_t count = 0;
52  for (std::vector<TileItemView*>::const_iterator it = tiles.begin();
53       it != tiles.end();
54       ++it) {
55    if ((*it)->visible())
56      count++;
57  }
58  return count;
59}
60
61// Choose a set that is 3 regular app list pages and 2 landscape app list pages.
62const int kInitialItems = 34;
63
64class TestTileSearchResult : public SearchResult {
65 public:
66  TestTileSearchResult() { set_display_type(DISPLAY_TILE); }
67  virtual ~TestTileSearchResult() {}
68
69 private:
70  DISALLOW_COPY_AND_ASSIGN(TestTileSearchResult);
71};
72
73// Allows the same tests to run with different contexts: either an Ash-style
74// root window or a desktop window tree host.
75class AppListViewTestContext {
76 public:
77  AppListViewTestContext(int test_type, gfx::NativeView parent);
78  ~AppListViewTestContext();
79
80  // Test displaying the app list and performs a standard set of checks on its
81  // top level views. Then closes the window.
82  void RunDisplayTest();
83
84  // Hides and reshows the app list with a folder open, expecting the main grid
85  // view to be shown.
86  void RunReshowWithOpenFolderTest();
87
88  // Tests displaying of the experimental app list and shows the start page.
89  void RunStartPageTest();
90
91  // Tests switching rapidly between multiple pages of the launcher.
92  void RunPageSwitchingAnimationTest();
93
94  // Tests changing the App List profile.
95  void RunProfileChangeTest();
96
97  // Tests displaying of the search results.
98  void RunSearchResultsTest();
99
100  // A standard set of checks on a view, e.g., ensuring it is drawn and visible.
101  static void CheckView(views::View* subview);
102
103  // Invoked when the Widget is closing, and the view it contains is about to
104  // be torn down. This only occurs in a run loop and will be used as a signal
105  // to quit.
106  void NativeWidgetClosing() {
107    view_ = NULL;
108    run_loop_->Quit();
109  }
110
111  // Whether the experimental "landscape" app launcher UI is being tested.
112  bool is_landscape() const {
113    return test_type_ == LANDSCAPE || test_type_ == EXPERIMENTAL;
114  }
115
116 private:
117  // Switches the active launcher page in the contents view and lays out to
118  // ensure all launcher pages are in the correct position.
119  void ShowContentsViewPageAndVerify(int index);
120
121  // Shows the app list and waits until a paint occurs.
122  void Show();
123
124  // Closes the app list. This sets |view_| to NULL.
125  void Close();
126
127  // Gets the PaginationModel owned by |view_|.
128  PaginationModel* GetPaginationModel();
129
130  const TestType test_type_;
131  scoped_ptr<base::RunLoop> run_loop_;
132  app_list::AppListView* view_;  // Owned by native widget.
133  scoped_ptr<app_list::test::AppListTestViewDelegate> delegate_;
134
135  DISALLOW_COPY_AND_ASSIGN(AppListViewTestContext);
136};
137
138// Extend the regular AppListTestViewDelegate to communicate back to the test
139// context. Note the test context doesn't simply inherit this, because the
140// delegate is owned by the view.
141class UnitTestViewDelegate : public app_list::test::AppListTestViewDelegate {
142 public:
143  UnitTestViewDelegate(AppListViewTestContext* parent) : parent_(parent) {}
144
145  // Overridden from app_list::AppListViewDelegate:
146  virtual bool ShouldCenterWindow() const OVERRIDE {
147    return app_list::switches::IsCenteredAppListEnabled();
148  }
149
150  // Overridden from app_list::test::AppListTestViewDelegate:
151  virtual void ViewClosing() OVERRIDE { parent_->NativeWidgetClosing(); }
152
153 private:
154  AppListViewTestContext* parent_;
155
156  DISALLOW_COPY_AND_ASSIGN(UnitTestViewDelegate);
157};
158
159AppListViewTestContext::AppListViewTestContext(int test_type,
160                                               gfx::NativeView parent)
161    : test_type_(static_cast<TestType>(test_type)) {
162  switch (test_type_) {
163    case NORMAL:
164      break;
165    case LANDSCAPE:
166      base::CommandLine::ForCurrentProcess()->AppendSwitch(
167          switches::kEnableCenteredAppList);
168      break;
169    case EXPERIMENTAL:
170      base::CommandLine::ForCurrentProcess()->AppendSwitch(
171          switches::kEnableExperimentalAppList);
172      break;
173    default:
174      NOTREACHED();
175      break;
176  }
177
178  delegate_.reset(new UnitTestViewDelegate(this));
179  view_ = new app_list::AppListView(delegate_.get());
180
181  // Initialize centered around a point that ensures the window is wholly shown.
182  view_->InitAsBubbleAtFixedLocation(parent,
183                                     0,
184                                     gfx::Point(300, 300),
185                                     views::BubbleBorder::FLOAT,
186                                     false /* border_accepts_events */);
187}
188
189AppListViewTestContext::~AppListViewTestContext() {
190  // The view observes the PaginationModel which is about to get destroyed, so
191  // if the view is not already deleted by the time this destructor is called,
192  // there will be problems.
193  EXPECT_FALSE(view_);
194}
195
196// static
197void AppListViewTestContext::CheckView(views::View* subview) {
198  ASSERT_TRUE(subview);
199  EXPECT_TRUE(subview->parent());
200  EXPECT_TRUE(subview->visible());
201  EXPECT_TRUE(subview->IsDrawn());
202}
203
204void AppListViewTestContext::ShowContentsViewPageAndVerify(int index) {
205  ContentsView* contents_view = view_->app_list_main_view()->contents_view();
206  contents_view->SetActivePage(index);
207  contents_view->Layout();
208  for (int i = 0; i < contents_view->NumLauncherPages(); ++i) {
209    EXPECT_EQ(i == index, IsViewAtOrigin(contents_view->GetPageView(i)));
210  }
211}
212
213void AppListViewTestContext::Show() {
214  view_->GetWidget()->Show();
215  run_loop_.reset(new base::RunLoop);
216  view_->SetNextPaintCallback(run_loop_->QuitClosure());
217  run_loop_->Run();
218
219  EXPECT_TRUE(view_->GetWidget()->IsVisible());
220}
221
222void AppListViewTestContext::Close() {
223  view_->GetWidget()->Close();
224  run_loop_.reset(new base::RunLoop);
225  run_loop_->Run();
226
227  // |view_| should have been deleted and set to NULL via ViewClosing().
228  EXPECT_FALSE(view_);
229}
230
231PaginationModel* AppListViewTestContext::GetPaginationModel() {
232  return view_->GetAppsPaginationModel();
233}
234
235void AppListViewTestContext::RunDisplayTest() {
236  EXPECT_FALSE(view_->GetWidget()->IsVisible());
237  EXPECT_EQ(-1, GetPaginationModel()->total_pages());
238  delegate_->GetTestModel()->PopulateApps(kInitialItems);
239
240  Show();
241
242  // Explicitly enforce the exact dimensions of the app list. Feel free to
243  // change these if you need to (they are just here to prevent against
244  // accidental changes to the window size).
245  switch (test_type_) {
246    case NORMAL:
247      EXPECT_EQ("400x500", view_->bounds().size().ToString());
248      break;
249    case LANDSCAPE:
250      // NOTE: Height should not exceed 402, because otherwise there might not
251      // be enough space to accomodate the virtual keyboard. (LANDSCAPE mode is
252      // enabled by default when the virtual keyboard is enabled.)
253      EXPECT_EQ("576x402", view_->bounds().size().ToString());
254      break;
255    case EXPERIMENTAL:
256      EXPECT_EQ("768x560", view_->bounds().size().ToString());
257      break;
258    default:
259      NOTREACHED();
260      break;
261  }
262
263  if (is_landscape())
264    EXPECT_EQ(2, GetPaginationModel()->total_pages());
265  else
266    EXPECT_EQ(3, GetPaginationModel()->total_pages());
267  EXPECT_EQ(0, GetPaginationModel()->selected_page());
268
269  // Checks on the main view.
270  AppListMainView* main_view = view_->app_list_main_view();
271  EXPECT_NO_FATAL_FAILURE(CheckView(main_view));
272  EXPECT_NO_FATAL_FAILURE(CheckView(main_view->contents_view()));
273
274  EXPECT_TRUE(main_view->contents_view()->IsNamedPageActive(
275      test_type_ == EXPERIMENTAL ? ContentsView::NAMED_PAGE_START
276                                 : ContentsView::NAMED_PAGE_APPS));
277
278  Close();
279}
280
281void AppListViewTestContext::RunReshowWithOpenFolderTest() {
282  EXPECT_FALSE(view_->GetWidget()->IsVisible());
283  EXPECT_EQ(-1, GetPaginationModel()->total_pages());
284
285  AppListTestModel* model = delegate_->GetTestModel();
286  model->PopulateApps(kInitialItems);
287  const std::string folder_id =
288      model->MergeItems(model->top_level_item_list()->item_at(0)->id(),
289                        model->top_level_item_list()->item_at(1)->id());
290
291  AppListFolderItem* folder_item = model->FindFolderItem(folder_id);
292  EXPECT_TRUE(folder_item);
293
294  Show();
295
296  // The main grid view should be showing initially.
297  AppListMainView* main_view = view_->app_list_main_view();
298  AppsContainerView* container_view =
299      main_view->contents_view()->apps_container_view();
300  EXPECT_NO_FATAL_FAILURE(CheckView(main_view));
301  EXPECT_NO_FATAL_FAILURE(CheckView(container_view->apps_grid_view()));
302  EXPECT_FALSE(container_view->app_list_folder_view()->visible());
303
304  AppsGridViewTestApi test_api(container_view->apps_grid_view());
305  test_api.PressItemAt(0);
306
307  // After pressing the folder item, the folder view should be showing.
308  EXPECT_NO_FATAL_FAILURE(CheckView(main_view));
309  EXPECT_NO_FATAL_FAILURE(CheckView(container_view->app_list_folder_view()));
310  EXPECT_FALSE(container_view->apps_grid_view()->visible());
311
312  view_->GetWidget()->Hide();
313  EXPECT_FALSE(view_->GetWidget()->IsVisible());
314
315  Show();
316
317  // The main grid view should be showing after a reshow.
318  EXPECT_NO_FATAL_FAILURE(CheckView(main_view));
319  EXPECT_NO_FATAL_FAILURE(CheckView(container_view->apps_grid_view()));
320  EXPECT_FALSE(container_view->app_list_folder_view()->visible());
321
322  Close();
323}
324
325void AppListViewTestContext::RunStartPageTest() {
326  EXPECT_FALSE(view_->GetWidget()->IsVisible());
327  EXPECT_EQ(-1, GetPaginationModel()->total_pages());
328  AppListTestModel* model = delegate_->GetTestModel();
329  model->PopulateApps(3);
330
331  Show();
332
333  AppListMainView* main_view = view_->app_list_main_view();
334  StartPageView* start_page_view =
335      main_view->contents_view()->start_page_view();
336  // Checks on the main view.
337  EXPECT_NO_FATAL_FAILURE(CheckView(main_view));
338  EXPECT_NO_FATAL_FAILURE(CheckView(main_view->contents_view()));
339  if (test_type_ == EXPERIMENTAL) {
340    EXPECT_NO_FATAL_FAILURE(CheckView(start_page_view));
341
342    // Show the start page view.
343    ContentsView* contents_view = main_view->contents_view();
344    ShowContentsViewPageAndVerify(contents_view->GetPageIndexForNamedPage(
345        ContentsView::NAMED_PAGE_START));
346    EXPECT_FALSE(main_view->search_box_view()->visible());
347
348    gfx::Size view_size(view_->GetPreferredSize());
349    ShowContentsViewPageAndVerify(
350        contents_view->GetPageIndexForNamedPage(ContentsView::NAMED_PAGE_APPS));
351    EXPECT_TRUE(main_view->search_box_view()->visible());
352
353    // Hiding and showing the search box should not affect the app list's
354    // preferred size. This is a regression test for http://crbug.com/386912.
355    EXPECT_EQ(view_size.ToString(), view_->GetPreferredSize().ToString());
356
357    // Check tiles hide and show on deletion and addition.
358    model->results()->Add(new TestTileSearchResult());
359    start_page_view->UpdateForTesting();
360    EXPECT_EQ(1u, GetVisibleTileItemViews(start_page_view->tile_views()));
361    model->results()->DeleteAll();
362    start_page_view->UpdateForTesting();
363    EXPECT_EQ(0u, GetVisibleTileItemViews(start_page_view->tile_views()));
364  } else {
365    EXPECT_EQ(NULL, start_page_view);
366  }
367
368  Close();
369}
370
371void AppListViewTestContext::RunPageSwitchingAnimationTest() {
372  if (test_type_ == EXPERIMENTAL) {
373    Show();
374
375    AppListMainView* main_view = view_->app_list_main_view();
376    // Checks on the main view.
377    EXPECT_NO_FATAL_FAILURE(CheckView(main_view));
378    EXPECT_NO_FATAL_FAILURE(CheckView(main_view->contents_view()));
379
380    ContentsView* contents_view = main_view->contents_view();
381    // Pad the ContentsView with blank pages so we have at least 3 views.
382    while (contents_view->NumLauncherPages() < 3)
383      contents_view->AddBlankPageForTesting();
384
385    contents_view->SetActivePage(0);
386    contents_view->Layout();
387    EXPECT_TRUE(IsViewAtOrigin(contents_view->GetPageView(0)));
388    EXPECT_FALSE(IsViewAtOrigin(contents_view->GetPageView(1)));
389    EXPECT_FALSE(IsViewAtOrigin(contents_view->GetPageView(2)));
390
391    // Change pages. View should not have moved without Layout().
392    contents_view->SetActivePage(1);
393    EXPECT_TRUE(IsViewAtOrigin(contents_view->GetPageView(0)));
394    EXPECT_FALSE(IsViewAtOrigin(contents_view->GetPageView(1)));
395    EXPECT_FALSE(IsViewAtOrigin(contents_view->GetPageView(2)));
396
397    // Change to a third page. This queues up the second animation behind the
398    // first.
399    contents_view->SetActivePage(2);
400    EXPECT_TRUE(IsViewAtOrigin(contents_view->GetPageView(0)));
401    EXPECT_FALSE(IsViewAtOrigin(contents_view->GetPageView(1)));
402    EXPECT_FALSE(IsViewAtOrigin(contents_view->GetPageView(2)));
403
404    // Call Layout(). Should jump to the third page.
405    contents_view->Layout();
406    EXPECT_FALSE(IsViewAtOrigin(contents_view->GetPageView(0)));
407    EXPECT_FALSE(IsViewAtOrigin(contents_view->GetPageView(1)));
408    EXPECT_TRUE(IsViewAtOrigin(contents_view->GetPageView(2)));
409  }
410
411  Close();
412}
413
414void AppListViewTestContext::RunProfileChangeTest() {
415  EXPECT_FALSE(view_->GetWidget()->IsVisible());
416  EXPECT_EQ(-1, GetPaginationModel()->total_pages());
417  delegate_->GetTestModel()->PopulateApps(kInitialItems);
418
419  Show();
420
421  if (is_landscape())
422    EXPECT_EQ(2, GetPaginationModel()->total_pages());
423  else
424    EXPECT_EQ(3, GetPaginationModel()->total_pages());
425
426  // Change the profile. The original model needs to be kept alive for
427  // observers to unregister themselves.
428  scoped_ptr<AppListTestModel> original_test_model(
429      delegate_->ReleaseTestModel());
430  delegate_->set_next_profile_app_count(1);
431
432  // The original ContentsView is destroyed here.
433  view_->SetProfileByPath(base::FilePath());
434  EXPECT_EQ(1, GetPaginationModel()->total_pages());
435
436  StartPageView* start_page_view =
437      view_->app_list_main_view()->contents_view()->start_page_view();
438  ContentsSwitcherView* contents_switcher_view =
439      view_->app_list_main_view()->contents_switcher_view();
440  if (test_type_ == EXPERIMENTAL) {
441    EXPECT_NO_FATAL_FAILURE(CheckView(contents_switcher_view));
442    EXPECT_EQ(view_->app_list_main_view()->contents_view(),
443              contents_switcher_view->contents_view());
444    EXPECT_NO_FATAL_FAILURE(CheckView(start_page_view));
445  } else {
446    EXPECT_EQ(NULL, contents_switcher_view);
447    EXPECT_EQ(NULL, start_page_view);
448  }
449
450  // New model updates should be processed by the start page view.
451  delegate_->GetTestModel()->results()->Add(new TestTileSearchResult());
452  if (test_type_ == EXPERIMENTAL) {
453    start_page_view->UpdateForTesting();
454    EXPECT_EQ(1u, GetVisibleTileItemViews(start_page_view->tile_views()));
455  }
456
457  // Old model updates should be ignored.
458  original_test_model->results()->Add(new TestTileSearchResult());
459  original_test_model->results()->Add(new TestTileSearchResult());
460  if (test_type_ == EXPERIMENTAL) {
461    start_page_view->UpdateForTesting();
462    EXPECT_EQ(1u, GetVisibleTileItemViews(start_page_view->tile_views()));
463  }
464
465  Close();
466}
467
468void AppListViewTestContext::RunSearchResultsTest() {
469  EXPECT_FALSE(view_->GetWidget()->IsVisible());
470  EXPECT_EQ(-1, GetPaginationModel()->total_pages());
471  AppListTestModel* model = delegate_->GetTestModel();
472  model->PopulateApps(3);
473
474  Show();
475
476  AppListMainView* main_view = view_->app_list_main_view();
477  ContentsView* contents_view = main_view->contents_view();
478  ShowContentsViewPageAndVerify(
479      contents_view->GetPageIndexForNamedPage(ContentsView::NAMED_PAGE_APPS));
480  EXPECT_TRUE(main_view->search_box_view()->visible());
481
482  // Show the search results.
483  contents_view->ShowSearchResults(true);
484  contents_view->Layout();
485  EXPECT_TRUE(contents_view->IsShowingSearchResults());
486  EXPECT_TRUE(main_view->search_box_view()->visible());
487
488  if (test_type_ == EXPERIMENTAL) {
489    EXPECT_TRUE(
490        contents_view->IsNamedPageActive(ContentsView::NAMED_PAGE_START));
491    EXPECT_TRUE(IsViewAtOrigin(contents_view->start_page_view()));
492  } else {
493    EXPECT_TRUE(contents_view->IsNamedPageActive(
494        ContentsView::NAMED_PAGE_SEARCH_RESULTS));
495    EXPECT_TRUE(IsViewAtOrigin(contents_view->search_results_view()));
496  }
497
498  // Hide the search results.
499  contents_view->ShowSearchResults(false);
500  contents_view->Layout();
501  EXPECT_FALSE(contents_view->IsShowingSearchResults());
502
503  // Check that we return to the page that we were on before the search.
504  EXPECT_TRUE(contents_view->IsNamedPageActive(ContentsView::NAMED_PAGE_APPS));
505  EXPECT_TRUE(IsViewAtOrigin(contents_view->apps_container_view()));
506  EXPECT_TRUE(main_view->search_box_view()->visible());
507
508  if (test_type_ == EXPERIMENTAL) {
509    ShowContentsViewPageAndVerify(contents_view->GetPageIndexForNamedPage(
510        ContentsView::NAMED_PAGE_START));
511
512    // Check that typing into the dummy search box triggers the search page.
513    base::string16 search_text = base::UTF8ToUTF16("test");
514    SearchBoxView* dummy_search_box =
515        contents_view->start_page_view()->dummy_search_box_view();
516    EXPECT_TRUE(dummy_search_box->IsDrawn());
517    dummy_search_box->search_box()->InsertText(search_text);
518    contents_view->Layout();
519    // Check that the current search is using |search_text|.
520    EXPECT_EQ(search_text, delegate_->GetTestModel()->search_box()->text());
521    EXPECT_TRUE(contents_view->IsShowingSearchResults());
522    EXPECT_FALSE(dummy_search_box->IsDrawn());
523    EXPECT_TRUE(main_view->search_box_view()->visible());
524    EXPECT_EQ(search_text, main_view->search_box_view()->search_box()->text());
525    EXPECT_TRUE(
526        contents_view->IsNamedPageActive(ContentsView::NAMED_PAGE_START));
527    EXPECT_TRUE(IsViewAtOrigin(contents_view->start_page_view()));
528
529    // Check that typing into the real search box triggers the search page.
530    ShowContentsViewPageAndVerify(
531        contents_view->GetPageIndexForNamedPage(ContentsView::NAMED_PAGE_APPS));
532    EXPECT_TRUE(IsViewAtOrigin(contents_view->apps_container_view()));
533
534    base::string16 new_search_text = base::UTF8ToUTF16("apple");
535    main_view->search_box_view()->search_box()->SetText(base::string16());
536    main_view->search_box_view()->search_box()->InsertText(new_search_text);
537    // Check that the current search is using |search_text|.
538    EXPECT_EQ(new_search_text, delegate_->GetTestModel()->search_box()->text());
539    EXPECT_EQ(new_search_text,
540              main_view->search_box_view()->search_box()->text());
541    EXPECT_TRUE(contents_view->IsShowingSearchResults());
542    EXPECT_FALSE(dummy_search_box->IsDrawn());
543    EXPECT_TRUE(main_view->search_box_view()->visible());
544    EXPECT_TRUE(dummy_search_box->search_box()->text().empty());
545
546    // Check that the dummy search box is clear when reshowing the start page.
547    ShowContentsViewPageAndVerify(
548        contents_view->GetPageIndexForNamedPage(ContentsView::NAMED_PAGE_APPS));
549    ShowContentsViewPageAndVerify(contents_view->GetPageIndexForNamedPage(
550        ContentsView::NAMED_PAGE_START));
551    EXPECT_TRUE(dummy_search_box->IsDrawn());
552    EXPECT_TRUE(dummy_search_box->search_box()->text().empty());
553  }
554
555  Close();
556}
557
558class AppListViewTestAura : public views::ViewsTestBase,
559                            public ::testing::WithParamInterface<int> {
560 public:
561  AppListViewTestAura() {}
562  virtual ~AppListViewTestAura() {}
563
564  // testing::Test overrides:
565  virtual void SetUp() OVERRIDE {
566    views::ViewsTestBase::SetUp();
567
568    // On Ash (only) the app list is placed into an aura::Window "container",
569    // which is also used to determine the context. In tests, use the ash root
570    // window as the parent. This only works on aura where the root window is a
571    // NativeView as well as a NativeWindow.
572    gfx::NativeView container = NULL;
573#if defined(USE_AURA)
574    container = GetContext();
575#endif
576
577    test_context_.reset(new AppListViewTestContext(GetParam(), container));
578  }
579
580  virtual void TearDown() OVERRIDE {
581    test_context_.reset();
582    views::ViewsTestBase::TearDown();
583  }
584
585 protected:
586  scoped_ptr<AppListViewTestContext> test_context_;
587
588 private:
589  DISALLOW_COPY_AND_ASSIGN(AppListViewTestAura);
590};
591
592class AppListViewTestDesktop : public views::ViewsTestBase,
593                               public ::testing::WithParamInterface<int> {
594 public:
595  AppListViewTestDesktop() {}
596  virtual ~AppListViewTestDesktop() {}
597
598  // testing::Test overrides:
599  virtual void SetUp() OVERRIDE {
600    set_views_delegate(new AppListViewTestViewsDelegate(this));
601    views::ViewsTestBase::SetUp();
602    test_context_.reset(new AppListViewTestContext(GetParam(), NULL));
603  }
604
605  virtual void TearDown() OVERRIDE {
606    test_context_.reset();
607    views::ViewsTestBase::TearDown();
608  }
609
610 protected:
611  scoped_ptr<AppListViewTestContext> test_context_;
612
613 private:
614  class AppListViewTestViewsDelegate : public views::TestViewsDelegate {
615   public:
616    AppListViewTestViewsDelegate(AppListViewTestDesktop* parent)
617        : parent_(parent) {}
618
619    // Overridden from views::ViewsDelegate:
620    virtual void OnBeforeWidgetInit(
621        views::Widget::InitParams* params,
622        views::internal::NativeWidgetDelegate* delegate) OVERRIDE;
623
624   private:
625    AppListViewTestDesktop* parent_;
626
627    DISALLOW_COPY_AND_ASSIGN(AppListViewTestViewsDelegate);
628  };
629
630  DISALLOW_COPY_AND_ASSIGN(AppListViewTestDesktop);
631};
632
633void AppListViewTestDesktop::AppListViewTestViewsDelegate::OnBeforeWidgetInit(
634    views::Widget::InitParams* params,
635    views::internal::NativeWidgetDelegate* delegate) {
636// Mimic the logic in ChromeViewsDelegate::OnBeforeWidgetInit(). Except, for
637// ChromeOS, use the root window from the AuraTestHelper rather than depending
638// on ash::Shell:GetPrimaryRootWindow(). Also assume non-ChromeOS is never the
639// Ash desktop, as that is covered by AppListViewTestAura.
640#if defined(OS_CHROMEOS)
641  if (!params->parent && !params->context)
642    params->context = parent_->GetContext();
643#elif defined(USE_AURA)
644  if (params->parent == NULL && params->context == NULL && !params->child)
645    params->native_widget = new views::DesktopNativeWidgetAura(delegate);
646#endif
647}
648
649}  // namespace
650
651// Tests showing the app list with basic test model in an ash-style root window.
652TEST_P(AppListViewTestAura, Display) {
653  EXPECT_NO_FATAL_FAILURE(test_context_->RunDisplayTest());
654}
655
656// Tests showing the app list on the desktop. Note on ChromeOS, this will still
657// use the regular root window.
658TEST_P(AppListViewTestDesktop, Display) {
659  EXPECT_NO_FATAL_FAILURE(test_context_->RunDisplayTest());
660}
661
662// Tests that the main grid view is shown after hiding and reshowing the app
663// list with a folder view open. This is a regression test for crbug.com/357058.
664TEST_P(AppListViewTestAura, ReshowWithOpenFolder) {
665  EXPECT_NO_FATAL_FAILURE(test_context_->RunReshowWithOpenFolderTest());
666}
667
668TEST_P(AppListViewTestDesktop, ReshowWithOpenFolder) {
669  EXPECT_NO_FATAL_FAILURE(test_context_->RunReshowWithOpenFolderTest());
670}
671
672// Tests that the start page view operates correctly.
673TEST_P(AppListViewTestAura, StartPageTest) {
674  EXPECT_NO_FATAL_FAILURE(test_context_->RunStartPageTest());
675}
676
677TEST_P(AppListViewTestDesktop, StartPageTest) {
678  EXPECT_NO_FATAL_FAILURE(test_context_->RunStartPageTest());
679}
680
681// Tests that the start page view operates correctly.
682TEST_P(AppListViewTestAura, PageSwitchingAnimationTest) {
683  EXPECT_NO_FATAL_FAILURE(test_context_->RunPageSwitchingAnimationTest());
684}
685
686TEST_P(AppListViewTestDesktop, PageSwitchingAnimationTest) {
687  EXPECT_NO_FATAL_FAILURE(test_context_->RunPageSwitchingAnimationTest());
688}
689
690// Tests that the profile changes operate correctly.
691TEST_P(AppListViewTestAura, ProfileChangeTest) {
692  EXPECT_NO_FATAL_FAILURE(test_context_->RunProfileChangeTest());
693}
694
695TEST_P(AppListViewTestDesktop, ProfileChangeTest) {
696  EXPECT_NO_FATAL_FAILURE(test_context_->RunProfileChangeTest());
697}
698
699// Tests that the correct views are displayed for showing search results.
700TEST_P(AppListViewTestAura, SearchResultsTest) {
701  EXPECT_NO_FATAL_FAILURE(test_context_->RunSearchResultsTest());
702}
703
704TEST_P(AppListViewTestDesktop, SearchResultsTest) {
705  EXPECT_NO_FATAL_FAILURE(test_context_->RunSearchResultsTest());
706}
707
708INSTANTIATE_TEST_CASE_P(AppListViewTestAuraInstance,
709                        AppListViewTestAura,
710                        ::testing::Range<int>(TEST_TYPE_START, TEST_TYPE_END));
711
712INSTANTIATE_TEST_CASE_P(AppListViewTestDesktopInstance,
713                        AppListViewTestDesktop,
714                        ::testing::Range<int>(TEST_TYPE_START, TEST_TYPE_END));
715
716}  // namespace test
717}  // namespace app_list
718