Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / views / controls / textfield / textfield_unittest.cc
blobd9b2db554e0c310daa03b3d5c05f997f66244847
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.
5 #include "ui/views/controls/textfield/textfield.h"
7 #include <set>
8 #include <string>
9 #include <vector>
11 #include "base/command_line.h"
12 #include "base/pickle.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "ui/accessibility/ax_view_state.h"
16 #include "ui/base/clipboard/clipboard.h"
17 #include "ui/base/clipboard/scoped_clipboard_writer.h"
18 #include "ui/base/dragdrop/drag_drop_types.h"
19 #include "ui/base/ime/input_method_base.h"
20 #include "ui/base/ime/input_method_delegate.h"
21 #include "ui/base/ime/input_method_factory.h"
22 #include "ui/base/ime/text_input_client.h"
23 #include "ui/base/l10n/l10n_util.h"
24 #include "ui/base/ui_base_switches.h"
25 #include "ui/base/ui_base_switches_util.h"
26 #include "ui/events/event.h"
27 #include "ui/events/event_processor.h"
28 #include "ui/events/event_utils.h"
29 #include "ui/events/keycodes/keyboard_codes.h"
30 #include "ui/gfx/render_text.h"
31 #include "ui/strings/grit/ui_strings.h"
32 #include "ui/views/controls/textfield/textfield_controller.h"
33 #include "ui/views/controls/textfield/textfield_model.h"
34 #include "ui/views/controls/textfield/textfield_test_api.h"
35 #include "ui/views/focus/focus_manager.h"
36 #include "ui/views/test/test_views_delegate.h"
37 #include "ui/views/test/views_test_base.h"
38 #include "ui/views/test/widget_test.h"
39 #include "ui/views/widget/widget.h"
40 #include "url/gurl.h"
42 #if defined(OS_WIN)
43 #include "base/win/windows_version.h"
44 #endif
46 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
47 #include "ui/events/linux/text_edit_key_bindings_delegate_auralinux.h"
48 #endif
50 #if defined(USE_X11)
51 #include "ui/events/event_utils.h"
52 #endif
54 using base::ASCIIToUTF16;
55 using base::UTF8ToUTF16;
56 using base::WideToUTF16;
58 #define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(ASCIIToUTF16(ascii), utf16)
60 namespace {
62 const base::char16 kHebrewLetterSamekh = 0x05E1;
64 class MockInputMethod : public ui::InputMethodBase {
65 public:
66 MockInputMethod();
67 ~MockInputMethod() override;
69 // Overridden from InputMethod:
70 bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
71 NativeEventResult* result) override;
72 bool DispatchKeyEvent(const ui::KeyEvent& key) override;
73 void OnTextInputTypeChanged(const ui::TextInputClient* client) override;
74 void OnCaretBoundsChanged(const ui::TextInputClient* client) override {}
75 void CancelComposition(const ui::TextInputClient* client) override;
76 void OnInputLocaleChanged() override {}
77 std::string GetInputLocale() override;
78 bool IsCandidatePopupOpen() const override;
79 void ShowImeIfNeeded() override {}
81 bool untranslated_ime_message_called() const {
82 return untranslated_ime_message_called_;
84 bool text_input_type_changed() const { return text_input_type_changed_; }
85 bool cancel_composition_called() const { return cancel_composition_called_; }
87 // Clears all internal states and result.
88 void Clear();
90 void SetCompositionTextForNextKey(const ui::CompositionText& composition);
91 void SetResultTextForNextKey(const base::string16& result);
93 private:
94 // Overridden from InputMethodBase.
95 void OnWillChangeFocusedClient(ui::TextInputClient* focused_before,
96 ui::TextInputClient* focused) override;
98 // Clears boolean states defined below.
99 void ClearStates();
101 // Whether a mock composition or result is scheduled for the next key event.
102 bool HasComposition();
104 // Clears only composition information and result text.
105 void ClearComposition();
107 // Composition information for the next key event. It'll be cleared
108 // automatically after dispatching the next key event.
109 ui::CompositionText composition_;
111 // Result text for the next key event. It'll be cleared automatically after
112 // dispatching the next key event.
113 base::string16 result_text_;
115 // Record call state of corresponding methods. They will be set to false
116 // automatically before dispatching a key event.
117 bool untranslated_ime_message_called_;
118 bool text_input_type_changed_;
119 bool cancel_composition_called_;
121 DISALLOW_COPY_AND_ASSIGN(MockInputMethod);
124 MockInputMethod::MockInputMethod()
125 : untranslated_ime_message_called_(false),
126 text_input_type_changed_(false),
127 cancel_composition_called_(false) {
130 MockInputMethod::~MockInputMethod() {
133 bool MockInputMethod::OnUntranslatedIMEMessage(const base::NativeEvent& event,
134 NativeEventResult* result) {
135 if (result)
136 *result = NativeEventResult();
137 return false;
140 bool MockInputMethod::DispatchKeyEvent(const ui::KeyEvent& key) {
141 // Checks whether the key event is from EventGenerator on Windows which will
142 // generate key event for WM_CHAR.
143 // The MockInputMethod will insert char on WM_KEYDOWN so ignore WM_CHAR here.
144 if (key.is_char() && key.HasNativeEvent())
145 return true;
147 bool handled = !IsTextInputTypeNone() && HasComposition();
148 ClearStates();
149 if (handled) {
150 DCHECK(!key.is_char());
151 ui::KeyEvent mock_key(ui::ET_KEY_PRESSED, ui::VKEY_PROCESSKEY, key.flags());
152 DispatchKeyEventPostIME(mock_key);
153 } else {
154 DispatchKeyEventPostIME(key);
157 ui::TextInputClient* client = GetTextInputClient();
158 if (client) {
159 if (handled) {
160 if (result_text_.length())
161 client->InsertText(result_text_);
162 if (composition_.text.length())
163 client->SetCompositionText(composition_);
164 else
165 client->ClearCompositionText();
166 } else if (key.type() == ui::ET_KEY_PRESSED) {
167 base::char16 ch = key.GetCharacter();
168 if (ch)
169 client->InsertChar(ch, key.flags());
173 ClearComposition();
174 return true;
177 void MockInputMethod::OnTextInputTypeChanged(
178 const ui::TextInputClient* client) {
179 if (IsTextInputClientFocused(client))
180 text_input_type_changed_ = true;
181 InputMethodBase::OnTextInputTypeChanged(client);
184 void MockInputMethod::CancelComposition(const ui::TextInputClient* client) {
185 if (IsTextInputClientFocused(client)) {
186 cancel_composition_called_ = true;
187 ClearComposition();
191 std::string MockInputMethod::GetInputLocale() {
192 return "en-US";
195 bool MockInputMethod::IsCandidatePopupOpen() const {
196 return false;
199 void MockInputMethod::OnWillChangeFocusedClient(
200 ui::TextInputClient* focused_before,
201 ui::TextInputClient* focused) {
202 ui::TextInputClient* client = GetTextInputClient();
203 if (client && client->HasCompositionText())
204 client->ConfirmCompositionText();
205 ClearComposition();
208 void MockInputMethod::Clear() {
209 ClearStates();
210 ClearComposition();
213 void MockInputMethod::SetCompositionTextForNextKey(
214 const ui::CompositionText& composition) {
215 composition_ = composition;
218 void MockInputMethod::SetResultTextForNextKey(const base::string16& result) {
219 result_text_ = result;
222 void MockInputMethod::ClearStates() {
223 untranslated_ime_message_called_ = false;
224 text_input_type_changed_ = false;
225 cancel_composition_called_ = false;
228 bool MockInputMethod::HasComposition() {
229 return composition_.text.length() || result_text_.length();
232 void MockInputMethod::ClearComposition() {
233 composition_.Clear();
234 result_text_.clear();
237 // A Textfield wrapper to intercept OnKey[Pressed|Released]() ressults.
238 class TestTextfield : public views::Textfield {
239 public:
240 TestTextfield()
241 : Textfield(),
242 key_handled_(false),
243 key_received_(false),
244 weak_ptr_factory_(this) {}
246 bool OnKeyPressed(const ui::KeyEvent& e) override {
247 key_received_ = true;
249 // Since OnKeyPressed() might destroy |this|, get a weak pointer and
250 // verify it isn't null before writing the bool value to key_handled_.
251 base::WeakPtr<TestTextfield> textfield(weak_ptr_factory_.GetWeakPtr());
252 bool key = views::Textfield::OnKeyPressed(e);
254 if (!textfield)
255 return key;
257 key_handled_ = key;
259 return key_handled_;
262 bool OnKeyReleased(const ui::KeyEvent& e) override {
263 key_received_ = true;
264 key_handled_ = views::Textfield::OnKeyReleased(e);
265 EXPECT_FALSE(key_handled_); // Textfield doesn't override OnKeyReleased.
266 return key_handled_;
269 // ui::TextInputClient overrides:
270 void InsertChar(base::char16 ch, int flags) override {
271 views::Textfield::InsertChar(ch, flags);
272 #if defined(OS_MACOSX)
273 // On Mac, characters are inserted directly rather than attempting to get a
274 // unicode character from the ui::KeyEvent (which isn't always possible).
275 key_received_ = true;
276 #endif
279 bool key_handled() const { return key_handled_; }
280 bool key_received() const { return key_received_; }
282 void clear() { key_received_ = key_handled_ = false; }
284 private:
285 bool key_handled_;
286 bool key_received_;
288 base::WeakPtrFactory<TestTextfield> weak_ptr_factory_;
290 DISALLOW_COPY_AND_ASSIGN(TestTextfield);
293 // Convenience to make constructing a GestureEvent simpler.
294 class GestureEventForTest : public ui::GestureEvent {
295 public:
296 GestureEventForTest(int x, int y, ui::GestureEventDetails details)
297 : GestureEvent(x, y, 0, base::TimeDelta(), details) {}
299 private:
300 DISALLOW_COPY_AND_ASSIGN(GestureEventForTest);
303 // This controller will happily destroy the target textfield passed on
304 // construction when a key event is triggered.
305 class TextfieldDestroyerController : public views::TextfieldController {
306 public:
307 explicit TextfieldDestroyerController(views::Textfield* target)
308 : target_(target) {
309 target_->set_controller(this);
312 views::Textfield* target() { return target_.get(); }
314 // views::TextfieldController:
315 bool HandleKeyEvent(views::Textfield* sender,
316 const ui::KeyEvent& key_event) override {
317 target_->OnBlur();
318 target_.reset();
319 return false;
322 private:
323 scoped_ptr<views::Textfield> target_;
326 base::string16 GetClipboardText(ui::ClipboardType type) {
327 base::string16 text;
328 ui::Clipboard::GetForCurrentThread()->ReadText(type, &text);
329 return text;
332 void SetClipboardText(ui::ClipboardType type, const std::string& text) {
333 ui::ScopedClipboardWriter(type).WriteText(ASCIIToUTF16(text));
336 } // namespace
338 namespace views {
340 class TextfieldTest : public ViewsTestBase, public TextfieldController {
341 public:
342 TextfieldTest()
343 : widget_(NULL),
344 textfield_(NULL),
345 model_(NULL),
346 input_method_(NULL),
347 on_before_user_action_(0),
348 on_after_user_action_(0),
349 copied_to_clipboard_(ui::CLIPBOARD_TYPE_LAST) {
350 input_method_ = new MockInputMethod();
351 ui::SetUpInputMethodForTesting(input_method_);
354 // ::testing::Test:
355 void TearDown() override {
356 if (widget_)
357 widget_->Close();
358 ViewsTestBase::TearDown();
361 ui::ClipboardType GetAndResetCopiedToClipboard() {
362 ui::ClipboardType clipboard_type = copied_to_clipboard_;
363 copied_to_clipboard_ = ui::CLIPBOARD_TYPE_LAST;
364 return clipboard_type;
367 // TextfieldController:
368 void ContentsChanged(Textfield* sender,
369 const base::string16& new_contents) override {
370 // Paste calls TextfieldController::ContentsChanged() explicitly even if the
371 // paste action did not change the content. So |new_contents| may match
372 // |last_contents_|. For more info, see http://crbug.com/79002
373 last_contents_ = new_contents;
376 void OnBeforeUserAction(Textfield* sender) override {
377 ++on_before_user_action_;
380 void OnAfterUserAction(Textfield* sender) override {
381 ++on_after_user_action_;
384 void OnAfterCutOrCopy(ui::ClipboardType clipboard_type) override {
385 copied_to_clipboard_ = clipboard_type;
388 void InitTextfield() {
389 InitTextfields(1);
392 void InitTextfields(int count) {
393 ASSERT_FALSE(textfield_);
394 textfield_ = new TestTextfield();
395 textfield_->set_controller(this);
396 widget_ = new Widget();
398 // The widget type must be an activatable type, and we don't want to worry
399 // about the non-client view, which leaves just TYPE_WINDOW_FRAMELESS.
400 Widget::InitParams params =
401 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
403 params.bounds = gfx::Rect(100, 100, 100, 100);
404 widget_->Init(params);
405 input_method_->SetDelegate(
406 test::WidgetTest::GetInputMethodDelegateForWidget(widget_));
407 View* container = new View();
408 widget_->SetContentsView(container);
409 container->AddChildView(textfield_);
410 textfield_->SetBoundsRect(params.bounds);
411 textfield_->set_id(1);
412 test_api_.reset(new TextfieldTestApi(textfield_));
414 for (int i = 1; i < count; i++) {
415 Textfield* textfield = new Textfield();
416 container->AddChildView(textfield);
417 textfield->set_id(i + 1);
420 model_ = test_api_->model();
421 model_->ClearEditHistory();
423 // Since the window type is activatable, showing the widget will also
424 // activate it. Calling Activate directly is insufficient, since that does
425 // not also _focus_ an aura::Window (i.e. using the FocusClient). Both the
426 // widget and the textfield must have focus to properly handle input.
427 widget_->Show();
428 textfield_->RequestFocus();
430 // On Mac, activation is asynchronous since desktop widgets are used. We
431 // don't want parallel tests to steal active status either, so fake it.
432 #if defined(OS_MACOSX) && !defined(USE_AURA)
433 fake_activation_ = test::WidgetTest::FakeWidgetIsActiveAlways();
434 #endif
437 ui::MenuModel* GetContextMenuModel() {
438 test_api_->UpdateContextMenu();
439 return test_api_->context_menu_contents();
442 // True if native Mac keystrokes should be used (to avoid ifdef litter).
443 bool TestingNativeMac() {
444 #if defined(OS_MACOSX)
445 return true;
446 #else
447 return false;
448 #endif
451 protected:
452 void SendKeyEvent(ui::KeyboardCode key_code,
453 bool alt,
454 bool shift,
455 bool control_or_command,
456 bool caps_lock) {
457 bool control = control_or_command;
458 bool command = false;
460 // By default, swap control and command for native events on Mac. This
461 // handles most cases.
462 if (TestingNativeMac())
463 std::swap(control, command);
465 int flags = (alt ? ui::EF_ALT_DOWN : 0) | (shift ? ui::EF_SHIFT_DOWN : 0) |
466 (control ? ui::EF_CONTROL_DOWN : 0) |
467 (command ? ui::EF_COMMAND_DOWN : 0) |
468 (caps_lock ? ui::EF_CAPS_LOCK_DOWN : 0);
470 // TODO(shuchen): making EventGenerator support input method and using
471 // EventGenerator here. crbug.com/512315.
472 ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, flags);
473 input_method_->DispatchKeyEvent(event);
476 void SendKeyEvent(ui::KeyboardCode key_code,
477 bool shift,
478 bool control_or_command) {
479 SendKeyEvent(key_code, false, shift, control_or_command, false);
482 void SendKeyEvent(ui::KeyboardCode key_code) {
483 SendKeyEvent(key_code, false, false);
486 void SendKeyEvent(base::char16 ch) {
487 if (ch < 0x80) {
488 ui::KeyboardCode code =
489 ch == ' ' ? ui::VKEY_SPACE :
490 static_cast<ui::KeyboardCode>(ui::VKEY_A + ch - 'a');
491 SendKeyEvent(code);
492 } else {
493 // For unicode characters, assume they come from IME rather than the
494 // keyboard. So they are dispatched directly to the input method.
495 ui::KeyEvent event(ch, ui::VKEY_UNKNOWN, ui::EF_NONE);
496 input_method_->DispatchKeyEvent(event);
500 // Sends a platform-specific move (and select) to start of line.
501 void SendHomeEvent(bool shift) {
502 if (TestingNativeMac()) {
503 // Use Cmd+Left on native Mac. An RTL-agnostic "end" doesn't have a
504 // default key-binding on Mac.
505 SendKeyEvent(ui::VKEY_LEFT, shift /* shift */, true /* command */);
506 return;
508 SendKeyEvent(ui::VKEY_HOME, shift /* shift */, false /* control */);
511 // Sends a platform-specific move (and select) to end of line.
512 void SendEndEvent(bool shift) {
513 if (TestingNativeMac()) {
514 SendKeyEvent(ui::VKEY_RIGHT, shift, true); // Cmd+Right.
515 return;
517 SendKeyEvent(ui::VKEY_END, shift, false);
520 // Sends {delete, move, select} word {forward, backward}.
521 void SendWordEvent(ui::KeyboardCode key, bool shift) {
522 bool alt = false;
523 bool control = true;
524 bool caps = false;
525 if (TestingNativeMac()) {
526 // Use Alt+Left/Right/Backspace on native Mac.
527 alt = true;
528 control = false;
530 SendKeyEvent(key, alt, shift, control, caps);
533 // Sends Shift+Delete if supported, otherwise Cmd+X again.
534 void SendAlternateCut() {
535 if (TestingNativeMac())
536 SendKeyEvent(ui::VKEY_X, false, true);
537 else
538 SendKeyEvent(ui::VKEY_DELETE, true, false);
541 // Sends Ctrl+Insert if supported, otherwise Cmd+C again.
542 void SendAlternateCopy() {
543 if (TestingNativeMac())
544 SendKeyEvent(ui::VKEY_C, false, true);
545 else
546 SendKeyEvent(ui::VKEY_INSERT, false, true);
549 // Sends Shift+Insert if supported, otherwise Cmd+V again.
550 void SendAlternatePaste() {
551 if (TestingNativeMac())
552 SendKeyEvent(ui::VKEY_V, false, true);
553 else
554 SendKeyEvent(ui::VKEY_INSERT, true, false);
557 View* GetFocusedView() {
558 return widget_->GetFocusManager()->GetFocusedView();
561 int GetCursorPositionX(int cursor_pos) {
562 return test_api_->GetRenderText()->GetCursorBounds(
563 gfx::SelectionModel(cursor_pos, gfx::CURSOR_FORWARD), false).x();
566 // Get the current cursor bounds.
567 gfx::Rect GetCursorBounds() {
568 return test_api_->GetRenderText()->GetUpdatedCursorBounds();
571 // Get the cursor bounds of |sel|.
572 gfx::Rect GetCursorBounds(const gfx::SelectionModel& sel) {
573 return test_api_->GetRenderText()->GetCursorBounds(sel, true);
576 gfx::Rect GetDisplayRect() {
577 return test_api_->GetRenderText()->display_rect();
580 // Mouse click on the point whose x-axis is |bound|'s x plus |x_offset| and
581 // y-axis is in the middle of |bound|'s vertical range.
582 void MouseClick(const gfx::Rect bound, int x_offset) {
583 gfx::Point point(bound.x() + x_offset, bound.y() + bound.height() / 2);
584 ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point,
585 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
586 ui::EF_LEFT_MOUSE_BUTTON);
587 textfield_->OnMousePressed(click);
588 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point,
589 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
590 ui::EF_LEFT_MOUSE_BUTTON);
591 textfield_->OnMouseReleased(release);
594 // This is to avoid double/triple click.
595 void NonClientMouseClick() {
596 ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
597 ui::EventTimeForNow(),
598 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT,
599 ui::EF_LEFT_MOUSE_BUTTON);
600 textfield_->OnMousePressed(click);
601 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
602 ui::EventTimeForNow(),
603 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT,
604 ui::EF_LEFT_MOUSE_BUTTON);
605 textfield_->OnMouseReleased(release);
608 void VerifyTextfieldContextMenuContents(bool textfield_has_selection,
609 bool can_undo,
610 ui::MenuModel* menu) {
611 EXPECT_EQ(can_undo, menu->IsEnabledAt(0 /* UNDO */));
612 EXPECT_TRUE(menu->IsEnabledAt(1 /* Separator */));
613 EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(2 /* CUT */));
614 EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(3 /* COPY */));
615 EXPECT_NE(GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE).empty(),
616 menu->IsEnabledAt(4 /* PASTE */));
617 EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(5 /* DELETE */));
618 EXPECT_TRUE(menu->IsEnabledAt(6 /* Separator */));
619 EXPECT_TRUE(menu->IsEnabledAt(7 /* SELECT ALL */));
622 // We need widget to populate wrapper class.
623 Widget* widget_;
625 TestTextfield* textfield_;
626 scoped_ptr<TextfieldTestApi> test_api_;
627 TextfieldModel* model_;
629 // The string from Controller::ContentsChanged callback.
630 base::string16 last_contents_;
632 // For testing input method related behaviors.
633 MockInputMethod* input_method_;
635 // Indicates how many times OnBeforeUserAction() is called.
636 int on_before_user_action_;
638 // Indicates how many times OnAfterUserAction() is called.
639 int on_after_user_action_;
641 private:
642 ui::ClipboardType copied_to_clipboard_;
643 scoped_ptr<test::WidgetTest::FakeActivation> fake_activation_;
645 DISALLOW_COPY_AND_ASSIGN(TextfieldTest);
648 TEST_F(TextfieldTest, ModelChangesTest) {
649 InitTextfield();
651 // TextfieldController::ContentsChanged() shouldn't be called when changing
652 // text programmatically.
653 last_contents_.clear();
654 textfield_->SetText(ASCIIToUTF16("this is"));
656 EXPECT_STR_EQ("this is", model_->text());
657 EXPECT_STR_EQ("this is", textfield_->text());
658 EXPECT_TRUE(last_contents_.empty());
660 textfield_->AppendText(ASCIIToUTF16(" a test"));
661 EXPECT_STR_EQ("this is a test", model_->text());
662 EXPECT_STR_EQ("this is a test", textfield_->text());
663 EXPECT_TRUE(last_contents_.empty());
665 EXPECT_EQ(base::string16(), textfield_->GetSelectedText());
666 textfield_->SelectAll(false);
667 EXPECT_STR_EQ("this is a test", textfield_->GetSelectedText());
668 EXPECT_TRUE(last_contents_.empty());
671 TEST_F(TextfieldTest, KeyTest) {
672 InitTextfield();
673 // Event flags: key, alt, shift, ctrl, caps-lock.
674 SendKeyEvent(ui::VKEY_T, false, true, false, false);
675 SendKeyEvent(ui::VKEY_E, false, false, false, false);
676 SendKeyEvent(ui::VKEY_X, false, true, false, true);
677 SendKeyEvent(ui::VKEY_T, false, false, false, true);
678 SendKeyEvent(ui::VKEY_1, false, true, false, false);
679 SendKeyEvent(ui::VKEY_1, false, false, false, false);
680 SendKeyEvent(ui::VKEY_1, false, true, false, true);
681 SendKeyEvent(ui::VKEY_1, false, false, false, true);
683 // On Mac, Caps+Shift remains uppercase.
684 if (TestingNativeMac())
685 EXPECT_STR_EQ("TeXT!1!1", textfield_->text());
686 else
687 EXPECT_STR_EQ("TexT!1!1", textfield_->text());
690 TEST_F(TextfieldTest, ControlAndSelectTest) {
691 // Insert a test string in a textfield.
692 InitTextfield();
693 textfield_->SetText(ASCIIToUTF16("one two three"));
694 SendHomeEvent(false);
695 SendKeyEvent(ui::VKEY_RIGHT, true, false);
696 SendKeyEvent(ui::VKEY_RIGHT, true, false);
697 SendKeyEvent(ui::VKEY_RIGHT, true, false);
699 EXPECT_STR_EQ("one", textfield_->GetSelectedText());
701 // Test word select.
702 SendWordEvent(ui::VKEY_RIGHT, true);
703 EXPECT_STR_EQ("one two", textfield_->GetSelectedText());
704 SendWordEvent(ui::VKEY_RIGHT, true);
705 EXPECT_STR_EQ("one two three", textfield_->GetSelectedText());
706 SendWordEvent(ui::VKEY_LEFT, true);
707 EXPECT_STR_EQ("one two ", textfield_->GetSelectedText());
708 SendWordEvent(ui::VKEY_LEFT, true);
709 EXPECT_STR_EQ("one ", textfield_->GetSelectedText());
711 // Replace the selected text.
712 SendKeyEvent(ui::VKEY_Z, true, false);
713 SendKeyEvent(ui::VKEY_E, true, false);
714 SendKeyEvent(ui::VKEY_R, true, false);
715 SendKeyEvent(ui::VKEY_O, true, false);
716 SendKeyEvent(ui::VKEY_SPACE, false, false);
717 EXPECT_STR_EQ("ZERO two three", textfield_->text());
719 SendEndEvent(true);
720 EXPECT_STR_EQ("two three", textfield_->GetSelectedText());
721 SendHomeEvent(true);
722 EXPECT_STR_EQ("ZERO ", textfield_->GetSelectedText());
725 TEST_F(TextfieldTest, InsertionDeletionTest) {
726 // Insert a test string in a textfield.
727 InitTextfield();
728 for (size_t i = 0; i < 10; i++)
729 SendKeyEvent(static_cast<ui::KeyboardCode>(ui::VKEY_A + i));
730 EXPECT_STR_EQ("abcdefghij", textfield_->text());
732 // Test the delete and backspace keys.
733 textfield_->SelectRange(gfx::Range(5));
734 for (int i = 0; i < 3; i++)
735 SendKeyEvent(ui::VKEY_BACK);
736 EXPECT_STR_EQ("abfghij", textfield_->text());
737 for (int i = 0; i < 3; i++)
738 SendKeyEvent(ui::VKEY_DELETE);
739 EXPECT_STR_EQ("abij", textfield_->text());
741 // Select all and replace with "k".
742 textfield_->SelectAll(false);
743 SendKeyEvent(ui::VKEY_K);
744 EXPECT_STR_EQ("k", textfield_->text());
746 // Delete the previous word from cursor.
747 bool shift = false;
748 textfield_->SetText(ASCIIToUTF16("one two three four"));
749 SendEndEvent(shift);
750 SendWordEvent(ui::VKEY_BACK, shift);
751 EXPECT_STR_EQ("one two three ", textfield_->text());
753 // Delete to a line break on Linux and ChromeOS, to a word break on Windows
754 // and Mac.
755 SendWordEvent(ui::VKEY_LEFT, shift);
756 shift = true;
757 SendWordEvent(ui::VKEY_BACK, shift);
758 #if defined(OS_LINUX)
759 EXPECT_STR_EQ("three ", textfield_->text());
760 #else
761 EXPECT_STR_EQ("one three ", textfield_->text());
762 #endif
764 // Delete the next word from cursor.
765 textfield_->SetText(ASCIIToUTF16("one two three four"));
766 shift = false;
767 SendHomeEvent(shift);
768 SendWordEvent(ui::VKEY_DELETE, shift);
769 EXPECT_STR_EQ(" two three four", textfield_->text());
771 // Delete to a line break on Linux and ChromeOS, to a word break on Windows
772 // and Mac.
773 SendWordEvent(ui::VKEY_RIGHT, shift);
774 shift = true;
775 SendWordEvent(ui::VKEY_DELETE, shift);
776 #if defined(OS_LINUX)
777 EXPECT_STR_EQ(" two", textfield_->text());
778 #else
779 EXPECT_STR_EQ(" two four", textfield_->text());
780 #endif
783 TEST_F(TextfieldTest, PasswordTest) {
784 InitTextfield();
785 textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
786 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType());
787 EXPECT_TRUE(textfield_->enabled());
788 EXPECT_TRUE(textfield_->IsFocusable());
790 last_contents_.clear();
791 textfield_->SetText(ASCIIToUTF16("password"));
792 // Ensure text() and the callback returns the actual text instead of "*".
793 EXPECT_STR_EQ("password", textfield_->text());
794 EXPECT_TRUE(last_contents_.empty());
795 model_->SelectAll(false);
796 SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "foo");
798 // Cut and copy should be disabled.
799 EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_CUT));
800 textfield_->ExecuteCommand(IDS_APP_CUT, 0);
801 SendKeyEvent(ui::VKEY_X, false, true);
802 EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_COPY));
803 textfield_->ExecuteCommand(IDS_APP_COPY, 0);
804 SendKeyEvent(ui::VKEY_C, false, true);
805 SendAlternateCopy();
806 EXPECT_STR_EQ("foo", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
807 EXPECT_STR_EQ("password", textfield_->text());
808 // [Shift]+[Delete] should just delete without copying text to the clipboard.
809 textfield_->SelectAll(false);
810 SendKeyEvent(ui::VKEY_DELETE, true, false);
812 // Paste should work normally.
813 EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE));
814 textfield_->ExecuteCommand(IDS_APP_PASTE, 0);
815 SendKeyEvent(ui::VKEY_V, false, true);
816 SendAlternatePaste();
817 EXPECT_STR_EQ("foo", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
818 EXPECT_STR_EQ("foofoofoo", textfield_->text());
821 TEST_F(TextfieldTest, TextInputType) {
822 InitTextfield();
824 // Defaults to TEXT
825 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, textfield_->GetTextInputType());
827 // And can be set.
828 textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_URL);
829 EXPECT_EQ(ui::TEXT_INPUT_TYPE_URL, textfield_->GetTextInputType());
830 textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
831 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType());
833 // Readonly textfields have type NONE
834 textfield_->SetReadOnly(true);
835 EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, textfield_->GetTextInputType());
837 textfield_->SetReadOnly(false);
838 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType());
840 // As do disabled textfields
841 textfield_->SetEnabled(false);
842 EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, textfield_->GetTextInputType());
844 textfield_->SetEnabled(true);
845 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType());
848 TEST_F(TextfieldTest, OnKeyPress) {
849 InitTextfield();
851 // Character keys are handled by the input method.
852 SendKeyEvent(ui::VKEY_A);
853 EXPECT_TRUE(textfield_->key_received());
854 EXPECT_FALSE(textfield_->key_handled());
855 textfield_->clear();
857 // Arrow keys and home/end are handled by the textfield.
858 SendKeyEvent(ui::VKEY_LEFT);
859 EXPECT_TRUE(textfield_->key_received());
860 EXPECT_TRUE(textfield_->key_handled());
861 textfield_->clear();
863 SendKeyEvent(ui::VKEY_RIGHT);
864 EXPECT_TRUE(textfield_->key_received());
865 EXPECT_TRUE(textfield_->key_handled());
866 textfield_->clear();
868 const bool shift = false;
869 SendHomeEvent(shift);
870 EXPECT_TRUE(textfield_->key_received());
871 EXPECT_TRUE(textfield_->key_handled());
872 textfield_->clear();
874 SendEndEvent(shift);
875 EXPECT_TRUE(textfield_->key_received());
876 EXPECT_TRUE(textfield_->key_handled());
877 textfield_->clear();
879 // F20, up/down key won't be handled.
880 SendKeyEvent(ui::VKEY_F20);
881 #if defined(OS_MACOSX)
882 // On Mac, key combinations that don't map to editing commands are forwarded
883 // on to the next responder, usually ending up at the window, which will beep.
884 EXPECT_FALSE(textfield_->key_received());
885 #else
886 EXPECT_TRUE(textfield_->key_received());
887 #endif
888 EXPECT_FALSE(textfield_->key_handled());
889 textfield_->clear();
891 SendKeyEvent(ui::VKEY_UP);
892 EXPECT_TRUE(textfield_->key_received());
893 EXPECT_FALSE(textfield_->key_handled());
894 textfield_->clear();
896 SendKeyEvent(ui::VKEY_DOWN);
897 EXPECT_TRUE(textfield_->key_received());
898 EXPECT_FALSE(textfield_->key_handled());
899 textfield_->clear();
902 // Tests that default key bindings are handled even with a delegate installed.
903 TEST_F(TextfieldTest, OnKeyPressBinding) {
904 InitTextfield();
906 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
907 // Install a TextEditKeyBindingsDelegateAuraLinux that does nothing.
908 class TestDelegate : public ui::TextEditKeyBindingsDelegateAuraLinux {
909 public:
910 TestDelegate() {}
911 ~TestDelegate() override {}
913 bool MatchEvent(
914 const ui::Event& event,
915 std::vector<ui::TextEditCommandAuraLinux>* commands) override {
916 return false;
919 private:
920 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
923 TestDelegate delegate;
924 ui::SetTextEditKeyBindingsDelegate(&delegate);
925 #endif
927 SendKeyEvent(ui::VKEY_A, false, false);
928 EXPECT_STR_EQ("a", textfield_->text());
929 textfield_->clear();
931 // Undo/Redo command keys are handled by the textfield.
932 SendKeyEvent(ui::VKEY_Z, false, true);
933 EXPECT_TRUE(textfield_->key_received());
934 EXPECT_TRUE(textfield_->key_handled());
935 EXPECT_TRUE(textfield_->text().empty());
936 textfield_->clear();
938 SendKeyEvent(ui::VKEY_Z, true, true);
939 EXPECT_TRUE(textfield_->key_received());
940 EXPECT_TRUE(textfield_->key_handled());
941 EXPECT_STR_EQ("a", textfield_->text());
942 textfield_->clear();
944 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
945 ui::SetTextEditKeyBindingsDelegate(NULL);
946 #endif
949 TEST_F(TextfieldTest, CursorMovement) {
950 InitTextfield();
952 // Test with trailing whitespace.
953 textfield_->SetText(ASCIIToUTF16("one two hre "));
955 // Send the cursor at the end.
956 SendKeyEvent(ui::VKEY_END);
958 // Ctrl+Left should move the cursor just before the last word.
959 const bool shift = false;
960 SendWordEvent(ui::VKEY_LEFT, shift);
961 SendKeyEvent(ui::VKEY_T);
962 EXPECT_STR_EQ("one two thre ", textfield_->text());
963 EXPECT_STR_EQ("one two thre ", last_contents_);
965 // Ctrl+Right should move the cursor to the end of the last word.
966 SendWordEvent(ui::VKEY_RIGHT, shift);
967 SendKeyEvent(ui::VKEY_E);
968 EXPECT_STR_EQ("one two three ", textfield_->text());
969 EXPECT_STR_EQ("one two three ", last_contents_);
971 // Ctrl+Right again should move the cursor to the end.
972 SendWordEvent(ui::VKEY_RIGHT, shift);
973 SendKeyEvent(ui::VKEY_BACK);
974 EXPECT_STR_EQ("one two three", textfield_->text());
975 EXPECT_STR_EQ("one two three", last_contents_);
977 // Test with leading whitespace.
978 textfield_->SetText(ASCIIToUTF16(" ne two"));
980 // Send the cursor at the beginning.
981 SendHomeEvent(shift);
983 // Ctrl+Right, then Ctrl+Left should move the cursor to the beginning of the
984 // first word.
985 SendWordEvent(ui::VKEY_RIGHT, shift);
986 SendWordEvent(ui::VKEY_LEFT, shift);
987 SendKeyEvent(ui::VKEY_O);
988 EXPECT_STR_EQ(" one two", textfield_->text());
989 EXPECT_STR_EQ(" one two", last_contents_);
991 // Ctrl+Left to move the cursor to the beginning of the first word.
992 SendWordEvent(ui::VKEY_LEFT, shift);
993 // Ctrl+Left again should move the cursor back to the very beginning.
994 SendWordEvent(ui::VKEY_LEFT, shift);
995 SendKeyEvent(ui::VKEY_DELETE);
996 EXPECT_STR_EQ("one two", textfield_->text());
997 EXPECT_STR_EQ("one two", last_contents_);
1000 TEST_F(TextfieldTest, FocusTraversalTest) {
1001 InitTextfields(3);
1002 textfield_->RequestFocus();
1004 EXPECT_EQ(1, GetFocusedView()->id());
1005 widget_->GetFocusManager()->AdvanceFocus(false);
1006 EXPECT_EQ(2, GetFocusedView()->id());
1007 widget_->GetFocusManager()->AdvanceFocus(false);
1008 EXPECT_EQ(3, GetFocusedView()->id());
1009 // Cycle back to the first textfield.
1010 widget_->GetFocusManager()->AdvanceFocus(false);
1011 EXPECT_EQ(1, GetFocusedView()->id());
1013 widget_->GetFocusManager()->AdvanceFocus(true);
1014 EXPECT_EQ(3, GetFocusedView()->id());
1015 widget_->GetFocusManager()->AdvanceFocus(true);
1016 EXPECT_EQ(2, GetFocusedView()->id());
1017 widget_->GetFocusManager()->AdvanceFocus(true);
1018 EXPECT_EQ(1, GetFocusedView()->id());
1019 // Cycle back to the last textfield.
1020 widget_->GetFocusManager()->AdvanceFocus(true);
1021 EXPECT_EQ(3, GetFocusedView()->id());
1023 // Request focus should still work.
1024 textfield_->RequestFocus();
1025 EXPECT_EQ(1, GetFocusedView()->id());
1027 // Test if clicking on textfield view sets the focus.
1028 widget_->GetFocusManager()->AdvanceFocus(true);
1029 EXPECT_EQ(3, GetFocusedView()->id());
1030 ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
1031 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
1032 ui::EF_LEFT_MOUSE_BUTTON);
1033 textfield_->OnMousePressed(click);
1034 EXPECT_EQ(1, GetFocusedView()->id());
1036 // Tab/Shift+Tab should also cycle focus, not insert a tab character.
1037 SendKeyEvent(ui::VKEY_TAB, false, false);
1038 EXPECT_EQ(2, GetFocusedView()->id());
1039 SendKeyEvent(ui::VKEY_TAB, false, false);
1040 EXPECT_EQ(3, GetFocusedView()->id());
1041 // Cycle back to the first textfield.
1042 SendKeyEvent(ui::VKEY_TAB, false, false);
1043 EXPECT_EQ(1, GetFocusedView()->id());
1045 SendKeyEvent(ui::VKEY_TAB, true, false);
1046 EXPECT_EQ(3, GetFocusedView()->id());
1047 SendKeyEvent(ui::VKEY_TAB, true, false);
1048 EXPECT_EQ(2, GetFocusedView()->id());
1049 SendKeyEvent(ui::VKEY_TAB, true, false);
1050 EXPECT_EQ(1, GetFocusedView()->id());
1051 // Cycle back to the last textfield.
1052 SendKeyEvent(ui::VKEY_TAB, true, false);
1053 EXPECT_EQ(3, GetFocusedView()->id());
1056 TEST_F(TextfieldTest, ContextMenuDisplayTest) {
1057 InitTextfield();
1058 EXPECT_TRUE(textfield_->context_menu_controller());
1059 textfield_->SetText(ASCIIToUTF16("hello world"));
1060 ui::Clipboard::GetForCurrentThread()->Clear(ui::CLIPBOARD_TYPE_COPY_PASTE);
1061 textfield_->ClearEditHistory();
1062 EXPECT_TRUE(GetContextMenuModel());
1063 VerifyTextfieldContextMenuContents(false, false, GetContextMenuModel());
1065 textfield_->SelectAll(false);
1066 VerifyTextfieldContextMenuContents(true, false, GetContextMenuModel());
1068 SendKeyEvent(ui::VKEY_T);
1069 VerifyTextfieldContextMenuContents(false, true, GetContextMenuModel());
1071 textfield_->SelectAll(false);
1072 VerifyTextfieldContextMenuContents(true, true, GetContextMenuModel());
1074 // Exercise the "paste enabled?" check in the verifier.
1075 SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
1076 VerifyTextfieldContextMenuContents(true, true, GetContextMenuModel());
1079 TEST_F(TextfieldTest, DoubleAndTripleClickTest) {
1080 InitTextfield();
1081 textfield_->SetText(ASCIIToUTF16("hello world"));
1082 ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
1083 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
1084 ui::EF_LEFT_MOUSE_BUTTON);
1085 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
1086 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
1087 ui::EF_LEFT_MOUSE_BUTTON);
1088 ui::MouseEvent double_click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
1089 ui::EventTimeForNow(),
1090 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK,
1091 ui::EF_LEFT_MOUSE_BUTTON);
1093 // Test for double click.
1094 textfield_->OnMousePressed(click);
1095 textfield_->OnMouseReleased(release);
1096 EXPECT_TRUE(textfield_->GetSelectedText().empty());
1097 textfield_->OnMousePressed(double_click);
1098 textfield_->OnMouseReleased(release);
1099 EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
1101 // Test for triple click.
1102 textfield_->OnMousePressed(click);
1103 textfield_->OnMouseReleased(release);
1104 EXPECT_STR_EQ("hello world", textfield_->GetSelectedText());
1106 // Another click should reset back to double click.
1107 textfield_->OnMousePressed(click);
1108 textfield_->OnMouseReleased(release);
1109 EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
1112 TEST_F(TextfieldTest, DragToSelect) {
1113 InitTextfield();
1114 textfield_->SetText(ASCIIToUTF16("hello world"));
1115 const int kStart = GetCursorPositionX(5);
1116 const int kEnd = 500;
1117 gfx::Point start_point(kStart, 0);
1118 gfx::Point end_point(kEnd, 0);
1119 ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, start_point, start_point,
1120 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
1121 ui::EF_LEFT_MOUSE_BUTTON);
1122 ui::MouseEvent click_b(ui::ET_MOUSE_PRESSED, end_point, end_point,
1123 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
1124 ui::EF_LEFT_MOUSE_BUTTON);
1125 ui::MouseEvent drag_left(ui::ET_MOUSE_DRAGGED, gfx::Point(), gfx::Point(),
1126 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
1127 ui::MouseEvent drag_right(ui::ET_MOUSE_DRAGGED, end_point, end_point,
1128 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
1129 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, end_point, end_point,
1130 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
1131 ui::EF_LEFT_MOUSE_BUTTON);
1132 textfield_->OnMousePressed(click_a);
1133 EXPECT_TRUE(textfield_->GetSelectedText().empty());
1134 // Check that dragging left selects the beginning of the string.
1135 textfield_->OnMouseDragged(drag_left);
1136 base::string16 text_left = textfield_->GetSelectedText();
1137 EXPECT_STR_EQ("hello", text_left);
1138 // Check that dragging right selects the rest of the string.
1139 textfield_->OnMouseDragged(drag_right);
1140 base::string16 text_right = textfield_->GetSelectedText();
1141 EXPECT_STR_EQ(" world", text_right);
1142 // Check that releasing in the same location does not alter the selection.
1143 textfield_->OnMouseReleased(release);
1144 EXPECT_EQ(text_right, textfield_->GetSelectedText());
1145 // Check that dragging from beyond the text length works too.
1146 textfield_->OnMousePressed(click_b);
1147 textfield_->OnMouseDragged(drag_left);
1148 textfield_->OnMouseReleased(release);
1149 EXPECT_EQ(textfield_->text(), textfield_->GetSelectedText());
1152 #if defined(OS_WIN)
1153 TEST_F(TextfieldTest, DragAndDrop_AcceptDrop) {
1154 InitTextfield();
1155 textfield_->SetText(ASCIIToUTF16("hello world"));
1157 ui::OSExchangeData data;
1158 base::string16 string(ASCIIToUTF16("string "));
1159 data.SetString(string);
1160 int formats = 0;
1161 std::set<OSExchangeData::CustomFormat> custom_formats;
1163 // Ensure that disabled textfields do not accept drops.
1164 textfield_->SetEnabled(false);
1165 EXPECT_FALSE(textfield_->GetDropFormats(&formats, &custom_formats));
1166 EXPECT_EQ(0, formats);
1167 EXPECT_TRUE(custom_formats.empty());
1168 EXPECT_FALSE(textfield_->CanDrop(data));
1169 textfield_->SetEnabled(true);
1171 // Ensure that read-only textfields do not accept drops.
1172 textfield_->SetReadOnly(true);
1173 EXPECT_FALSE(textfield_->GetDropFormats(&formats, &custom_formats));
1174 EXPECT_EQ(0, formats);
1175 EXPECT_TRUE(custom_formats.empty());
1176 EXPECT_FALSE(textfield_->CanDrop(data));
1177 textfield_->SetReadOnly(false);
1179 // Ensure that enabled and editable textfields do accept drops.
1180 EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats));
1181 EXPECT_EQ(ui::OSExchangeData::STRING, formats);
1182 EXPECT_TRUE(custom_formats.empty());
1183 EXPECT_TRUE(textfield_->CanDrop(data));
1184 gfx::Point drop_point(GetCursorPositionX(6), 0);
1185 ui::DropTargetEvent drop(data, drop_point, drop_point,
1186 ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE);
1187 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE,
1188 textfield_->OnDragUpdated(drop));
1189 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, textfield_->OnPerformDrop(drop));
1190 EXPECT_STR_EQ("hello string world", textfield_->text());
1192 // Ensure that textfields do not accept non-OSExchangeData::STRING types.
1193 ui::OSExchangeData bad_data;
1194 bad_data.SetFilename(base::FilePath(FILE_PATH_LITERAL("x")));
1195 ui::OSExchangeData::CustomFormat fmt = ui::Clipboard::GetBitmapFormatType();
1196 bad_data.SetPickledData(fmt, base::Pickle());
1197 bad_data.SetFileContents(base::FilePath(L"x"), "x");
1198 bad_data.SetHtml(base::string16(ASCIIToUTF16("x")), GURL("x.org"));
1199 ui::OSExchangeData::DownloadFileInfo download(base::FilePath(), NULL);
1200 bad_data.SetDownloadFileInfo(download);
1201 EXPECT_FALSE(textfield_->CanDrop(bad_data));
1203 #endif
1205 TEST_F(TextfieldTest, DragAndDrop_InitiateDrag) {
1206 InitTextfield();
1207 textfield_->SetText(ASCIIToUTF16("hello string world"));
1209 // Ensure the textfield will provide selected text for drag data.
1210 base::string16 string;
1211 ui::OSExchangeData data;
1212 const gfx::Range kStringRange(6, 12);
1213 textfield_->SelectRange(kStringRange);
1214 const gfx::Point kStringPoint(GetCursorPositionX(9), 0);
1215 textfield_->WriteDragDataForView(NULL, kStringPoint, &data);
1216 EXPECT_TRUE(data.GetString(&string));
1217 EXPECT_EQ(textfield_->GetSelectedText(), string);
1219 // Ensure that disabled textfields do not support drag operations.
1220 textfield_->SetEnabled(false);
1221 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
1222 textfield_->GetDragOperationsForView(NULL, kStringPoint));
1223 textfield_->SetEnabled(true);
1224 // Ensure that textfields without selections do not support drag operations.
1225 textfield_->ClearSelection();
1226 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
1227 textfield_->GetDragOperationsForView(NULL, kStringPoint));
1228 textfield_->SelectRange(kStringRange);
1229 // Ensure that password textfields do not support drag operations.
1230 textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
1231 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
1232 textfield_->GetDragOperationsForView(NULL, kStringPoint));
1233 textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT);
1234 // Ensure that textfields only initiate drag operations inside the selection.
1235 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, kStringPoint, kStringPoint,
1236 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
1237 ui::EF_LEFT_MOUSE_BUTTON);
1238 textfield_->OnMousePressed(press_event);
1239 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
1240 textfield_->GetDragOperationsForView(NULL, gfx::Point()));
1241 EXPECT_FALSE(textfield_->CanStartDragForView(NULL, gfx::Point(),
1242 gfx::Point()));
1243 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY,
1244 textfield_->GetDragOperationsForView(NULL, kStringPoint));
1245 EXPECT_TRUE(textfield_->CanStartDragForView(NULL, kStringPoint,
1246 gfx::Point()));
1247 // Ensure that textfields support local moves.
1248 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
1249 textfield_->GetDragOperationsForView(textfield_, kStringPoint));
1252 TEST_F(TextfieldTest, DragAndDrop_ToTheRight) {
1253 InitTextfield();
1254 textfield_->SetText(ASCIIToUTF16("hello world"));
1256 base::string16 string;
1257 ui::OSExchangeData data;
1258 int formats = 0;
1259 int operations = 0;
1260 std::set<OSExchangeData::CustomFormat> custom_formats;
1262 // Start dragging "ello".
1263 textfield_->SelectRange(gfx::Range(1, 5));
1264 gfx::Point point(GetCursorPositionX(3), 0);
1265 ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point,
1266 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
1267 ui::EF_LEFT_MOUSE_BUTTON);
1268 textfield_->OnMousePressed(click_a);
1269 EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, click_a.location(),
1270 gfx::Point()));
1271 operations = textfield_->GetDragOperationsForView(textfield_,
1272 click_a.location());
1273 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
1274 operations);
1275 textfield_->WriteDragDataForView(NULL, click_a.location(), &data);
1276 EXPECT_TRUE(data.GetString(&string));
1277 EXPECT_EQ(textfield_->GetSelectedText(), string);
1278 EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats));
1279 EXPECT_EQ(ui::OSExchangeData::STRING, formats);
1280 EXPECT_TRUE(custom_formats.empty());
1282 // Drop "ello" after "w".
1283 const gfx::Point kDropPoint(GetCursorPositionX(7), 0);
1284 EXPECT_TRUE(textfield_->CanDrop(data));
1285 ui::DropTargetEvent drop_a(data, kDropPoint, kDropPoint, operations);
1286 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a));
1287 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnPerformDrop(drop_a));
1288 EXPECT_STR_EQ("h welloorld", textfield_->text());
1289 textfield_->OnDragDone();
1291 // Undo/Redo the drag&drop change.
1292 SendKeyEvent(ui::VKEY_Z, false, true);
1293 EXPECT_STR_EQ("hello world", textfield_->text());
1294 SendKeyEvent(ui::VKEY_Z, false, true);
1295 EXPECT_STR_EQ("", textfield_->text());
1296 SendKeyEvent(ui::VKEY_Z, false, true);
1297 EXPECT_STR_EQ("", textfield_->text());
1298 SendKeyEvent(ui::VKEY_Z, true, true);
1299 EXPECT_STR_EQ("hello world", textfield_->text());
1300 SendKeyEvent(ui::VKEY_Z, true, true);
1301 EXPECT_STR_EQ("h welloorld", textfield_->text());
1302 SendKeyEvent(ui::VKEY_Z, true, true);
1303 EXPECT_STR_EQ("h welloorld", textfield_->text());
1306 TEST_F(TextfieldTest, DragAndDrop_ToTheLeft) {
1307 InitTextfield();
1308 textfield_->SetText(ASCIIToUTF16("hello world"));
1310 base::string16 string;
1311 ui::OSExchangeData data;
1312 int formats = 0;
1313 int operations = 0;
1314 std::set<OSExchangeData::CustomFormat> custom_formats;
1316 // Start dragging " worl".
1317 textfield_->SelectRange(gfx::Range(5, 10));
1318 gfx::Point point(GetCursorPositionX(7), 0);
1319 ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point,
1320 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
1321 ui::EF_LEFT_MOUSE_BUTTON);
1322 textfield_->OnMousePressed(click_a);
1323 EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, click_a.location(),
1324 gfx::Point()));
1325 operations = textfield_->GetDragOperationsForView(textfield_,
1326 click_a.location());
1327 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
1328 operations);
1329 textfield_->WriteDragDataForView(NULL, click_a.location(), &data);
1330 EXPECT_TRUE(data.GetString(&string));
1331 EXPECT_EQ(textfield_->GetSelectedText(), string);
1332 EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats));
1333 EXPECT_EQ(ui::OSExchangeData::STRING, formats);
1334 EXPECT_TRUE(custom_formats.empty());
1336 // Drop " worl" after "h".
1337 EXPECT_TRUE(textfield_->CanDrop(data));
1338 gfx::Point drop_point(GetCursorPositionX(1), 0);
1339 ui::DropTargetEvent drop_a(data, drop_point, drop_point, operations);
1340 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a));
1341 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnPerformDrop(drop_a));
1342 EXPECT_STR_EQ("h worlellod", textfield_->text());
1343 textfield_->OnDragDone();
1345 // Undo/Redo the drag&drop change.
1346 SendKeyEvent(ui::VKEY_Z, false, true);
1347 EXPECT_STR_EQ("hello world", textfield_->text());
1348 SendKeyEvent(ui::VKEY_Z, false, true);
1349 EXPECT_STR_EQ("", textfield_->text());
1350 SendKeyEvent(ui::VKEY_Z, false, true);
1351 EXPECT_STR_EQ("", textfield_->text());
1352 SendKeyEvent(ui::VKEY_Z, true, true);
1353 EXPECT_STR_EQ("hello world", textfield_->text());
1354 SendKeyEvent(ui::VKEY_Z, true, true);
1355 EXPECT_STR_EQ("h worlellod", textfield_->text());
1356 SendKeyEvent(ui::VKEY_Z, true, true);
1357 EXPECT_STR_EQ("h worlellod", textfield_->text());
1360 TEST_F(TextfieldTest, DragAndDrop_Canceled) {
1361 InitTextfield();
1362 textfield_->SetText(ASCIIToUTF16("hello world"));
1364 // Start dragging "worl".
1365 textfield_->SelectRange(gfx::Range(6, 10));
1366 gfx::Point point(GetCursorPositionX(8), 0);
1367 ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point,
1368 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
1369 ui::EF_LEFT_MOUSE_BUTTON);
1370 textfield_->OnMousePressed(click);
1371 ui::OSExchangeData data;
1372 textfield_->WriteDragDataForView(NULL, click.location(), &data);
1373 EXPECT_TRUE(textfield_->CanDrop(data));
1374 // Drag the text over somewhere valid, outside the current selection.
1375 gfx::Point drop_point(GetCursorPositionX(2), 0);
1376 ui::DropTargetEvent drop(data, drop_point, drop_point,
1377 ui::DragDropTypes::DRAG_MOVE);
1378 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop));
1379 // "Cancel" the drag, via move and release over the selection, and OnDragDone.
1380 gfx::Point drag_point(GetCursorPositionX(9), 0);
1381 ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, drag_point, drag_point,
1382 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
1383 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, drag_point, drag_point,
1384 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
1385 ui::EF_LEFT_MOUSE_BUTTON);
1386 textfield_->OnMouseDragged(drag);
1387 textfield_->OnMouseReleased(release);
1388 textfield_->OnDragDone();
1389 EXPECT_EQ(ASCIIToUTF16("hello world"), textfield_->text());
1392 TEST_F(TextfieldTest, ReadOnlyTest) {
1393 InitTextfield();
1394 textfield_->SetText(ASCIIToUTF16("read only"));
1395 textfield_->SetReadOnly(true);
1396 EXPECT_TRUE(textfield_->enabled());
1397 EXPECT_TRUE(textfield_->IsFocusable());
1399 bool shift = false;
1400 SendHomeEvent(shift);
1401 EXPECT_EQ(0U, textfield_->GetCursorPosition());
1402 SendEndEvent(shift);
1403 EXPECT_EQ(9U, textfield_->GetCursorPosition());
1405 SendKeyEvent(ui::VKEY_LEFT, shift, false);
1406 EXPECT_EQ(8U, textfield_->GetCursorPosition());
1407 SendWordEvent(ui::VKEY_LEFT, shift);
1408 EXPECT_EQ(5U, textfield_->GetCursorPosition());
1409 shift = true;
1410 SendWordEvent(ui::VKEY_LEFT, shift);
1411 EXPECT_EQ(0U, textfield_->GetCursorPosition());
1412 EXPECT_STR_EQ("read ", textfield_->GetSelectedText());
1413 textfield_->SelectAll(false);
1414 EXPECT_STR_EQ("read only", textfield_->GetSelectedText());
1416 // Cut should be disabled.
1417 SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
1418 EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_CUT));
1419 textfield_->ExecuteCommand(IDS_APP_CUT, 0);
1420 SendKeyEvent(ui::VKEY_X, false, true);
1421 SendAlternateCut();
1422 EXPECT_STR_EQ("Test", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
1423 EXPECT_STR_EQ("read only", textfield_->text());
1425 // Paste should be disabled.
1426 EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE));
1427 textfield_->ExecuteCommand(IDS_APP_PASTE, 0);
1428 SendKeyEvent(ui::VKEY_V, false, true);
1429 SendAlternatePaste();
1430 EXPECT_STR_EQ("read only", textfield_->text());
1432 // Copy should work normally.
1433 SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
1434 EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_COPY));
1435 textfield_->ExecuteCommand(IDS_APP_COPY, 0);
1436 EXPECT_STR_EQ("read only", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
1437 SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
1438 SendKeyEvent(ui::VKEY_C, false, true);
1439 EXPECT_STR_EQ("read only", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
1440 SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
1441 SendAlternateCopy();
1442 EXPECT_STR_EQ("read only", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
1444 // SetText should work even in read only mode.
1445 textfield_->SetText(ASCIIToUTF16(" four five six "));
1446 EXPECT_STR_EQ(" four five six ", textfield_->text());
1448 textfield_->SelectAll(false);
1449 EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
1451 // Text field is unmodifiable and selection shouldn't change.
1452 SendKeyEvent(ui::VKEY_DELETE);
1453 EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
1454 SendKeyEvent(ui::VKEY_BACK);
1455 EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
1456 SendKeyEvent(ui::VKEY_T);
1457 EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
1460 TEST_F(TextfieldTest, TextInputClientTest) {
1461 InitTextfield();
1462 ui::TextInputClient* client = textfield_;
1463 EXPECT_TRUE(client);
1464 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, client->GetTextInputType());
1466 textfield_->SetText(ASCIIToUTF16("0123456789"));
1467 gfx::Range range;
1468 EXPECT_TRUE(client->GetTextRange(&range));
1469 EXPECT_EQ(0U, range.start());
1470 EXPECT_EQ(10U, range.end());
1472 EXPECT_TRUE(client->SetSelectionRange(gfx::Range(1, 4)));
1473 EXPECT_TRUE(client->GetSelectionRange(&range));
1474 EXPECT_EQ(gfx::Range(1, 4), range);
1476 base::string16 substring;
1477 EXPECT_TRUE(client->GetTextFromRange(range, &substring));
1478 EXPECT_STR_EQ("123", substring);
1480 EXPECT_TRUE(client->DeleteRange(range));
1481 EXPECT_STR_EQ("0456789", textfield_->text());
1483 ui::CompositionText composition;
1484 composition.text = UTF8ToUTF16("321");
1485 // Set composition through input method.
1486 input_method_->Clear();
1487 input_method_->SetCompositionTextForNextKey(composition);
1488 textfield_->clear();
1490 on_before_user_action_ = on_after_user_action_ = 0;
1492 // Send a key to trigger MockInputMethod::DispatchKeyEvent(). Note the
1493 // specific VKEY isn't used (MockInputMethod will mock a ui::VKEY_PROCESSKEY
1494 // whenever it has a test composition). However, on Mac, it can't be a letter
1495 // (e.g. VKEY_A) since all native character events on Mac are unicode events
1496 // and don't have a meaningful ui::KeyEvent that would trigger
1497 // DispatchKeyEvent().
1498 SendKeyEvent(ui::VKEY_RETURN);
1500 EXPECT_TRUE(textfield_->key_received());
1501 EXPECT_FALSE(textfield_->key_handled());
1502 EXPECT_TRUE(client->HasCompositionText());
1503 EXPECT_TRUE(client->GetCompositionTextRange(&range));
1504 EXPECT_STR_EQ("0321456789", textfield_->text());
1505 EXPECT_EQ(gfx::Range(1, 4), range);
1506 EXPECT_EQ(1, on_before_user_action_);
1507 EXPECT_EQ(1, on_after_user_action_);
1509 input_method_->SetResultTextForNextKey(UTF8ToUTF16("123"));
1510 on_before_user_action_ = on_after_user_action_ = 0;
1511 textfield_->clear();
1512 SendKeyEvent(ui::VKEY_RETURN);
1513 EXPECT_TRUE(textfield_->key_received());
1514 EXPECT_FALSE(textfield_->key_handled());
1515 EXPECT_FALSE(client->HasCompositionText());
1516 EXPECT_FALSE(input_method_->cancel_composition_called());
1517 EXPECT_STR_EQ("0123456789", textfield_->text());
1518 EXPECT_EQ(1, on_before_user_action_);
1519 EXPECT_EQ(1, on_after_user_action_);
1521 input_method_->Clear();
1522 input_method_->SetCompositionTextForNextKey(composition);
1523 textfield_->clear();
1524 SendKeyEvent(ui::VKEY_RETURN);
1525 EXPECT_TRUE(client->HasCompositionText());
1526 EXPECT_STR_EQ("0123321456789", textfield_->text());
1528 on_before_user_action_ = on_after_user_action_ = 0;
1529 textfield_->clear();
1530 SendKeyEvent(ui::VKEY_RIGHT);
1531 EXPECT_FALSE(client->HasCompositionText());
1532 EXPECT_TRUE(input_method_->cancel_composition_called());
1533 EXPECT_TRUE(textfield_->key_received());
1534 EXPECT_TRUE(textfield_->key_handled());
1535 EXPECT_STR_EQ("0123321456789", textfield_->text());
1536 EXPECT_EQ(8U, textfield_->GetCursorPosition());
1537 EXPECT_EQ(1, on_before_user_action_);
1538 EXPECT_EQ(1, on_after_user_action_);
1540 textfield_->clear();
1541 textfield_->SetText(ASCIIToUTF16("0123456789"));
1542 EXPECT_TRUE(client->SetSelectionRange(gfx::Range(5, 5)));
1543 client->ExtendSelectionAndDelete(4, 2);
1544 EXPECT_STR_EQ("0789", textfield_->text());
1546 // On{Before,After}UserAction should be called by whatever user action
1547 // triggers clearing or setting a selection if appropriate.
1548 on_before_user_action_ = on_after_user_action_ = 0;
1549 textfield_->clear();
1550 textfield_->ClearSelection();
1551 textfield_->SelectAll(false);
1552 EXPECT_EQ(0, on_before_user_action_);
1553 EXPECT_EQ(0, on_after_user_action_);
1555 input_method_->Clear();
1557 // Changing the Textfield to readonly shouldn't change the input client, since
1558 // it's still required for selections and clipboard copy.
1559 ui::TextInputClient* text_input_client = textfield_;
1560 EXPECT_TRUE(text_input_client);
1561 EXPECT_NE(ui::TEXT_INPUT_TYPE_NONE, text_input_client->GetTextInputType());
1562 textfield_->SetReadOnly(true);
1563 EXPECT_TRUE(input_method_->text_input_type_changed());
1564 EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, text_input_client->GetTextInputType());
1566 input_method_->Clear();
1567 textfield_->SetReadOnly(false);
1568 EXPECT_TRUE(input_method_->text_input_type_changed());
1569 EXPECT_NE(ui::TEXT_INPUT_TYPE_NONE, text_input_client->GetTextInputType());
1571 input_method_->Clear();
1572 textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
1573 EXPECT_TRUE(input_method_->text_input_type_changed());
1576 TEST_F(TextfieldTest, UndoRedoTest) {
1577 InitTextfield();
1578 SendKeyEvent(ui::VKEY_A);
1579 EXPECT_STR_EQ("a", textfield_->text());
1580 SendKeyEvent(ui::VKEY_Z, false, true);
1581 EXPECT_STR_EQ("", textfield_->text());
1582 SendKeyEvent(ui::VKEY_Z, false, true);
1583 EXPECT_STR_EQ("", textfield_->text());
1584 SendKeyEvent(ui::VKEY_Z, true, true);
1585 EXPECT_STR_EQ("a", textfield_->text());
1586 SendKeyEvent(ui::VKEY_Z, true, true);
1587 EXPECT_STR_EQ("a", textfield_->text());
1589 // AppendText
1590 textfield_->AppendText(ASCIIToUTF16("b"));
1591 last_contents_.clear(); // AppendText doesn't call ContentsChanged.
1592 EXPECT_STR_EQ("ab", textfield_->text());
1593 SendKeyEvent(ui::VKEY_Z, false, true);
1594 EXPECT_STR_EQ("a", textfield_->text());
1595 SendKeyEvent(ui::VKEY_Z, true, true);
1596 EXPECT_STR_EQ("ab", textfield_->text());
1598 // SetText
1599 SendKeyEvent(ui::VKEY_C);
1600 // Undo'ing append moves the cursor to the end for now.
1601 // A no-op SetText won't add a new edit; see TextfieldModel::SetText.
1602 EXPECT_STR_EQ("abc", textfield_->text());
1603 textfield_->SetText(ASCIIToUTF16("abc"));
1604 EXPECT_STR_EQ("abc", textfield_->text());
1605 SendKeyEvent(ui::VKEY_Z, false, true);
1606 EXPECT_STR_EQ("ab", textfield_->text());
1607 SendKeyEvent(ui::VKEY_Z, true, true);
1608 EXPECT_STR_EQ("abc", textfield_->text());
1609 SendKeyEvent(ui::VKEY_Z, true, true);
1610 EXPECT_STR_EQ("abc", textfield_->text());
1611 textfield_->SetText(ASCIIToUTF16("123"));
1612 textfield_->SetText(ASCIIToUTF16("123"));
1613 EXPECT_STR_EQ("123", textfield_->text());
1614 SendKeyEvent(ui::VKEY_END, false, false);
1615 SendKeyEvent(ui::VKEY_4, false, false);
1616 EXPECT_STR_EQ("1234", textfield_->text());
1617 last_contents_.clear();
1618 SendKeyEvent(ui::VKEY_Z, false, true);
1619 EXPECT_STR_EQ("123", textfield_->text());
1620 SendKeyEvent(ui::VKEY_Z, false, true);
1621 // the insert edit "c" and set edit "123" are merged to single edit,
1622 // so text becomes "ab" after undo.
1623 EXPECT_STR_EQ("ab", textfield_->text());
1624 SendKeyEvent(ui::VKEY_Z, false, true);
1625 EXPECT_STR_EQ("a", textfield_->text());
1626 SendKeyEvent(ui::VKEY_Z, true, true);
1627 EXPECT_STR_EQ("ab", textfield_->text());
1628 SendKeyEvent(ui::VKEY_Z, true, true);
1629 EXPECT_STR_EQ("123", textfield_->text());
1630 SendKeyEvent(ui::VKEY_Z, true, true);
1631 EXPECT_STR_EQ("1234", textfield_->text());
1633 // Undoing to the same text shouldn't call ContentsChanged.
1634 SendKeyEvent(ui::VKEY_A, false, true); // select all
1635 SendKeyEvent(ui::VKEY_A);
1636 EXPECT_STR_EQ("a", textfield_->text());
1637 SendKeyEvent(ui::VKEY_B);
1638 SendKeyEvent(ui::VKEY_C);
1639 EXPECT_STR_EQ("abc", textfield_->text());
1640 SendKeyEvent(ui::VKEY_Z, false, true);
1641 EXPECT_STR_EQ("1234", textfield_->text());
1642 SendKeyEvent(ui::VKEY_Z, true, true);
1643 EXPECT_STR_EQ("abc", textfield_->text());
1645 // Delete/Backspace
1646 SendKeyEvent(ui::VKEY_BACK);
1647 EXPECT_STR_EQ("ab", textfield_->text());
1648 SendHomeEvent(false);
1649 SendKeyEvent(ui::VKEY_DELETE);
1650 EXPECT_STR_EQ("b", textfield_->text());
1651 SendKeyEvent(ui::VKEY_A, false, true);
1652 SendKeyEvent(ui::VKEY_DELETE);
1653 EXPECT_STR_EQ("", textfield_->text());
1654 SendKeyEvent(ui::VKEY_Z, false, true);
1655 EXPECT_STR_EQ("b", textfield_->text());
1656 SendKeyEvent(ui::VKEY_Z, false, true);
1657 EXPECT_STR_EQ("ab", textfield_->text());
1658 SendKeyEvent(ui::VKEY_Z, false, true);
1659 EXPECT_STR_EQ("abc", textfield_->text());
1660 SendKeyEvent(ui::VKEY_Z, true, true);
1661 EXPECT_STR_EQ("ab", textfield_->text());
1662 SendKeyEvent(ui::VKEY_Z, true, true);
1663 EXPECT_STR_EQ("b", textfield_->text());
1664 SendKeyEvent(ui::VKEY_Z, true, true);
1665 EXPECT_STR_EQ("", textfield_->text());
1666 SendKeyEvent(ui::VKEY_Z, true, true);
1667 EXPECT_STR_EQ("", textfield_->text());
1670 // Most platforms support Ctrl+Y as an alternative to Ctrl+Shift+Z, but on Mac
1671 // that is bound to "Show full history", so is not mapped as an editing
1672 // command. So, on Mac, send Cmd+Shift+Z.
1673 #if !defined(OS_MACOSX)
1675 // Test that Ctrl+Y works for Redo, as well as Ctrl+Shift+Z.
1676 TEST_F(TextfieldTest, RedoWithCtrlY) {
1677 InitTextfield();
1678 SendKeyEvent(ui::VKEY_A);
1679 EXPECT_STR_EQ("a", textfield_->text());
1680 SendKeyEvent(ui::VKEY_Z, false, true);
1681 EXPECT_STR_EQ("", textfield_->text());
1682 SendKeyEvent(ui::VKEY_Y, false, true);
1683 EXPECT_STR_EQ("a", textfield_->text());
1684 SendKeyEvent(ui::VKEY_Z, false, true);
1685 EXPECT_STR_EQ("", textfield_->text());
1686 SendKeyEvent(ui::VKEY_Z, true, true);
1687 EXPECT_STR_EQ("a", textfield_->text());
1690 #endif // !defined(OS_MACOSX)
1692 TEST_F(TextfieldTest, CutCopyPaste) {
1693 InitTextfield();
1695 // Ensure IDS_APP_CUT cuts.
1696 textfield_->SetText(ASCIIToUTF16("123"));
1697 textfield_->SelectAll(false);
1698 EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_CUT));
1699 textfield_->ExecuteCommand(IDS_APP_CUT, 0);
1700 EXPECT_STR_EQ("123", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
1701 EXPECT_STR_EQ("", textfield_->text());
1702 EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
1704 // Ensure [Ctrl]+[x] cuts and [Ctrl]+[Alt][x] does nothing.
1705 textfield_->SetText(ASCIIToUTF16("456"));
1706 textfield_->SelectAll(false);
1707 SendKeyEvent(ui::VKEY_X, true, false, true, false);
1708 EXPECT_STR_EQ("123", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
1709 EXPECT_STR_EQ("456", textfield_->text());
1710 EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
1711 SendKeyEvent(ui::VKEY_X, false, true);
1712 EXPECT_STR_EQ("456", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
1713 EXPECT_STR_EQ("", textfield_->text());
1714 EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
1716 // Ensure [Shift]+[Delete] cuts.
1717 textfield_->SetText(ASCIIToUTF16("123"));
1718 textfield_->SelectAll(false);
1719 SendAlternateCut();
1720 EXPECT_STR_EQ("123", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
1721 EXPECT_STR_EQ("", textfield_->text());
1722 EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
1724 // Ensure IDS_APP_COPY copies.
1725 textfield_->SetText(ASCIIToUTF16("789"));
1726 textfield_->SelectAll(false);
1727 EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_COPY));
1728 textfield_->ExecuteCommand(IDS_APP_COPY, 0);
1729 EXPECT_STR_EQ("789", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
1730 EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
1732 // Ensure [Ctrl]+[c] copies and [Ctrl]+[Alt][c] does nothing.
1733 textfield_->SetText(ASCIIToUTF16("012"));
1734 textfield_->SelectAll(false);
1735 SendKeyEvent(ui::VKEY_C, true, false, true, false);
1736 EXPECT_STR_EQ("789", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
1737 EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
1738 SendKeyEvent(ui::VKEY_C, false, true);
1739 EXPECT_STR_EQ("012", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
1740 EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
1742 // Ensure [Ctrl]+[Insert] copies.
1743 textfield_->SetText(ASCIIToUTF16("345"));
1744 textfield_->SelectAll(false);
1745 SendAlternateCopy();
1746 EXPECT_STR_EQ("345", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
1747 EXPECT_STR_EQ("345", textfield_->text());
1748 EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
1750 // Ensure IDS_APP_PASTE, [Ctrl]+[V], and [Shift]+[Insert] pastes;
1751 // also ensure that [Ctrl]+[Alt]+[V] does nothing.
1752 SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "abc");
1753 textfield_->SetText(base::string16());
1754 EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE));
1755 textfield_->ExecuteCommand(IDS_APP_PASTE, 0);
1756 EXPECT_STR_EQ("abc", textfield_->text());
1757 SendKeyEvent(ui::VKEY_V, false, true);
1758 EXPECT_STR_EQ("abcabc", textfield_->text());
1759 SendAlternatePaste();
1760 EXPECT_STR_EQ("abcabcabc", textfield_->text());
1761 SendKeyEvent(ui::VKEY_V, true, false, true, false);
1762 EXPECT_STR_EQ("abcabcabc", textfield_->text());
1764 // Ensure [Ctrl]+[Shift]+[Insert] is a no-op.
1765 textfield_->SelectAll(false);
1766 SendKeyEvent(ui::VKEY_INSERT, true, true);
1767 EXPECT_STR_EQ("abc", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
1768 EXPECT_STR_EQ("abcabcabc", textfield_->text());
1769 EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
1772 TEST_F(TextfieldTest, OvertypeMode) {
1773 InitTextfield();
1774 // Overtype mode should be disabled (no-op [Insert]).
1775 textfield_->SetText(ASCIIToUTF16("2"));
1776 const bool shift = false;
1777 SendHomeEvent(shift);
1778 // Note: On Mac, there is no insert key. Insert sends kVK_Help. Currently,
1779 // since there is no overtype on toolkit-views, the behavior happens to match.
1780 // However, there's no enable-overtype equivalent key combination on OSX.
1781 SendKeyEvent(ui::VKEY_INSERT);
1782 SendKeyEvent(ui::VKEY_1, false, false);
1783 EXPECT_STR_EQ("12", textfield_->text());
1786 TEST_F(TextfieldTest, TextCursorDisplayTest) {
1787 InitTextfield();
1788 // LTR-RTL string in LTR context.
1789 SendKeyEvent('a');
1790 EXPECT_STR_EQ("a", textfield_->text());
1791 int x = GetCursorBounds().x();
1792 int prev_x = x;
1794 SendKeyEvent('b');
1795 EXPECT_STR_EQ("ab", textfield_->text());
1796 x = GetCursorBounds().x();
1797 EXPECT_LT(prev_x, x);
1798 prev_x = x;
1800 SendKeyEvent(0x05E1);
1801 EXPECT_EQ(WideToUTF16(L"ab\x05E1"), textfield_->text());
1802 x = GetCursorBounds().x();
1803 EXPECT_GE(1, std::abs(x - prev_x));
1805 SendKeyEvent(0x05E2);
1806 EXPECT_EQ(WideToUTF16(L"ab\x05E1\x5E2"), textfield_->text());
1807 x = GetCursorBounds().x();
1808 EXPECT_GE(1, std::abs(x - prev_x));
1810 // Clear text.
1811 SendKeyEvent(ui::VKEY_A, false, true);
1812 SendKeyEvent(ui::VKEY_DELETE);
1814 // RTL-LTR string in LTR context.
1815 SendKeyEvent(0x05E1);
1816 EXPECT_EQ(WideToUTF16(L"\x05E1"), textfield_->text());
1817 x = GetCursorBounds().x();
1818 EXPECT_EQ(GetDisplayRect().x(), x);
1819 prev_x = x;
1821 SendKeyEvent(0x05E2);
1822 EXPECT_EQ(WideToUTF16(L"\x05E1\x05E2"), textfield_->text());
1823 x = GetCursorBounds().x();
1824 EXPECT_GE(1, std::abs(x - prev_x));
1826 SendKeyEvent('a');
1827 EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"a"), textfield_->text());
1828 x = GetCursorBounds().x();
1829 EXPECT_LT(prev_x, x);
1830 prev_x = x;
1832 SendKeyEvent('b');
1833 EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"ab"), textfield_->text());
1834 x = GetCursorBounds().x();
1835 EXPECT_LT(prev_x, x);
1838 TEST_F(TextfieldTest, TextCursorDisplayInRTLTest) {
1839 std::string locale = l10n_util::GetApplicationLocale("");
1840 base::i18n::SetICUDefaultLocale("he");
1842 InitTextfield();
1843 // LTR-RTL string in RTL context.
1844 SendKeyEvent('a');
1845 EXPECT_STR_EQ("a", textfield_->text());
1846 int x = GetCursorBounds().x();
1847 EXPECT_EQ(GetDisplayRect().right() - 1, x);
1848 int prev_x = x;
1850 SendKeyEvent('b');
1851 EXPECT_STR_EQ("ab", textfield_->text());
1852 x = GetCursorBounds().x();
1853 EXPECT_GE(1, std::abs(x - prev_x));
1855 SendKeyEvent(0x05E1);
1856 EXPECT_EQ(WideToUTF16(L"ab\x05E1"), textfield_->text());
1857 x = GetCursorBounds().x();
1858 EXPECT_GT(prev_x, x);
1859 prev_x = x;
1861 SendKeyEvent(0x05E2);
1862 EXPECT_EQ(WideToUTF16(L"ab\x05E1\x5E2"), textfield_->text());
1863 x = GetCursorBounds().x();
1864 EXPECT_GT(prev_x, x);
1866 // Clear text.
1867 SendKeyEvent(ui::VKEY_A, false, true);
1868 SendKeyEvent(ui::VKEY_DELETE);
1870 // RTL-LTR string in RTL context.
1871 SendKeyEvent(0x05E1);
1872 EXPECT_EQ(WideToUTF16(L"\x05E1"), textfield_->text());
1873 x = GetCursorBounds().x();
1874 prev_x = x;
1876 SendKeyEvent(0x05E2);
1877 EXPECT_EQ(WideToUTF16(L"\x05E1\x05E2"), textfield_->text());
1878 x = GetCursorBounds().x();
1879 EXPECT_GT(prev_x, x);
1880 prev_x = x;
1882 SendKeyEvent('a');
1883 EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"a"), textfield_->text());
1884 x = GetCursorBounds().x();
1885 EXPECT_GE(1, std::abs(x - prev_x));
1886 prev_x = x;
1888 SendKeyEvent('b');
1889 EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"ab"), textfield_->text());
1890 x = GetCursorBounds().x();
1891 EXPECT_GE(1, std::abs(x - prev_x));
1893 // Reset locale.
1894 base::i18n::SetICUDefaultLocale(locale);
1897 TEST_F(TextfieldTest, HitInsideTextAreaTest) {
1898 InitTextfield();
1899 textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2"));
1900 std::vector<gfx::Rect> cursor_bounds;
1902 // Save each cursor bound.
1903 gfx::SelectionModel sel(0, gfx::CURSOR_FORWARD);
1904 cursor_bounds.push_back(GetCursorBounds(sel));
1906 sel = gfx::SelectionModel(1, gfx::CURSOR_BACKWARD);
1907 gfx::Rect bound = GetCursorBounds(sel);
1908 sel = gfx::SelectionModel(1, gfx::CURSOR_FORWARD);
1909 EXPECT_EQ(bound.x(), GetCursorBounds(sel).x());
1910 cursor_bounds.push_back(bound);
1912 // Check that a cursor at the end of the Latin portion of the text is at the
1913 // same position as a cursor placed at the end of the RTL Hebrew portion.
1914 sel = gfx::SelectionModel(2, gfx::CURSOR_BACKWARD);
1915 bound = GetCursorBounds(sel);
1916 sel = gfx::SelectionModel(4, gfx::CURSOR_BACKWARD);
1917 EXPECT_EQ(bound.x(), GetCursorBounds(sel).x());
1918 cursor_bounds.push_back(bound);
1920 sel = gfx::SelectionModel(3, gfx::CURSOR_BACKWARD);
1921 bound = GetCursorBounds(sel);
1922 sel = gfx::SelectionModel(3, gfx::CURSOR_FORWARD);
1923 EXPECT_EQ(bound.x(), GetCursorBounds(sel).x());
1924 cursor_bounds.push_back(bound);
1926 sel = gfx::SelectionModel(2, gfx::CURSOR_FORWARD);
1927 bound = GetCursorBounds(sel);
1928 sel = gfx::SelectionModel(4, gfx::CURSOR_FORWARD);
1929 EXPECT_EQ(bound.x(), GetCursorBounds(sel).x());
1930 cursor_bounds.push_back(bound);
1932 // Expected cursor position when clicking left and right of each character.
1933 size_t cursor_pos_expected[] = {0, 1, 1, 2, 4, 3, 3, 2};
1935 int index = 0;
1936 for (int i = 0; i < static_cast<int>(cursor_bounds.size() - 1); ++i) {
1937 int half_width = (cursor_bounds[i + 1].x() - cursor_bounds[i].x()) / 2;
1938 MouseClick(cursor_bounds[i], half_width / 2);
1939 EXPECT_EQ(cursor_pos_expected[index++], textfield_->GetCursorPosition());
1941 // To avoid trigger double click. Not using sleep() since it takes longer
1942 // for the test to run if using sleep().
1943 NonClientMouseClick();
1945 MouseClick(cursor_bounds[i + 1], - (half_width / 2));
1946 EXPECT_EQ(cursor_pos_expected[index++], textfield_->GetCursorPosition());
1948 NonClientMouseClick();
1952 TEST_F(TextfieldTest, HitOutsideTextAreaTest) {
1953 InitTextfield();
1955 // LTR-RTL string in LTR context.
1956 textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2"));
1958 const bool shift = false;
1959 SendHomeEvent(shift);
1960 gfx::Rect bound = GetCursorBounds();
1961 MouseClick(bound, -10);
1962 EXPECT_EQ(bound, GetCursorBounds());
1964 SendEndEvent(shift);
1965 bound = GetCursorBounds();
1966 MouseClick(bound, 10);
1967 EXPECT_EQ(bound, GetCursorBounds());
1969 NonClientMouseClick();
1971 // RTL-LTR string in LTR context.
1972 textfield_->SetText(WideToUTF16(L"\x05E1\x5E2" L"ab"));
1974 SendHomeEvent(shift);
1975 bound = GetCursorBounds();
1976 MouseClick(bound, 10);
1977 EXPECT_EQ(bound, GetCursorBounds());
1979 SendEndEvent(shift);
1980 bound = GetCursorBounds();
1981 MouseClick(bound, -10);
1982 EXPECT_EQ(bound, GetCursorBounds());
1985 TEST_F(TextfieldTest, HitOutsideTextAreaInRTLTest) {
1986 std::string locale = l10n_util::GetApplicationLocale("");
1987 base::i18n::SetICUDefaultLocale("he");
1989 InitTextfield();
1991 // RTL-LTR string in RTL context.
1992 textfield_->SetText(WideToUTF16(L"\x05E1\x5E2" L"ab"));
1993 const bool shift = false;
1994 SendHomeEvent(shift);
1995 gfx::Rect bound = GetCursorBounds();
1996 MouseClick(bound, 10);
1997 EXPECT_EQ(bound, GetCursorBounds());
1999 SendEndEvent(shift);
2000 bound = GetCursorBounds();
2001 MouseClick(bound, -10);
2002 EXPECT_EQ(bound, GetCursorBounds());
2004 NonClientMouseClick();
2006 // LTR-RTL string in RTL context.
2007 textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2"));
2008 SendHomeEvent(shift);
2009 bound = GetCursorBounds();
2010 MouseClick(bound, -10);
2011 EXPECT_EQ(bound, GetCursorBounds());
2013 SendEndEvent(shift);
2014 bound = GetCursorBounds();
2015 MouseClick(bound, 10);
2016 EXPECT_EQ(bound, GetCursorBounds());
2018 // Reset locale.
2019 base::i18n::SetICUDefaultLocale(locale);
2022 TEST_F(TextfieldTest, OverflowTest) {
2023 InitTextfield();
2025 base::string16 str;
2026 for (int i = 0; i < 500; ++i)
2027 SendKeyEvent('a');
2028 SendKeyEvent(kHebrewLetterSamekh);
2029 EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
2031 // Test mouse pointing.
2032 MouseClick(GetCursorBounds(), -1);
2033 EXPECT_EQ(500U, textfield_->GetCursorPosition());
2035 // Clear text.
2036 SendKeyEvent(ui::VKEY_A, false, true);
2037 SendKeyEvent(ui::VKEY_DELETE);
2039 for (int i = 0; i < 500; ++i)
2040 SendKeyEvent(kHebrewLetterSamekh);
2041 SendKeyEvent('a');
2042 EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
2044 MouseClick(GetCursorBounds(), -1);
2045 EXPECT_EQ(501U, textfield_->GetCursorPosition());
2048 TEST_F(TextfieldTest, OverflowInRTLTest) {
2049 std::string locale = l10n_util::GetApplicationLocale("");
2050 base::i18n::SetICUDefaultLocale("he");
2052 InitTextfield();
2054 base::string16 str;
2055 for (int i = 0; i < 500; ++i)
2056 SendKeyEvent('a');
2057 SendKeyEvent(kHebrewLetterSamekh);
2058 EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
2060 MouseClick(GetCursorBounds(), 1);
2061 EXPECT_EQ(501U, textfield_->GetCursorPosition());
2063 // Clear text.
2064 SendKeyEvent(ui::VKEY_A, false, true);
2065 SendKeyEvent(ui::VKEY_DELETE);
2067 for (int i = 0; i < 500; ++i)
2068 SendKeyEvent(kHebrewLetterSamekh);
2069 SendKeyEvent('a');
2070 EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
2072 MouseClick(GetCursorBounds(), 1);
2073 EXPECT_EQ(500U, textfield_->GetCursorPosition());
2075 // Reset locale.
2076 base::i18n::SetICUDefaultLocale(locale);
2079 TEST_F(TextfieldTest, GetCompositionCharacterBoundsTest) {
2080 InitTextfield();
2081 ui::CompositionText composition;
2082 composition.text = UTF8ToUTF16("abc123");
2083 const uint32 char_count = static_cast<uint32>(composition.text.length());
2084 ui::TextInputClient* client = textfield_;
2086 // Compare the composition character bounds with surrounding cursor bounds.
2087 for (uint32 i = 0; i < char_count; ++i) {
2088 composition.selection = gfx::Range(i);
2089 client->SetCompositionText(composition);
2090 gfx::Point cursor_origin = GetCursorBounds().origin();
2091 views::View::ConvertPointToScreen(textfield_, &cursor_origin);
2093 composition.selection = gfx::Range(i + 1);
2094 client->SetCompositionText(composition);
2095 gfx::Point next_cursor_bottom_left = GetCursorBounds().bottom_left();
2096 views::View::ConvertPointToScreen(textfield_, &next_cursor_bottom_left);
2098 gfx::Rect character;
2099 EXPECT_TRUE(client->GetCompositionCharacterBounds(i, &character));
2100 EXPECT_EQ(character.origin(), cursor_origin) << " i=" << i;
2101 EXPECT_EQ(character.bottom_right(), next_cursor_bottom_left) << " i=" << i;
2104 // Return false if the index is out of range.
2105 gfx::Rect rect;
2106 EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count, &rect));
2107 EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 1, &rect));
2108 EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 100, &rect));
2111 TEST_F(TextfieldTest, GetCompositionCharacterBounds_ComplexText) {
2112 InitTextfield();
2114 const base::char16 kUtf16Chars[] = {
2115 // U+0020 SPACE
2116 0x0020,
2117 // U+1F408 (CAT) as surrogate pair
2118 0xd83d, 0xdc08,
2119 // U+5642 as Ideographic Variation Sequences
2120 0x5642, 0xDB40, 0xDD00,
2121 // U+260E (BLACK TELEPHONE) as Emoji Variation Sequences
2122 0x260E, 0xFE0F,
2123 // U+0020 SPACE
2124 0x0020,
2126 const size_t kUtf16CharsCount = arraysize(kUtf16Chars);
2128 ui::CompositionText composition;
2129 composition.text.assign(kUtf16Chars, kUtf16Chars + kUtf16CharsCount);
2130 ui::TextInputClient* client = textfield_;
2131 client->SetCompositionText(composition);
2133 // Make sure GetCompositionCharacterBounds never fails for index.
2134 gfx::Rect rects[kUtf16CharsCount];
2135 gfx::Rect prev_cursor = GetCursorBounds();
2136 for (uint32 i = 0; i < kUtf16CharsCount; ++i)
2137 EXPECT_TRUE(client->GetCompositionCharacterBounds(i, &rects[i]));
2139 // Here we might expect the following results but it actually depends on how
2140 // Uniscribe or HarfBuzz treats them with given font.
2141 // - rects[1] == rects[2]
2142 // - rects[3] == rects[4] == rects[5]
2143 // - rects[6] == rects[7]
2146 // The word we select by double clicking should remain selected regardless of
2147 // where we drag the mouse afterwards without releasing the left button.
2148 TEST_F(TextfieldTest, KeepInitiallySelectedWord) {
2149 InitTextfield();
2151 textfield_->SetText(ASCIIToUTF16("abc def ghi"));
2153 textfield_->SelectRange(gfx::Range(5, 5));
2154 const gfx::Rect middle_cursor = GetCursorBounds();
2155 textfield_->SelectRange(gfx::Range(0, 0));
2156 const gfx::Point beginning = GetCursorBounds().origin();
2158 // Double click, but do not release the left button.
2159 MouseClick(middle_cursor, 0);
2160 const gfx::Point middle(middle_cursor.x(),
2161 middle_cursor.y() + middle_cursor.height() / 2);
2162 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, middle, middle,
2163 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
2164 ui::EF_LEFT_MOUSE_BUTTON);
2165 textfield_->OnMousePressed(press_event);
2166 EXPECT_EQ(gfx::Range(4, 7), textfield_->GetSelectedRange());
2168 // Drag the mouse to the beginning of the textfield.
2169 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, beginning, beginning,
2170 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
2171 textfield_->OnMouseDragged(drag_event);
2172 EXPECT_EQ(gfx::Range(7, 0), textfield_->GetSelectedRange());
2175 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
2176 // flaky: http://crbug.com/396477
2177 TEST_F(TextfieldTest, DISABLED_SelectionClipboard) {
2178 InitTextfield();
2179 textfield_->SetText(ASCIIToUTF16("0123"));
2180 gfx::Point point_1(GetCursorPositionX(1), 0);
2181 gfx::Point point_2(GetCursorPositionX(2), 0);
2182 gfx::Point point_3(GetCursorPositionX(3), 0);
2183 gfx::Point point_4(GetCursorPositionX(4), 0);
2185 // Text selected by the mouse should be placed on the selection clipboard.
2186 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, point_1, point_1,
2187 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
2188 ui::EF_LEFT_MOUSE_BUTTON);
2189 textfield_->OnMousePressed(press);
2190 ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, point_3, point_3,
2191 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
2192 ui::EF_LEFT_MOUSE_BUTTON);
2193 textfield_->OnMouseDragged(drag);
2194 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point_3, point_3,
2195 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
2196 ui::EF_LEFT_MOUSE_BUTTON);
2197 textfield_->OnMouseReleased(release);
2198 EXPECT_EQ(gfx::Range(1, 3), textfield_->GetSelectedRange());
2199 EXPECT_STR_EQ("12", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
2201 // Select-all should update the selection clipboard.
2202 SendKeyEvent(ui::VKEY_A, false, true);
2203 EXPECT_EQ(gfx::Range(0, 4), textfield_->GetSelectedRange());
2204 EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
2205 EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
2207 // Shift-click selection modifications should update the clipboard.
2208 NonClientMouseClick();
2209 ui::MouseEvent press_2(ui::ET_MOUSE_PRESSED, point_2, point_2,
2210 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
2211 ui::EF_LEFT_MOUSE_BUTTON);
2212 press_2.set_flags(press_2.flags() | ui::EF_SHIFT_DOWN);
2213 #if defined(USE_X11)
2214 ui::UpdateX11EventForFlags(&press_2);
2215 #endif
2216 textfield_->OnMousePressed(press_2);
2217 ui::MouseEvent release_2(ui::ET_MOUSE_RELEASED, point_2, point_2,
2218 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
2219 ui::EF_LEFT_MOUSE_BUTTON);
2220 textfield_->OnMouseReleased(release_2);
2221 EXPECT_EQ(gfx::Range(0, 2), textfield_->GetSelectedRange());
2222 EXPECT_STR_EQ("01", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
2223 EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
2225 // Shift-Left/Right should update the selection clipboard.
2226 SendKeyEvent(ui::VKEY_RIGHT, true, false);
2227 EXPECT_STR_EQ("012", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
2228 EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
2229 SendKeyEvent(ui::VKEY_LEFT, true, false);
2230 EXPECT_STR_EQ("01", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
2231 EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
2232 SendKeyEvent(ui::VKEY_RIGHT, true, true);
2233 EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
2234 EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
2236 // Moving the cursor without a selection should not change the clipboard.
2237 SendKeyEvent(ui::VKEY_LEFT, false, false);
2238 EXPECT_EQ(gfx::Range(0, 0), textfield_->GetSelectedRange());
2239 EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
2240 EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
2242 // Middle clicking should paste at the mouse (not cursor) location.
2243 // The cursor should be placed at the end of the pasted text.
2244 ui::MouseEvent middle(ui::ET_MOUSE_PRESSED, point_4, point_4,
2245 ui::EventTimeForNow(), ui::EF_MIDDLE_MOUSE_BUTTON,
2246 ui::EF_MIDDLE_MOUSE_BUTTON);
2247 textfield_->OnMousePressed(middle);
2248 EXPECT_STR_EQ("01230123", textfield_->text());
2249 EXPECT_EQ(gfx::Range(8, 8), textfield_->GetSelectedRange());
2250 EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
2252 // Middle clicking on an unfocused textfield should focus it and paste.
2253 textfield_->GetFocusManager()->ClearFocus();
2254 EXPECT_FALSE(textfield_->HasFocus());
2255 textfield_->OnMousePressed(middle);
2256 EXPECT_TRUE(textfield_->HasFocus());
2257 EXPECT_STR_EQ("012301230123", textfield_->text());
2258 EXPECT_EQ(gfx::Range(8, 8), textfield_->GetSelectedRange());
2259 EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
2261 // Middle clicking with an empty selection clipboard should still focus.
2262 SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, std::string());
2263 textfield_->GetFocusManager()->ClearFocus();
2264 EXPECT_FALSE(textfield_->HasFocus());
2265 textfield_->OnMousePressed(middle);
2266 EXPECT_TRUE(textfield_->HasFocus());
2267 EXPECT_STR_EQ("012301230123", textfield_->text());
2268 EXPECT_EQ(gfx::Range(4, 4), textfield_->GetSelectedRange());
2269 EXPECT_TRUE(GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION).empty());
2271 // Middle clicking in the selection should clear the clipboard and selection.
2272 SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "foo");
2273 textfield_->SelectRange(gfx::Range(2, 6));
2274 textfield_->OnMousePressed(middle);
2275 EXPECT_STR_EQ("012301230123", textfield_->text());
2276 EXPECT_EQ(gfx::Range(6, 6), textfield_->GetSelectedRange());
2277 EXPECT_TRUE(GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION).empty());
2279 // Double and triple clicking should update the clipboard contents.
2280 textfield_->SetText(ASCIIToUTF16("ab cd ef"));
2281 gfx::Point word(GetCursorPositionX(4), 0);
2282 ui::MouseEvent press_word(ui::ET_MOUSE_PRESSED, word, word,
2283 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
2284 ui::EF_LEFT_MOUSE_BUTTON);
2285 textfield_->OnMousePressed(press_word);
2286 ui::MouseEvent release_word(ui::ET_MOUSE_RELEASED, word, word,
2287 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
2288 ui::EF_LEFT_MOUSE_BUTTON);
2289 textfield_->OnMouseReleased(release_word);
2290 ui::MouseEvent double_click(ui::ET_MOUSE_PRESSED, word, word,
2291 ui::EventTimeForNow(),
2292 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK,
2293 ui::EF_LEFT_MOUSE_BUTTON);
2294 textfield_->OnMousePressed(double_click);
2295 textfield_->OnMouseReleased(release_word);
2296 EXPECT_EQ(gfx::Range(3, 5), textfield_->GetSelectedRange());
2297 EXPECT_STR_EQ("cd", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
2298 EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
2299 textfield_->OnMousePressed(press_word);
2300 textfield_->OnMouseReleased(release_word);
2301 EXPECT_EQ(gfx::Range(0, 8), textfield_->GetSelectedRange());
2302 EXPECT_STR_EQ("ab cd ef", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
2303 EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
2305 // Selecting a range of text without any user interaction should not change
2306 // the clipboard content.
2307 textfield_->SelectRange(gfx::Range(0, 3));
2308 EXPECT_STR_EQ("ab ", textfield_->GetSelectedText());
2309 EXPECT_STR_EQ("ab cd ef", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
2310 EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
2312 SetClipboardText(ui::CLIPBOARD_TYPE_SELECTION, "other");
2313 textfield_->SelectAll(false);
2314 EXPECT_STR_EQ("other", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
2315 EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
2317 #endif
2319 // Long_Press gesture in Textfield can initiate a drag and drop now.
2320 TEST_F(TextfieldTest, TestLongPressInitiatesDragDrop) {
2321 InitTextfield();
2322 textfield_->SetText(ASCIIToUTF16("Hello string world"));
2324 // Ensure the textfield will provide selected text for drag data.
2325 textfield_->SelectRange(gfx::Range(6, 12));
2326 const gfx::Point kStringPoint(GetCursorPositionX(9), 0);
2328 // Enable touch-drag-drop to make long press effective.
2329 base::CommandLine::ForCurrentProcess()->AppendSwitch(
2330 switches::kEnableTouchDragDrop);
2332 // Create a long press event in the selected region should start a drag.
2333 GestureEventForTest long_press(
2334 kStringPoint.x(),
2335 kStringPoint.y(),
2336 ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
2337 textfield_->OnGestureEvent(&long_press);
2338 EXPECT_TRUE(textfield_->CanStartDragForView(NULL, kStringPoint,
2339 kStringPoint));
2342 TEST_F(TextfieldTest, GetTextfieldBaseline_FontFallbackTest) {
2343 InitTextfield();
2344 textfield_->SetText(UTF8ToUTF16("abc"));
2345 const int old_baseline = textfield_->GetBaseline();
2347 // Set text which may fall back to a font which has taller baseline than
2348 // the default font.
2349 textfield_->SetText(UTF8ToUTF16("\xE0\xB9\x91"));
2350 const int new_baseline = textfield_->GetBaseline();
2352 // Regardless of the text, the baseline must be the same.
2353 EXPECT_EQ(new_baseline, old_baseline);
2356 // Tests that a textfield view can be destroyed from OnKeyEvent() on its
2357 // controller and it does not crash.
2358 TEST_F(TextfieldTest, DestroyingTextfieldFromOnKeyEvent) {
2359 InitTextfield();
2361 // The controller assumes ownership of the textfield.
2362 TextfieldDestroyerController controller(textfield_);
2363 EXPECT_TRUE(controller.target());
2365 // Send a key to trigger OnKeyEvent().
2366 SendKeyEvent(ui::VKEY_RETURN);
2368 EXPECT_FALSE(controller.target());
2371 class TextfieldTouchSelectionTest : public TextfieldTest {
2372 public:
2373 // TextfieldTest:
2374 void SetUp() override {
2375 TextfieldTest::SetUp();
2376 base::CommandLine::ForCurrentProcess()->AppendSwitch(
2377 switches::kEnableTouchEditing);
2380 protected:
2381 // Simulates a complete tap.
2382 void Tap(const gfx::Point& point) {
2383 GestureEventForTest begin(
2384 point.x(), point.y(), ui::GestureEventDetails(ui::ET_GESTURE_BEGIN));
2385 textfield_->OnGestureEvent(&begin);
2387 GestureEventForTest tap_down(
2388 point.x(), point.y(), ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
2389 textfield_->OnGestureEvent(&tap_down);
2391 GestureEventForTest show_press(
2392 point.x(),
2393 point.y(),
2394 ui::GestureEventDetails(ui::ET_GESTURE_SHOW_PRESS));
2395 textfield_->OnGestureEvent(&show_press);
2397 ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP);
2398 tap_details.set_tap_count(1);
2399 GestureEventForTest tap(point.x(), point.y(), tap_details);
2400 textfield_->OnGestureEvent(&tap);
2402 GestureEventForTest end(
2403 point.x(), point.y(), ui::GestureEventDetails(ui::ET_GESTURE_END));
2404 textfield_->OnGestureEvent(&end);
2409 // Touch selection and dragging currently only works for chromeos.
2410 #if defined(OS_CHROMEOS)
2411 TEST_F(TextfieldTouchSelectionTest, TouchSelectionAndDraggingTest) {
2412 InitTextfield();
2413 textfield_->SetText(ASCIIToUTF16("hello world"));
2414 EXPECT_FALSE(test_api_->touch_selection_controller());
2415 const int x = GetCursorPositionX(2);
2417 // Tapping on the textfield should turn on the TouchSelectionController.
2418 ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP);
2419 tap_details.set_tap_count(1);
2420 GestureEventForTest tap(x, 0, tap_details);
2421 textfield_->OnGestureEvent(&tap);
2422 EXPECT_TRUE(test_api_->touch_selection_controller());
2424 // Un-focusing the textfield should reset the TouchSelectionController
2425 textfield_->GetFocusManager()->ClearFocus();
2426 EXPECT_FALSE(test_api_->touch_selection_controller());
2427 textfield_->RequestFocus();
2429 // With touch editing enabled, long press should not show context menu.
2430 // Instead, select word and invoke TouchSelectionController.
2431 GestureEventForTest long_press_1(
2432 x, 0, ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
2433 textfield_->OnGestureEvent(&long_press_1);
2434 EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
2435 EXPECT_TRUE(test_api_->touch_selection_controller());
2436 EXPECT_TRUE(long_press_1.handled());
2438 // With touch drag drop enabled, long pressing in the selected region should
2439 // start a drag and remove TouchSelectionController.
2440 ASSERT_TRUE(switches::IsTouchDragDropEnabled());
2441 GestureEventForTest long_press_2(
2442 x, 0, ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
2443 textfield_->OnGestureEvent(&long_press_2);
2444 EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
2445 EXPECT_FALSE(test_api_->touch_selection_controller());
2446 EXPECT_FALSE(long_press_2.handled());
2448 // After disabling touch drag drop, long pressing again in the selection
2449 // region should not do anything.
2450 base::CommandLine::ForCurrentProcess()->AppendSwitch(
2451 switches::kDisableTouchDragDrop);
2452 ASSERT_FALSE(switches::IsTouchDragDropEnabled());
2453 GestureEventForTest long_press_3(
2454 x, 0, ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
2455 textfield_->OnGestureEvent(&long_press_3);
2456 EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
2457 EXPECT_FALSE(test_api_->touch_selection_controller());
2458 EXPECT_FALSE(long_press_3.handled());
2460 #endif
2462 TEST_F(TextfieldTouchSelectionTest, TouchSelectionInUnfocusableTextfield) {
2463 InitTextfield();
2464 textfield_->SetText(ASCIIToUTF16("hello world"));
2465 gfx::Point touch_point(GetCursorPositionX(2), 0);
2467 // Disable textfield and tap on it. Touch text selection should not get
2468 // activated.
2469 textfield_->SetEnabled(false);
2470 Tap(touch_point);
2471 EXPECT_FALSE(test_api_->touch_selection_controller());
2472 textfield_->SetEnabled(true);
2474 // Make textfield unfocusable and tap on it. Touch text selection should not
2475 // get activated.
2476 textfield_->SetFocusable(false);
2477 Tap(touch_point);
2478 EXPECT_FALSE(textfield_->HasFocus());
2479 EXPECT_FALSE(test_api_->touch_selection_controller());
2480 textfield_->SetFocusable(true);
2483 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
2484 #if defined(OS_MACOSX) && !defined(USE_AURA)
2485 #define MAYBE_TapOnSelection DISABLED_TapOnSelection
2486 #else
2487 #define MAYBE_TapOnSelection TapOnSelection
2488 #endif
2490 TEST_F(TextfieldTouchSelectionTest, MAYBE_TapOnSelection) {
2491 InitTextfield();
2492 textfield_->SetText(ASCIIToUTF16("hello world"));
2493 gfx::Range sel_range(2, 7);
2494 gfx::Range tap_range(5, 5);
2495 gfx::Rect tap_rect =
2496 GetCursorBounds(gfx::SelectionModel(tap_range, gfx::CURSOR_FORWARD));
2497 gfx::Point tap_point = tap_rect.CenterPoint();
2499 // Select range |sel_range| and check if touch selection handles are not
2500 // present and correct range is selected.
2501 textfield_->SetSelectionRange(sel_range);
2502 gfx::Range range;
2503 textfield_->GetSelectionRange(&range);
2504 EXPECT_FALSE(test_api_->touch_selection_controller());
2505 EXPECT_EQ(sel_range, range);
2507 // Tap on selection and check if touch selectoin handles are shown, but
2508 // selection range is not modified.
2509 Tap(tap_point);
2510 textfield_->GetSelectionRange(&range);
2511 EXPECT_TRUE(test_api_->touch_selection_controller());
2512 EXPECT_EQ(sel_range, range);
2514 // Tap again on selection and check if touch selection handles are still
2515 // present and selection is changed to a cursor at tap location.
2516 Tap(tap_point);
2517 textfield_->GetSelectionRange(&range);
2518 EXPECT_TRUE(test_api_->touch_selection_controller());
2519 EXPECT_EQ(tap_range, range);
2522 TEST_F(TextfieldTest, AccessiblePasswordTest) {
2523 InitTextfield();
2524 textfield_->SetText(ASCIIToUTF16("password"));
2526 ui::AXViewState state_regular;
2527 textfield_->GetAccessibleState(&state_regular);
2528 EXPECT_EQ(ui::AX_ROLE_TEXT_FIELD, state_regular.role);
2529 EXPECT_EQ(ASCIIToUTF16("password"), state_regular.value);
2530 EXPECT_FALSE(state_regular.HasStateFlag(ui::AX_STATE_PROTECTED));
2532 textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
2533 ui::AXViewState state_protected;
2534 textfield_->GetAccessibleState(&state_protected);
2535 EXPECT_EQ(ui::AX_ROLE_TEXT_FIELD, state_protected.role);
2536 EXPECT_EQ(ASCIIToUTF16("********"), state_protected.value);
2537 EXPECT_TRUE(state_protected.HasStateFlag(ui::AX_STATE_PROTECTED));
2540 } // namespace views