| OLD | NEW |
| (Empty) |
| 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 #import "ui/app_list/cocoa/apps_search_box_controller.h" | |
| 6 | |
| 7 #include "base/mac/scoped_nsobject.h" | |
| 8 #include "base/macros.h" | |
| 9 #include "base/strings/sys_string_conversions.h" | |
| 10 #include "base/strings/utf_string_conversions.h" | |
| 11 #import "testing/gtest_mac.h" | |
| 12 #include "ui/app_list/app_list_menu.h" | |
| 13 #include "ui/app_list/app_list_model_observer.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 #import "ui/base/cocoa/menu_controller.h" | |
| 18 #import "ui/gfx/test/ui_cocoa_test_helper.h" | |
| 19 | |
| 20 using base::ASCIIToUTF16; | |
| 21 | |
| 22 @interface TestAppsSearchBoxDelegate : NSObject<AppsSearchBoxDelegate> { | |
| 23 @private | |
| 24 app_list::SearchBoxModel searchBoxModel_; | |
| 25 app_list::test::AppListTestViewDelegate appListDelegate_; | |
| 26 app_list::test::AppListTestModel appListModel_; | |
| 27 int textChangeCount_; | |
| 28 } | |
| 29 | |
| 30 @property(assign, nonatomic) int textChangeCount; | |
| 31 | |
| 32 @end | |
| 33 | |
| 34 @implementation TestAppsSearchBoxDelegate | |
| 35 | |
| 36 @synthesize textChangeCount = textChangeCount_; | |
| 37 | |
| 38 - (id)init { | |
| 39 if ((self = [super init])) { | |
| 40 app_list::AppListViewDelegate::Users users(2); | |
| 41 users[0].name = ASCIIToUTF16("user1"); | |
| 42 users[1].name = ASCIIToUTF16("user2"); | |
| 43 users[1].email = ASCIIToUTF16("user2@chromium.org"); | |
| 44 users[1].active = true; | |
| 45 appListDelegate_.SetUsers(users); | |
| 46 } | |
| 47 return self; | |
| 48 } | |
| 49 | |
| 50 - (app_list::SearchBoxModel*)searchBoxModel { | |
| 51 return &searchBoxModel_; | |
| 52 } | |
| 53 | |
| 54 - (app_list::AppListViewDelegate*)appListDelegate { | |
| 55 return &appListDelegate_; | |
| 56 } | |
| 57 | |
| 58 - (app_list::test::AppListTestViewDelegate*)appListTestViewDelegate { | |
| 59 return &appListDelegate_; | |
| 60 } | |
| 61 | |
| 62 | |
| 63 - (BOOL)control:(NSControl*)control | |
| 64 textView:(NSTextView*)textView | |
| 65 doCommandBySelector:(SEL)command { | |
| 66 return NO; | |
| 67 } | |
| 68 | |
| 69 - (void)modelTextDidChange { | |
| 70 ++textChangeCount_; | |
| 71 } | |
| 72 | |
| 73 - (CGFloat)bubbleCornerRadius { | |
| 74 return 3; | |
| 75 } | |
| 76 | |
| 77 - (app_list::AppListModel*)appListModel { | |
| 78 return &appListModel_; | |
| 79 } | |
| 80 | |
| 81 @end | |
| 82 | |
| 83 namespace app_list { | |
| 84 namespace test { | |
| 85 | |
| 86 class AppsSearchBoxControllerTest : public ui::CocoaTest { | |
| 87 public: | |
| 88 AppsSearchBoxControllerTest() { | |
| 89 Init(); | |
| 90 } | |
| 91 | |
| 92 void SetUp() override { | |
| 93 apps_search_box_controller_.reset( | |
| 94 [[AppsSearchBoxController alloc] initWithFrame: | |
| 95 NSMakeRect(0, 0, 400, 100)]); | |
| 96 delegate_.reset([[TestAppsSearchBoxDelegate alloc] init]); | |
| 97 [apps_search_box_controller_ setDelegate:delegate_]; | |
| 98 | |
| 99 ui::CocoaTest::SetUp(); | |
| 100 [[test_window() contentView] addSubview:[apps_search_box_controller_ view]]; | |
| 101 } | |
| 102 | |
| 103 void TearDown() override { | |
| 104 [apps_search_box_controller_ setDelegate:nil]; | |
| 105 ui::CocoaTest::TearDown(); | |
| 106 } | |
| 107 | |
| 108 void SimulateKeyAction(SEL c) { | |
| 109 base::scoped_nsobject<NSTextView> stub_field_editor( | |
| 110 [[NSTextView alloc] initWithFrame:NSZeroRect]); | |
| 111 NSControl* control = [apps_search_box_controller_ searchTextField]; | |
| 112 [apps_search_box_controller_ control:control | |
| 113 textView:stub_field_editor.get() | |
| 114 doCommandBySelector:c]; | |
| 115 } | |
| 116 | |
| 117 protected: | |
| 118 base::scoped_nsobject<TestAppsSearchBoxDelegate> delegate_; | |
| 119 base::scoped_nsobject<AppsSearchBoxController> apps_search_box_controller_; | |
| 120 | |
| 121 private: | |
| 122 DISALLOW_COPY_AND_ASSIGN(AppsSearchBoxControllerTest); | |
| 123 }; | |
| 124 | |
| 125 TEST_VIEW(AppsSearchBoxControllerTest, [apps_search_box_controller_ view]); | |
| 126 | |
| 127 // Test the search box initialization, and search input and clearing. | |
| 128 TEST_F(AppsSearchBoxControllerTest, SearchBoxModel) { | |
| 129 app_list::SearchBoxModel* model = [delegate_ searchBoxModel]; | |
| 130 // Usually localized "Search". | |
| 131 const base::string16 hit_text(ASCIIToUTF16("hint")); | |
| 132 model->SetHintText(hit_text); | |
| 133 EXPECT_NSEQ(base::SysUTF16ToNSString(hit_text), | |
| 134 [[[apps_search_box_controller_ searchTextField] cell] placeholderString]); | |
| 135 | |
| 136 const base::string16 search_text(ASCIIToUTF16("test")); | |
| 137 model->SetText(search_text); | |
| 138 EXPECT_NSEQ(base::SysUTF16ToNSString(search_text), | |
| 139 [[apps_search_box_controller_ searchTextField] stringValue]); | |
| 140 // Updates coming via the model should notify the delegate. | |
| 141 EXPECT_EQ(1, [delegate_ textChangeCount]); | |
| 142 | |
| 143 // Updates from the view should update the model and notify the delegate. | |
| 144 [apps_search_box_controller_ clearSearch]; | |
| 145 EXPECT_EQ(base::string16(), model->text()); | |
| 146 EXPECT_NSEQ([NSString string], | |
| 147 [[apps_search_box_controller_ searchTextField] stringValue]); | |
| 148 EXPECT_EQ(2, [delegate_ textChangeCount]); | |
| 149 | |
| 150 // Test pressing escape clears the search. First add some text. | |
| 151 model->SetText(search_text); | |
| 152 EXPECT_EQ(3, [delegate_ textChangeCount]); | |
| 153 | |
| 154 EXPECT_NSEQ(base::SysUTF16ToNSString(search_text), | |
| 155 [[apps_search_box_controller_ searchTextField] stringValue]); | |
| 156 SimulateKeyAction(@selector(complete:)); | |
| 157 EXPECT_NSEQ([NSString string], | |
| 158 [[apps_search_box_controller_ searchTextField] stringValue]); | |
| 159 EXPECT_EQ(4, [delegate_ textChangeCount]); | |
| 160 } | |
| 161 | |
| 162 // Test the popup menu items when there is only one user.. | |
| 163 TEST_F(AppsSearchBoxControllerTest, SearchBoxMenuSingleUser) { | |
| 164 // Set a single user. We need to set the delegate again because the | |
| 165 // AppListModel observer isn't hooked up in these tests. | |
| 166 [delegate_ appListTestViewDelegate]->SetUsers( | |
| 167 app_list::AppListViewDelegate::Users(1)); | |
| 168 [apps_search_box_controller_ setDelegate:delegate_]; | |
| 169 | |
| 170 NSPopUpButton* menu_control = [apps_search_box_controller_ menuControl]; | |
| 171 EXPECT_TRUE([apps_search_box_controller_ appListMenu]); | |
| 172 ui::MenuModel* menu_model | |
| 173 = [apps_search_box_controller_ appListMenu]->menu_model(); | |
| 174 // Add one to the item count to account for the blank, first item that Cocoa | |
| 175 // has in its popup menus. | |
| 176 EXPECT_EQ(menu_model->GetItemCount() + 1, | |
| 177 [[menu_control menu] numberOfItems]); | |
| 178 | |
| 179 // All command ids should be less than |SELECT_PROFILE| as no user menu items | |
| 180 // are being shown. | |
| 181 for (int i = 0; i < menu_model->GetItemCount(); ++i) | |
| 182 EXPECT_LT(menu_model->GetCommandIdAt(i), AppListMenu::SELECT_PROFILE); | |
| 183 | |
| 184 // The number of items should match the index that starts profile items. | |
| 185 EXPECT_EQ(AppListMenu::SELECT_PROFILE, menu_model->GetItemCount()); | |
| 186 } | |
| 187 | |
| 188 // Test the popup menu items for the multi-profile case. | |
| 189 TEST_F(AppsSearchBoxControllerTest, SearchBoxMenu) { | |
| 190 const app_list::AppListViewDelegate::Users& users = | |
| 191 [delegate_ appListDelegate]->GetUsers(); | |
| 192 NSPopUpButton* menu_control = [apps_search_box_controller_ menuControl]; | |
| 193 EXPECT_TRUE([apps_search_box_controller_ appListMenu]); | |
| 194 ui::MenuModel* menu_model | |
| 195 = [apps_search_box_controller_ appListMenu]->menu_model(); | |
| 196 // Add one to the item count to account for the blank, first item that Cocoa | |
| 197 // has in its popup menus. | |
| 198 EXPECT_EQ(menu_model->GetItemCount() + 1, | |
| 199 [[menu_control menu] numberOfItems]); | |
| 200 | |
| 201 ui::MenuModel* found_menu_model = menu_model; | |
| 202 int index; | |
| 203 MenuController* controller = [[menu_control menu] delegate]; | |
| 204 | |
| 205 // The first user item is an unchecked label. | |
| 206 EXPECT_TRUE(ui::MenuModel::GetModelAndIndexForCommandId( | |
| 207 AppListMenu::SELECT_PROFILE, &menu_model, &index)); | |
| 208 EXPECT_EQ(found_menu_model, menu_model); | |
| 209 NSMenuItem* unchecked_user_item = [[menu_control menu] itemAtIndex:index + 1]; | |
| 210 [controller validateUserInterfaceItem:unchecked_user_item]; | |
| 211 // The profile name should be shown if there is no email available. | |
| 212 EXPECT_NSEQ(base::SysUTF16ToNSString(users[0].name), | |
| 213 [unchecked_user_item title]); | |
| 214 EXPECT_EQ(NSOffState, [unchecked_user_item state]); | |
| 215 | |
| 216 // The second user item is a checked label because it is the active profile. | |
| 217 EXPECT_TRUE(ui::MenuModel::GetModelAndIndexForCommandId( | |
| 218 AppListMenu::SELECT_PROFILE + 1, &menu_model, &index)); | |
| 219 EXPECT_EQ(found_menu_model, menu_model); | |
| 220 NSMenuItem* checked_user_item = [[menu_control menu] itemAtIndex:index + 1]; | |
| 221 [controller validateUserInterfaceItem:checked_user_item]; | |
| 222 // The email is shown when available. | |
| 223 EXPECT_NSEQ(base::SysUTF16ToNSString(users[1].email), | |
| 224 [checked_user_item title]); | |
| 225 EXPECT_EQ(NSOnState, [checked_user_item state]); | |
| 226 | |
| 227 // A regular item should have just the label. | |
| 228 EXPECT_TRUE(ui::MenuModel::GetModelAndIndexForCommandId( | |
| 229 AppListMenu::SHOW_SETTINGS, &menu_model, &index)); | |
| 230 EXPECT_EQ(found_menu_model, menu_model); | |
| 231 NSMenuItem* settings_item = [[menu_control menu] itemAtIndex:index + 1]; | |
| 232 EXPECT_FALSE([settings_item view]); | |
| 233 EXPECT_NSEQ(base::SysUTF16ToNSString(menu_model->GetLabelAt(index)), | |
| 234 [settings_item title]); | |
| 235 } | |
| 236 | |
| 237 // Test adding another user, and changing an existing one. | |
| 238 TEST_F(AppsSearchBoxControllerTest, SearchBoxMenuChangingUsers) { | |
| 239 app_list::AppListViewDelegate::Users users = | |
| 240 [delegate_ appListDelegate]->GetUsers(); | |
| 241 EXPECT_EQ(2u, users.size()); | |
| 242 ui::MenuModel* menu_model | |
| 243 = [apps_search_box_controller_ appListMenu]->menu_model(); | |
| 244 // Adding one to account for the empty item at index 0 in Cocoa popup menus. | |
| 245 int non_user_items = menu_model->GetItemCount() - users.size() + 1; | |
| 246 | |
| 247 NSPopUpButton* menu_control = [apps_search_box_controller_ menuControl]; | |
| 248 EXPECT_EQ(2, [[menu_control menu] numberOfItems] - non_user_items); | |
| 249 EXPECT_NSEQ(base::SysUTF16ToNSString(users[0].name), | |
| 250 [[[menu_control menu] itemAtIndex:1] title]); | |
| 251 | |
| 252 users[0].name = ASCIIToUTF16("renamed user"); | |
| 253 app_list::AppListViewDelegate::User new_user; | |
| 254 new_user.name = ASCIIToUTF16("user3"); | |
| 255 users.push_back(new_user); | |
| 256 [delegate_ appListTestViewDelegate]->SetUsers(users); | |
| 257 // Note: menu does not automatically get rebuilt. Force a rebuild (which | |
| 258 // would normally occur when the UI is closed / re-opend). | |
| 259 [apps_search_box_controller_ rebuildMenu]; | |
| 260 | |
| 261 // Should now be an extra item, and it should have correct titles. | |
| 262 EXPECT_EQ(3, [[menu_control menu] numberOfItems] - non_user_items); | |
| 263 EXPECT_NSEQ(base::SysUTF16ToNSString(users[0].name), | |
| 264 [[[menu_control menu] itemAtIndex:1] title]); | |
| 265 EXPECT_NSEQ(base::SysUTF16ToNSString(new_user.name), | |
| 266 [[[menu_control menu] itemAtIndex:3] title]); | |
| 267 } | |
| 268 | |
| 269 } // namespace test | |
| 270 } // namespace app_list | |
| OLD | NEW |