Update V8 to version 4.5.98.
[chromium-blink-merge.git] / ui / app_list / cocoa / apps_search_results_controller_unittest.mm
blob72c9798269708a6cc28216b5c9a41cfef99689d9
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.
5 #import "ui/app_list/cocoa/apps_search_results_controller.h"
7 #include "base/mac/scoped_nsobject.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #import "testing/gtest_mac.h"
13 #include "ui/app_list/test/app_list_test_model.h"
14 #include "ui/app_list/test/test_search_result.h"
15 #include "ui/base/models/simple_menu_model.h"
16 #import "ui/events/test/cocoa_test_event_utils.h"
17 #include "ui/gfx/image/image_skia_util_mac.h"
18 #import "ui/gfx/test/ui_cocoa_test_helper.h"
20 @interface TestAppsSearchResultsDelegate : NSObject<AppsSearchResultsDelegate> {
21  @private
22   app_list::test::AppListTestModel appListModel_;
23   app_list::SearchResult* lastOpenedResult_;
26 @property(readonly, nonatomic) app_list::SearchResult* lastOpenedResult;
28 - (void)quitMessageLoop;
30 @end
32 @implementation TestAppsSearchResultsDelegate
34 @synthesize lastOpenedResult = lastOpenedResult_;
36 - (app_list::AppListModel*)appListModel {
37   return &appListModel_;
40 - (void)openResult:(app_list::SearchResult*)result {
41   lastOpenedResult_ = result;
44 - (void)quitMessageLoop {
45   base::MessageLoop::current()->QuitNow();
48 @end
50 namespace app_list {
51 namespace test {
52 namespace {
54 const int kDefaultResultsCount = 3;
56 class SearchResultWithMenu : public TestSearchResult {
57  public:
58   SearchResultWithMenu(const std::string& title, const std::string& details)
59       : menu_model_(NULL),
60         menu_ready_(true) {
61     set_title(base::ASCIIToUTF16(title));
62     set_details(base::ASCIIToUTF16(details));
63     menu_model_.AddItem(0, base::UTF8ToUTF16("Menu For: " + title));
64   }
66   void SetMenuReadyForTesting(bool ready) {
67     menu_ready_ = ready;
68   }
70   ui::MenuModel* GetContextMenuModel() override {
71     if (!menu_ready_)
72       return NULL;
74     return &menu_model_;
75   }
77  private:
78   ui::SimpleMenuModel menu_model_;
79   bool menu_ready_;
81   DISALLOW_COPY_AND_ASSIGN(SearchResultWithMenu);
84 class AppsSearchResultsControllerTest : public ui::CocoaTest {
85  public:
86   AppsSearchResultsControllerTest() {}
88   void AddTestResultAtIndex(size_t index,
89                             const std::string& title,
90                             const std::string& details) {
91     scoped_ptr<SearchResult> result(new SearchResultWithMenu(title, details));
92     AppListModel::SearchResults* results = [delegate_ appListModel]->results();
93     results->AddAt(index, result.release());
94   }
96   SearchResult* ModelResultAt(size_t index) {
97     return [delegate_ appListModel]->results()->GetItemAt(index);
98   }
100   NSCell* ViewResultAt(NSInteger index) {
101     NSTableView* table_view = [apps_search_results_controller_ tableView];
102     return [table_view preparedCellAtColumn:0
103                                         row:index];
104   }
106   void SetMenuReadyAt(size_t index, bool ready) {
107     SearchResultWithMenu* result =
108         static_cast<SearchResultWithMenu*>(ModelResultAt(index));
109     result->SetMenuReadyForTesting(ready);
110   }
112   BOOL SimulateKeyAction(SEL c) {
113     return [apps_search_results_controller_ handleCommandBySelector:c];
114   }
116   void ExpectConsistent();
118   // ui::CocoaTest overrides:
119   void SetUp() override;
120   void TearDown() override;
122  protected:
123   base::scoped_nsobject<TestAppsSearchResultsDelegate> delegate_;
124   base::scoped_nsobject<AppsSearchResultsController>
125       apps_search_results_controller_;
127  private:
128   DISALLOW_COPY_AND_ASSIGN(AppsSearchResultsControllerTest);
131 void AppsSearchResultsControllerTest::ExpectConsistent() {
132   NSInteger item_count = [delegate_ appListModel]->results()->item_count();
133   ASSERT_EQ(item_count,
134             [[apps_search_results_controller_ tableView] numberOfRows]);
136   // Compare content strings to ensure the order of items is consistent, and any
137   // model data that should have been reloaded has been reloaded in the view.
138   for (NSInteger i = 0; i < item_count; ++i) {
139     SearchResult* result = ModelResultAt(i);
140     base::string16 string_in_model = result->title();
141     if (!result->details().empty())
142       string_in_model += base::ASCIIToUTF16("\n") + result->details();
143     EXPECT_NSEQ(base::SysUTF16ToNSString(string_in_model),
144                 [[ViewResultAt(i) attributedStringValue] string]);
145   }
148 void AppsSearchResultsControllerTest::SetUp() {
149   apps_search_results_controller_.reset(
150       [[AppsSearchResultsController alloc] initWithAppsSearchResultsFrameSize:
151           NSMakeSize(400, 400)]);
152   // The view is initially hidden. Give it a non-zero height so it draws.
153   [[apps_search_results_controller_ view] setFrameSize:NSMakeSize(400, 400)];
155   delegate_.reset([[TestAppsSearchResultsDelegate alloc] init]);
157   // Populate with some results so that TEST_VIEW does something non-trivial.
158   for (int i = 0; i < kDefaultResultsCount; ++i)
159     AddTestResultAtIndex(i, base::StringPrintf("Result %d", i), "ItemDetail");
161   SearchResult::Tags test_tags;
162   // Apply markup to the substring "Result" in the first item.
163   test_tags.push_back(SearchResult::Tag(SearchResult::Tag::NONE, 0, 1));
164   test_tags.push_back(SearchResult::Tag(SearchResult::Tag::URL, 1, 2));
165   test_tags.push_back(SearchResult::Tag(SearchResult::Tag::MATCH, 2, 3));
166   test_tags.push_back(SearchResult::Tag(SearchResult::Tag::DIM, 3, 4));
167   test_tags.push_back(SearchResult::Tag(SearchResult::Tag::MATCH |
168                                         SearchResult::Tag::URL, 4, 5));
169   test_tags.push_back(SearchResult::Tag(SearchResult::Tag::MATCH |
170                                         SearchResult::Tag::DIM, 5, 6));
172   SearchResult* result = ModelResultAt(0);
173   result->SetIcon(gfx::ImageSkiaFromNSImage(
174       [NSImage imageNamed:NSImageNameStatusAvailable]));
175   result->set_title_tags(test_tags);
177   [apps_search_results_controller_ setDelegate:delegate_];
179   ui::CocoaTest::SetUp();
180   [[test_window() contentView] addSubview:
181       [apps_search_results_controller_ view]];
184 void AppsSearchResultsControllerTest::TearDown() {
185   [apps_search_results_controller_ setDelegate:nil];
186   ui::CocoaTest::TearDown();
189 NSEvent* MouseEventInRow(NSTableView* table_view, NSInteger row_index) {
190   NSRect row_rect = [table_view rectOfRow:row_index];
191   NSPoint point_in_view = NSMakePoint(NSMidX(row_rect), NSMidY(row_rect));
192   NSPoint point_in_window = [table_view convertPoint:point_in_view
193                                               toView:nil];
194   return cocoa_test_event_utils::LeftMouseDownAtPoint(point_in_window);
197 }  // namespace
199 TEST_VIEW(AppsSearchResultsControllerTest,
200           [apps_search_results_controller_ view]);
202 TEST_F(AppsSearchResultsControllerTest, ModelObservers) {
203   NSTableView* table_view = [apps_search_results_controller_ tableView];
204   ExpectConsistent();
206   EXPECT_EQ(1, [table_view numberOfColumns]);
207   EXPECT_EQ(kDefaultResultsCount, [table_view numberOfRows]);
209   // Insert at start.
210   AddTestResultAtIndex(0, "One", std::string());
211   EXPECT_EQ(kDefaultResultsCount + 1, [table_view numberOfRows]);
212   ExpectConsistent();
214   // Remove from end.
215   [delegate_ appListModel]->results()->DeleteAt(kDefaultResultsCount);
216   EXPECT_EQ(kDefaultResultsCount, [table_view numberOfRows]);
217   ExpectConsistent();
219   // Insert at end.
220   AddTestResultAtIndex(kDefaultResultsCount, "Four", std::string());
221   EXPECT_EQ(kDefaultResultsCount + 1, [table_view numberOfRows]);
222   ExpectConsistent();
224   // Delete from start.
225   [delegate_ appListModel]->results()->DeleteAt(0);
226   EXPECT_EQ(kDefaultResultsCount, [table_view numberOfRows]);
227   ExpectConsistent();
229   // Test clearing results.
230   [delegate_ appListModel]->results()->DeleteAll();
231   EXPECT_EQ(0, [table_view numberOfRows]);
232   ExpectConsistent();
235 TEST_F(AppsSearchResultsControllerTest, KeyboardSelectAndActivate) {
236   NSTableView* table_view = [apps_search_results_controller_ tableView];
237   EXPECT_EQ(-1, [table_view selectedRow]);
239   // Pressing up when nothing is selected should select the last item.
240   EXPECT_TRUE(SimulateKeyAction(@selector(moveUp:)));
241   EXPECT_EQ(kDefaultResultsCount - 1, [table_view selectedRow]);
242   [table_view deselectAll:nil];
243   EXPECT_EQ(-1, [table_view selectedRow]);
245   // Pressing down when nothing is selected should select the first item.
246   EXPECT_TRUE(SimulateKeyAction(@selector(moveDown:)));
247   EXPECT_EQ(0, [table_view selectedRow]);
249   // Pressing up should wrap around.
250   EXPECT_TRUE(SimulateKeyAction(@selector(moveUp:)));
251   EXPECT_EQ(kDefaultResultsCount - 1, [table_view selectedRow]);
253   // Down should now also wrap, since the selection is at the end.
254   EXPECT_TRUE(SimulateKeyAction(@selector(moveDown:)));
255   EXPECT_EQ(0, [table_view selectedRow]);
257   // Regular down and up movement, ensuring the cells have correct backgrounds.
258   EXPECT_TRUE(SimulateKeyAction(@selector(moveDown:)));
259   EXPECT_EQ(1, [table_view selectedRow]);
260   EXPECT_EQ(NSBackgroundStyleDark, [ViewResultAt(1) backgroundStyle]);
261   EXPECT_EQ(NSBackgroundStyleLight, [ViewResultAt(0) backgroundStyle]);
263   EXPECT_TRUE(SimulateKeyAction(@selector(moveUp:)));
264   EXPECT_EQ(0, [table_view selectedRow]);
265   EXPECT_EQ(NSBackgroundStyleDark, [ViewResultAt(0) backgroundStyle]);
266   EXPECT_EQ(NSBackgroundStyleLight, [ViewResultAt(1) backgroundStyle]);
268   // Test activating items.
269   EXPECT_TRUE(SimulateKeyAction(@selector(insertNewline:)));
270   EXPECT_EQ(ModelResultAt(0), [delegate_ lastOpenedResult]);
271   EXPECT_TRUE(SimulateKeyAction(@selector(moveDown:)));
272   EXPECT_TRUE(SimulateKeyAction(@selector(insertNewline:)));
273   EXPECT_EQ(ModelResultAt(1), [delegate_ lastOpenedResult]);
276 TEST_F(AppsSearchResultsControllerTest, ContextMenus) {
277   NSTableView* table_view = [apps_search_results_controller_ tableView];
278   NSEvent* mouse_in_row_0 = MouseEventInRow(table_view, 0);
279   NSEvent* mouse_in_row_1 = MouseEventInRow(table_view, 1);
281   NSMenu* menu = [table_view menuForEvent:mouse_in_row_0];
282   EXPECT_EQ(1, [menu numberOfItems]);
283   EXPECT_NSEQ(@"Menu For: Result 0", [[menu itemAtIndex:0] title]);
285   // Test a context menu request while the item is still installing.
286   SetMenuReadyAt(1, false);
287   menu = [table_view menuForEvent:mouse_in_row_1];
288   EXPECT_EQ(nil, menu);
290   SetMenuReadyAt(1, true);
291   menu = [table_view menuForEvent:mouse_in_row_1];
292   EXPECT_EQ(1, [menu numberOfItems]);
293   EXPECT_NSEQ(@"Menu For: Result 1", [[menu itemAtIndex:0] title]);
296 }  // namespace test
297 }  // namespace app_list