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