combobox_unittest.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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 "ui/views/controls/combobox/combobox.h" 6 7#include <set> 8 9#include "base/basictypes.h" 10#include "base/strings/utf_string_conversions.h" 11#include "ui/base/ime/text_input_client.h" 12#include "ui/base/models/combobox_model.h" 13#include "ui/events/event.h" 14#include "ui/events/event_constants.h" 15#include "ui/events/keycodes/keyboard_codes.h" 16#include "ui/views/controls/combobox/combobox_listener.h" 17#include "ui/views/controls/menu/menu_runner.h" 18#include "ui/views/controls/menu/menu_runner_handler.h" 19#include "ui/views/ime/mock_input_method.h" 20#include "ui/views/test/menu_runner_test_api.h" 21#include "ui/views/test/views_test_base.h" 22#include "ui/views/widget/widget.h" 23 24using base::ASCIIToUTF16; 25 26namespace views { 27 28namespace { 29 30// An dummy implementation of MenuRunnerHandler to check if the dropdown menu is 31// shown or not. 32class TestMenuRunnerHandler : public MenuRunnerHandler { 33 public: 34 TestMenuRunnerHandler() : executed_(false) {} 35 36 bool executed() const { return executed_; } 37 38 virtual MenuRunner::RunResult RunMenuAt(Widget* parent, 39 MenuButton* button, 40 const gfx::Rect& bounds, 41 MenuAnchorPosition anchor, 42 ui::MenuSourceType source_type, 43 int32 types) OVERRIDE { 44 executed_ = true; 45 return MenuRunner::NORMAL_EXIT; 46 } 47 48 private: 49 bool executed_; 50 51 DISALLOW_COPY_AND_ASSIGN(TestMenuRunnerHandler); 52}; 53 54// A wrapper of Combobox to intercept the result of OnKeyPressed() and 55// OnKeyReleased() methods. 56class TestCombobox : public Combobox { 57 public: 58 explicit TestCombobox(ui::ComboboxModel* model) 59 : Combobox(model), 60 key_handled_(false), 61 key_received_(false) {} 62 63 virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE { 64 key_received_ = true; 65 key_handled_ = Combobox::OnKeyPressed(e); 66 return key_handled_; 67 } 68 69 virtual bool OnKeyReleased(const ui::KeyEvent& e) OVERRIDE { 70 key_received_ = true; 71 key_handled_ = Combobox::OnKeyReleased(e); 72 return key_handled_; 73 } 74 75 bool key_handled() const { return key_handled_; } 76 bool key_received() const { return key_received_; } 77 78 void clear() { 79 key_received_ = key_handled_ = false; 80 } 81 82 private: 83 bool key_handled_; 84 bool key_received_; 85 86 DISALLOW_COPY_AND_ASSIGN(TestCombobox); 87}; 88 89// A concrete class is needed to test the combobox. 90class TestComboboxModel : public ui::ComboboxModel { 91 public: 92 TestComboboxModel() {} 93 virtual ~TestComboboxModel() {} 94 95 // ui::ComboboxModel: 96 virtual int GetItemCount() const OVERRIDE { 97 return 10; 98 } 99 virtual base::string16 GetItemAt(int index) OVERRIDE { 100 if (IsItemSeparatorAt(index)) { 101 NOTREACHED(); 102 return ASCIIToUTF16("SEPARATOR"); 103 } 104 return ASCIIToUTF16(index % 2 == 0 ? "PEANUT BUTTER" : "JELLY"); 105 } 106 virtual bool IsItemSeparatorAt(int index) OVERRIDE { 107 return separators_.find(index) != separators_.end(); 108 } 109 110 void SetSeparators(const std::set<int>& separators) { 111 separators_ = separators; 112 } 113 114 private: 115 std::set<int> separators_; 116 117 DISALLOW_COPY_AND_ASSIGN(TestComboboxModel); 118}; 119 120// A combobox model which refers to a vector. 121class VectorComboboxModel : public ui::ComboboxModel { 122 public: 123 explicit VectorComboboxModel(std::vector<std::string>* values) 124 : values_(values) {} 125 virtual ~VectorComboboxModel() {} 126 127 // ui::ComboboxModel: 128 virtual int GetItemCount() const OVERRIDE { 129 return (int)values_->size(); 130 } 131 virtual base::string16 GetItemAt(int index) OVERRIDE { 132 return ASCIIToUTF16(values_->at(index)); 133 } 134 virtual bool IsItemSeparatorAt(int index) OVERRIDE { 135 return false; 136 } 137 138 private: 139 std::vector<std::string>* values_; 140}; 141 142class EvilListener : public ComboboxListener { 143 public: 144 EvilListener() : deleted_(false) {} 145 virtual ~EvilListener() {}; 146 147 // ComboboxListener: 148 virtual void OnPerformAction(Combobox* combobox) OVERRIDE { 149 delete combobox; 150 deleted_ = true; 151 } 152 153 bool deleted() const { return deleted_; } 154 155 private: 156 bool deleted_; 157 158 DISALLOW_COPY_AND_ASSIGN(EvilListener); 159}; 160 161class TestComboboxListener : public views::ComboboxListener { 162 public: 163 TestComboboxListener() : perform_action_index_(-1), actions_performed_(0) {} 164 virtual ~TestComboboxListener() {} 165 166 virtual void OnPerformAction(views::Combobox* combobox) OVERRIDE { 167 perform_action_index_ = combobox->selected_index(); 168 actions_performed_++; 169 } 170 171 int perform_action_index() const { 172 return perform_action_index_; 173 } 174 175 bool on_perform_action_called() const { 176 return actions_performed_ > 0; 177 } 178 179 int actions_performed() const { 180 return actions_performed_; 181 } 182 183 private: 184 int perform_action_index_; 185 int actions_performed_; 186 187 private: 188 DISALLOW_COPY_AND_ASSIGN(TestComboboxListener); 189}; 190 191} // namespace 192 193class ComboboxTest : public ViewsTestBase { 194 public: 195 ComboboxTest() : widget_(NULL), combobox_(NULL) {} 196 197 virtual void TearDown() OVERRIDE { 198 if (widget_) 199 widget_->Close(); 200 ViewsTestBase::TearDown(); 201 } 202 203 void InitCombobox() { 204 model_.reset(new TestComboboxModel()); 205 206 ASSERT_FALSE(combobox_); 207 combobox_ = new TestCombobox(model_.get()); 208 combobox_->set_id(1); 209 210 widget_ = new Widget; 211 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 212 params.bounds = gfx::Rect(200, 200, 200, 200); 213 widget_->Init(params); 214 View* container = new View(); 215 widget_->SetContentsView(container); 216 container->AddChildView(combobox_); 217 218 widget_->ReplaceInputMethod(new MockInputMethod); 219 220 // Assumes the Widget is always focused. 221 widget_->GetInputMethod()->OnFocus(); 222 223 combobox_->RequestFocus(); 224 combobox_->SizeToPreferredSize(); 225 } 226 227 protected: 228 void SendKeyEvent(ui::KeyboardCode key_code) { 229 SendKeyEventWithType(key_code, ui::ET_KEY_PRESSED); 230 } 231 232 void SendKeyEventWithType(ui::KeyboardCode key_code, ui::EventType type) { 233 ui::KeyEvent event(type, key_code, 0, false); 234 widget_->GetInputMethod()->DispatchKeyEvent(event); 235 } 236 237 View* GetFocusedView() { 238 return widget_->GetFocusManager()->GetFocusedView(); 239 } 240 241 void PerformClick(const gfx::Point& point) { 242 ui::MouseEvent pressed_event = ui::MouseEvent(ui::ET_MOUSE_PRESSED, point, 243 point, 244 ui::EF_LEFT_MOUSE_BUTTON, 245 ui::EF_LEFT_MOUSE_BUTTON); 246 widget_->OnMouseEvent(&pressed_event); 247 ui::MouseEvent released_event = ui::MouseEvent(ui::ET_MOUSE_RELEASED, point, 248 point, 249 ui::EF_LEFT_MOUSE_BUTTON, 250 ui::EF_LEFT_MOUSE_BUTTON); 251 widget_->OnMouseEvent(&released_event); 252 } 253 254 // We need widget to populate wrapper class. 255 Widget* widget_; 256 257 // |combobox_| will be allocated InitCombobox() and then owned by |widget_|. 258 TestCombobox* combobox_; 259 260 // Combobox does not take ownership of the model, hence it needs to be scoped. 261 scoped_ptr<TestComboboxModel> model_; 262}; 263 264TEST_F(ComboboxTest, KeyTest) { 265 InitCombobox(); 266 SendKeyEvent(ui::VKEY_END); 267 EXPECT_EQ(combobox_->selected_index() + 1, model_->GetItemCount()); 268 SendKeyEvent(ui::VKEY_HOME); 269 EXPECT_EQ(combobox_->selected_index(), 0); 270 SendKeyEvent(ui::VKEY_DOWN); 271 SendKeyEvent(ui::VKEY_DOWN); 272 EXPECT_EQ(combobox_->selected_index(), 2); 273 SendKeyEvent(ui::VKEY_RIGHT); 274 EXPECT_EQ(combobox_->selected_index(), 2); 275 SendKeyEvent(ui::VKEY_LEFT); 276 EXPECT_EQ(combobox_->selected_index(), 2); 277 SendKeyEvent(ui::VKEY_UP); 278 EXPECT_EQ(combobox_->selected_index(), 1); 279 SendKeyEvent(ui::VKEY_PRIOR); 280 EXPECT_EQ(combobox_->selected_index(), 0); 281 SendKeyEvent(ui::VKEY_NEXT); 282 EXPECT_EQ(combobox_->selected_index(), model_->GetItemCount() - 1); 283} 284 285// Check that if a combobox is disabled before it has a native wrapper, then the 286// native wrapper inherits the disabled state when it gets created. 287TEST_F(ComboboxTest, DisabilityTest) { 288 model_.reset(new TestComboboxModel()); 289 290 ASSERT_FALSE(combobox_); 291 combobox_ = new TestCombobox(model_.get()); 292 combobox_->SetEnabled(false); 293 294 widget_ = new Widget; 295 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 296 params.bounds = gfx::Rect(100, 100, 100, 100); 297 widget_->Init(params); 298 View* container = new View(); 299 widget_->SetContentsView(container); 300 container->AddChildView(combobox_); 301 EXPECT_FALSE(combobox_->enabled()); 302} 303 304// Verifies that we don't select a separator line in combobox when navigating 305// through keyboard. 306TEST_F(ComboboxTest, SkipSeparatorSimple) { 307 InitCombobox(); 308 std::set<int> separators; 309 separators.insert(2); 310 model_->SetSeparators(separators); 311 EXPECT_EQ(0, combobox_->selected_index()); 312 SendKeyEvent(ui::VKEY_DOWN); 313 EXPECT_EQ(1, combobox_->selected_index()); 314 SendKeyEvent(ui::VKEY_DOWN); 315 EXPECT_EQ(3, combobox_->selected_index()); 316 SendKeyEvent(ui::VKEY_UP); 317 EXPECT_EQ(1, combobox_->selected_index()); 318 SendKeyEvent(ui::VKEY_HOME); 319 EXPECT_EQ(0, combobox_->selected_index()); 320 SendKeyEvent(ui::VKEY_PRIOR); 321 EXPECT_EQ(0, combobox_->selected_index()); 322 SendKeyEvent(ui::VKEY_END); 323 EXPECT_EQ(9, combobox_->selected_index()); 324} 325 326// Verifies that we never select the separator that is in the beginning of the 327// combobox list when navigating through keyboard. 328TEST_F(ComboboxTest, SkipSeparatorBeginning) { 329 InitCombobox(); 330 std::set<int> separators; 331 separators.insert(0); 332 model_->SetSeparators(separators); 333 EXPECT_EQ(0, combobox_->selected_index()); 334 SendKeyEvent(ui::VKEY_DOWN); 335 EXPECT_EQ(1, combobox_->selected_index()); 336 SendKeyEvent(ui::VKEY_DOWN); 337 EXPECT_EQ(2, combobox_->selected_index()); 338 SendKeyEvent(ui::VKEY_UP); 339 EXPECT_EQ(1, combobox_->selected_index()); 340 SendKeyEvent(ui::VKEY_HOME); 341 EXPECT_EQ(1, combobox_->selected_index()); 342 SendKeyEvent(ui::VKEY_PRIOR); 343 EXPECT_EQ(1, combobox_->selected_index()); 344 SendKeyEvent(ui::VKEY_END); 345 EXPECT_EQ(9, combobox_->selected_index()); 346} 347 348// Verifies that we never select the separator that is in the end of the 349// combobox list when navigating through keyboard. 350TEST_F(ComboboxTest, SkipSeparatorEnd) { 351 InitCombobox(); 352 std::set<int> separators; 353 separators.insert(model_->GetItemCount() - 1); 354 model_->SetSeparators(separators); 355 combobox_->SetSelectedIndex(8); 356 SendKeyEvent(ui::VKEY_DOWN); 357 EXPECT_EQ(8, combobox_->selected_index()); 358 SendKeyEvent(ui::VKEY_UP); 359 EXPECT_EQ(7, combobox_->selected_index()); 360 SendKeyEvent(ui::VKEY_END); 361 EXPECT_EQ(8, combobox_->selected_index()); 362} 363 364// Verifies that we never select any of the adjacent separators (multiple 365// consecutive) that appear in the beginning of the combobox list when 366// navigating through keyboard. 367TEST_F(ComboboxTest, SkipMultipleSeparatorsAtBeginning) { 368 InitCombobox(); 369 std::set<int> separators; 370 separators.insert(0); 371 separators.insert(1); 372 separators.insert(2); 373 model_->SetSeparators(separators); 374 EXPECT_EQ(0, combobox_->selected_index()); 375 SendKeyEvent(ui::VKEY_DOWN); 376 EXPECT_EQ(3, combobox_->selected_index()); 377 SendKeyEvent(ui::VKEY_UP); 378 EXPECT_EQ(3, combobox_->selected_index()); 379 SendKeyEvent(ui::VKEY_NEXT); 380 EXPECT_EQ(9, combobox_->selected_index()); 381 SendKeyEvent(ui::VKEY_HOME); 382 EXPECT_EQ(3, combobox_->selected_index()); 383 SendKeyEvent(ui::VKEY_END); 384 EXPECT_EQ(9, combobox_->selected_index()); 385 SendKeyEvent(ui::VKEY_PRIOR); 386 EXPECT_EQ(3, combobox_->selected_index()); 387} 388 389// Verifies that we never select any of the adjacent separators (multiple 390// consecutive) that appear in the middle of the combobox list when navigating 391// through keyboard. 392TEST_F(ComboboxTest, SkipMultipleAdjacentSeparatorsAtMiddle) { 393 InitCombobox(); 394 std::set<int> separators; 395 separators.insert(4); 396 separators.insert(5); 397 separators.insert(6); 398 model_->SetSeparators(separators); 399 combobox_->SetSelectedIndex(3); 400 SendKeyEvent(ui::VKEY_DOWN); 401 EXPECT_EQ(7, combobox_->selected_index()); 402 SendKeyEvent(ui::VKEY_UP); 403 EXPECT_EQ(3, combobox_->selected_index()); 404} 405 406// Verifies that we never select any of the adjacent separators (multiple 407// consecutive) that appear in the end of the combobox list when navigating 408// through keyboard. 409TEST_F(ComboboxTest, SkipMultipleSeparatorsAtEnd) { 410 InitCombobox(); 411 std::set<int> separators; 412 separators.insert(7); 413 separators.insert(8); 414 separators.insert(9); 415 model_->SetSeparators(separators); 416 combobox_->SetSelectedIndex(6); 417 SendKeyEvent(ui::VKEY_DOWN); 418 EXPECT_EQ(6, combobox_->selected_index()); 419 SendKeyEvent(ui::VKEY_UP); 420 EXPECT_EQ(5, combobox_->selected_index()); 421 SendKeyEvent(ui::VKEY_HOME); 422 EXPECT_EQ(0, combobox_->selected_index()); 423 SendKeyEvent(ui::VKEY_NEXT); 424 EXPECT_EQ(6, combobox_->selected_index()); 425 SendKeyEvent(ui::VKEY_PRIOR); 426 EXPECT_EQ(0, combobox_->selected_index()); 427 SendKeyEvent(ui::VKEY_END); 428 EXPECT_EQ(6, combobox_->selected_index()); 429} 430 431TEST_F(ComboboxTest, GetTextForRowTest) { 432 InitCombobox(); 433 std::set<int> separators; 434 separators.insert(0); 435 separators.insert(1); 436 separators.insert(9); 437 model_->SetSeparators(separators); 438 for (int i = 0; i < combobox_->GetRowCount(); ++i) { 439 if (separators.count(i) != 0) { 440 EXPECT_TRUE(combobox_->GetTextForRow(i).empty()) << i; 441 } else { 442 EXPECT_EQ(ASCIIToUTF16(i % 2 == 0 ? "PEANUT BUTTER" : "JELLY"), 443 combobox_->GetTextForRow(i)) << i; 444 } 445 } 446} 447 448// Verifies selecting the first matching value (and returning whether found). 449TEST_F(ComboboxTest, SelectValue) { 450 InitCombobox(); 451 ASSERT_EQ(model_->GetDefaultIndex(), combobox_->selected_index()); 452 EXPECT_TRUE(combobox_->SelectValue(ASCIIToUTF16("PEANUT BUTTER"))); 453 EXPECT_EQ(0, combobox_->selected_index()); 454 EXPECT_TRUE(combobox_->SelectValue(ASCIIToUTF16("JELLY"))); 455 EXPECT_EQ(1, combobox_->selected_index()); 456 EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("BANANAS"))); 457 EXPECT_EQ(1, combobox_->selected_index()); 458 459 // With the action style, the selected index is always 0. 460 combobox_->SetStyle(Combobox::STYLE_ACTION); 461 EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("PEANUT BUTTER"))); 462 EXPECT_EQ(0, combobox_->selected_index()); 463 EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("JELLY"))); 464 EXPECT_EQ(0, combobox_->selected_index()); 465 EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("BANANAS"))); 466 EXPECT_EQ(0, combobox_->selected_index()); 467} 468 469TEST_F(ComboboxTest, SelectIndexActionStyle) { 470 InitCombobox(); 471 472 // With the action style, the selected index is always 0. 473 combobox_->SetStyle(Combobox::STYLE_ACTION); 474 combobox_->SetSelectedIndex(1); 475 EXPECT_EQ(0, combobox_->selected_index()); 476 combobox_->SetSelectedIndex(2); 477 EXPECT_EQ(0, combobox_->selected_index()); 478 combobox_->SetSelectedIndex(3); 479 EXPECT_EQ(0, combobox_->selected_index()); 480} 481 482TEST_F(ComboboxTest, ListenerHandlesDelete) { 483 TestComboboxModel model; 484 485 // |combobox| will be deleted on change. 486 TestCombobox* combobox = new TestCombobox(&model); 487 scoped_ptr<EvilListener> evil_listener(new EvilListener()); 488 combobox->set_listener(evil_listener.get()); 489 ASSERT_NO_FATAL_FAILURE(combobox->ExecuteCommand(2)); 490 EXPECT_TRUE(evil_listener->deleted()); 491 492 // With STYLE_ACTION 493 // |combobox| will be deleted on change. 494 combobox = new TestCombobox(&model); 495 evil_listener.reset(new EvilListener()); 496 combobox->set_listener(evil_listener.get()); 497 combobox->SetStyle(Combobox::STYLE_ACTION); 498 ASSERT_NO_FATAL_FAILURE(combobox->ExecuteCommand(2)); 499 EXPECT_TRUE(evil_listener->deleted()); 500} 501 502TEST_F(ComboboxTest, Click) { 503 InitCombobox(); 504 505 TestComboboxListener listener; 506 combobox_->set_listener(&listener); 507 508 combobox_->Layout(); 509 510 // Click the left side. The menu is shown. 511 TestMenuRunnerHandler* test_menu_runner_handler = new TestMenuRunnerHandler(); 512 scoped_ptr<MenuRunnerHandler> menu_runner_handler(test_menu_runner_handler); 513 test::MenuRunnerTestAPI test_api( 514 combobox_->dropdown_list_menu_runner_.get()); 515 test_api.SetMenuRunnerHandler(menu_runner_handler.Pass()); 516 PerformClick(gfx::Point(combobox_->x() + 1, 517 combobox_->y() + combobox_->height() / 2)); 518 EXPECT_FALSE(listener.on_perform_action_called()); 519 EXPECT_TRUE(test_menu_runner_handler->executed()); 520} 521 522TEST_F(ComboboxTest, ClickButDisabled) { 523 InitCombobox(); 524 525 TestComboboxListener listener; 526 combobox_->set_listener(&listener); 527 528 combobox_->Layout(); 529 combobox_->SetEnabled(false); 530 531 // Click the left side, but nothing happens since the combobox is disabled. 532 TestMenuRunnerHandler* test_menu_runner_handler = new TestMenuRunnerHandler(); 533 scoped_ptr<MenuRunnerHandler> menu_runner_handler(test_menu_runner_handler); 534 test::MenuRunnerTestAPI test_api( 535 combobox_->dropdown_list_menu_runner_.get()); 536 test_api.SetMenuRunnerHandler(menu_runner_handler.Pass()); 537 PerformClick(gfx::Point(combobox_->x() + 1, 538 combobox_->y() + combobox_->height() / 2)); 539 EXPECT_FALSE(listener.on_perform_action_called()); 540 EXPECT_FALSE(test_menu_runner_handler->executed()); 541} 542 543TEST_F(ComboboxTest, NotifyOnClickWithReturnKey) { 544 InitCombobox(); 545 546 TestComboboxListener listener; 547 combobox_->set_listener(&listener); 548 549 // With STYLE_NORMAL, the click event is ignored. 550 SendKeyEvent(ui::VKEY_RETURN); 551 EXPECT_FALSE(listener.on_perform_action_called()); 552 553 // With STYLE_ACTION, the click event is notified. 554 combobox_->SetStyle(Combobox::STYLE_ACTION); 555 SendKeyEvent(ui::VKEY_RETURN); 556 EXPECT_TRUE(listener.on_perform_action_called()); 557 EXPECT_EQ(0, listener.perform_action_index()); 558} 559 560TEST_F(ComboboxTest, NotifyOnClickWithSpaceKey) { 561 InitCombobox(); 562 563 TestComboboxListener listener; 564 combobox_->set_listener(&listener); 565 566 // With STYLE_NORMAL, the click event is ignored. 567 SendKeyEvent(ui::VKEY_SPACE); 568 EXPECT_FALSE(listener.on_perform_action_called()); 569 SendKeyEventWithType(ui::VKEY_SPACE, ui::ET_KEY_RELEASED); 570 EXPECT_FALSE(listener.on_perform_action_called()); 571 572 // With STYLE_ACTION, the click event is notified after releasing. 573 combobox_->SetStyle(Combobox::STYLE_ACTION); 574 SendKeyEvent(ui::VKEY_SPACE); 575 EXPECT_FALSE(listener.on_perform_action_called()); 576 SendKeyEventWithType(ui::VKEY_SPACE, ui::ET_KEY_RELEASED); 577 EXPECT_TRUE(listener.on_perform_action_called()); 578 EXPECT_EQ(0, listener.perform_action_index()); 579} 580 581TEST_F(ComboboxTest, NotifyOnClickWithMouse) { 582 InitCombobox(); 583 584 TestComboboxListener listener; 585 combobox_->set_listener(&listener); 586 587 combobox_->SetStyle(Combobox::STYLE_ACTION); 588 combobox_->Layout(); 589 590 // Click the right side (arrow button). The menu is shown. 591 TestMenuRunnerHandler* test_menu_runner_handler = new TestMenuRunnerHandler(); 592 scoped_ptr<MenuRunnerHandler> menu_runner_handler(test_menu_runner_handler); 593 scoped_ptr<test::MenuRunnerTestAPI> test_api( 594 new test::MenuRunnerTestAPI(combobox_->dropdown_list_menu_runner_.get())); 595 test_api->SetMenuRunnerHandler(menu_runner_handler.Pass()); 596 597 PerformClick(gfx::Point(combobox_->x() + combobox_->width() - 1, 598 combobox_->y() + combobox_->height() / 2)); 599 EXPECT_FALSE(listener.on_perform_action_called()); 600 EXPECT_TRUE(test_menu_runner_handler->executed()); 601 602 // Click the left side (text button). The click event is notified. 603 test_menu_runner_handler = new TestMenuRunnerHandler(); 604 menu_runner_handler.reset(test_menu_runner_handler); 605 test_api.reset( 606 new test::MenuRunnerTestAPI(combobox_->dropdown_list_menu_runner_.get())); 607 test_api->SetMenuRunnerHandler(menu_runner_handler.Pass()); 608 PerformClick(gfx::Point(combobox_->x() + 1, 609 combobox_->y() + combobox_->height() / 2)); 610 EXPECT_TRUE(listener.on_perform_action_called()); 611 EXPECT_FALSE(test_menu_runner_handler->executed()); 612 EXPECT_EQ(0, listener.perform_action_index()); 613} 614 615TEST_F(ComboboxTest, ConsumingPressKeyEvents) { 616 InitCombobox(); 617 618 EXPECT_FALSE(combobox_->OnKeyPressed( 619 ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, 0, false))); 620 EXPECT_FALSE(combobox_->OnKeyPressed( 621 ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0, false))); 622 623 // When the combobox's style is STYLE_ACTION, pressing events of a space key 624 // or an enter key will be consumed. 625 combobox_->SetStyle(Combobox::STYLE_ACTION); 626 EXPECT_TRUE(combobox_->OnKeyPressed( 627 ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, 0, false))); 628 EXPECT_TRUE(combobox_->OnKeyPressed( 629 ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0, false))); 630} 631 632TEST_F(ComboboxTest, ContentWidth) { 633 std::vector<std::string> values; 634 VectorComboboxModel model(&values); 635 TestCombobox combobox(&model); 636 637 std::string long_item = "this is the long item"; 638 std::string short_item = "s"; 639 640 values.resize(1); 641 values[0] = long_item; 642 combobox.ModelChanged(); 643 644 const int long_item_width = combobox.content_size_.width(); 645 646 values[0] = short_item; 647 combobox.ModelChanged(); 648 649 const int short_item_width = combobox.content_size_.width(); 650 651 values.resize(2); 652 values[0] = short_item; 653 values[1] = long_item; 654 combobox.ModelChanged(); 655 656 // When the style is STYLE_NORMAL, the width will fit with the longest item. 657 combobox.SetStyle(Combobox::STYLE_NORMAL); 658 EXPECT_EQ(long_item_width, combobox.content_size_.width()); 659 660 // When the style is STYLE_ACTION, the width will fit with the first items' 661 // width. 662 combobox.SetStyle(Combobox::STYLE_ACTION); 663 EXPECT_EQ(short_item_width, combobox.content_size_.width()); 664} 665 666TEST_F(ComboboxTest, TypingPrefixNotifiesListener) { 667 InitCombobox(); 668 669 TestComboboxListener listener; 670 combobox_->set_listener(&listener); 671 672 // Type the first character of the second menu item ("JELLY"). 673 combobox_->GetTextInputClient()->InsertChar('J', ui::EF_NONE); 674 EXPECT_EQ(1, listener.actions_performed()); 675 EXPECT_EQ(1, listener.perform_action_index()); 676 677 // Type the second character of "JELLY", item shouldn't change and 678 // OnPerformAction() shouldn't be re-called. 679 combobox_->GetTextInputClient()->InsertChar('E', ui::EF_NONE); 680 EXPECT_EQ(1, listener.actions_performed()); 681 EXPECT_EQ(1, listener.perform_action_index()); 682 683 // Clears the typed text. 684 combobox_->OnBlur(); 685 686 // Type the first character of "PEANUT BUTTER", which should change the 687 // selected index and perform an action. 688 combobox_->GetTextInputClient()->InsertChar('P', ui::EF_NONE); 689 EXPECT_EQ(2, listener.actions_performed()); 690 EXPECT_EQ(2, listener.perform_action_index()); 691} 692 693} // namespace views 694