| Index: ui/views/controls/textfield/textfield_unittest.cc
|
| diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
|
| index ca3839c18ed1cef77ff5352ee137d501e7202b35..fd57ce127d6a46032640e19bfe7c69f3ac64412c 100644
|
| --- a/ui/views/controls/textfield/textfield_unittest.cc
|
| +++ b/ui/views/controls/textfield/textfield_unittest.cc
|
| @@ -21,6 +21,7 @@
|
| #include "ui/base/ui_base_switches_util.h"
|
| #include "ui/events/event.h"
|
| #include "ui/events/keycodes/keyboard_codes.h"
|
| +#include "ui/events/test/event_generator.h"
|
| #include "ui/gfx/render_text.h"
|
| #include "ui/strings/grit/ui_strings.h"
|
| #include "ui/views/controls/textfield/textfield_controller.h"
|
| @@ -56,6 +57,15 @@ namespace {
|
|
|
| const base::char16 kHebrewLetterSamekh = 0x05E1;
|
|
|
| +// The method used for dispatching key events. Either dispatch directly to the
|
| +// MockInputMethod using the keycodes it expects internally, or dispatch to the
|
| +// native window implementation using platform-specific keycodes, which should
|
| +// be translated into the correct editing commands.
|
| +enum EventDispatchMethod {
|
| + DISPATCH_TO_INPUT_METHOD,
|
| + DISPATCH_TO_WINDOW,
|
| +};
|
| +
|
| // A Textfield wrapper to intercept OnKey[Pressed|Released]() ressults.
|
| class TestTextfield : public views::Textfield {
|
| public:
|
| @@ -159,6 +169,12 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
|
| copied_to_clipboard_(ui::CLIPBOARD_TYPE_LAST) {
|
| }
|
|
|
| + // Provide an implementation of GetParam which parameterized subclasses can
|
| + // override using gtest's GetParam().
|
| + virtual EventDispatchMethod GetParamWithDefault() {
|
| + return DISPATCH_TO_INPUT_METHOD;
|
| + }
|
| +
|
| // ::testing::Test:
|
| void TearDown() override {
|
| if (widget_)
|
| @@ -202,7 +218,12 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
|
| textfield_ = new TestTextfield();
|
| textfield_->set_controller(this);
|
| widget_ = new Widget();
|
| - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
|
| +
|
| + // The widget type must be an activatable type, and we don't want to worry
|
| + // about the non-client view, which leaves just TYPE_WINDOW_FRAMELESS.
|
| + Widget::InitParams params =
|
| + CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
|
| +
|
| params.bounds = gfx::Rect(100, 100, 100, 100);
|
| widget_->Init(params);
|
| View* container = new View();
|
| @@ -224,8 +245,11 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
|
| input_method_ = new MockInputMethod();
|
| widget_->ReplaceInputMethod(input_method_);
|
|
|
| - // Activate the widget and focus the textfield for input handling.
|
| - widget_->Activate();
|
| + // Since the window type is activatable, showing the widget will also
|
| + // activate it. Calling Activate directly is insufficient, since that does
|
| + // not also _focus_ an aura::Window (i.e. using the FocusClient). Both the
|
| + // widget and the textfield must have focus to properly handle input.
|
| + widget_->Show();
|
| textfield_->RequestFocus();
|
|
|
| // On Mac, activation is asynchronous since desktop widgets are used. We
|
| @@ -233,6 +257,11 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
|
| #if defined(OS_MACOSX) && !defined(USE_AURA)
|
| fake_activation_ = test::WidgetTest::FakeWidgetIsActiveAlways();
|
| #endif
|
| +
|
| + if (GetParamWithDefault() == DISPATCH_TO_WINDOW) {
|
| + event_generator_.reset(new ui::test::EventGenerator(
|
| + GetContext(), widget_->GetNativeWindow()));
|
| + }
|
| }
|
|
|
| ui::MenuModel* GetContextMenuModel() {
|
| @@ -240,22 +269,50 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
|
| return test_api_->context_menu_contents();
|
| }
|
|
|
| + // On Mac, true if testing a views::TextField in an NSWindow using native
|
| + // NSEvents. On other platforms, a helper function to avoid ifdef litter.
|
| + bool TestingNativeMac() {
|
| +#if defined(OS_MACOSX)
|
| + return GetParamWithDefault() == DISPATCH_TO_WINDOW;
|
| +#else
|
| + return false;
|
| +#endif
|
| + }
|
| +
|
| protected:
|
| void SendKeyEvent(ui::KeyboardCode key_code,
|
| bool alt,
|
| bool shift,
|
| - bool control,
|
| + bool control_or_command,
|
| bool caps_lock) {
|
| - int flags = (alt ? ui::EF_ALT_DOWN : 0) |
|
| - (shift ? ui::EF_SHIFT_DOWN : 0) |
|
| + bool control = control_or_command;
|
| + bool command = false;
|
| +
|
| + // By default, swap control and command for native events on Mac. This
|
| + // handles most cases.
|
| + if (TestingNativeMac())
|
| + std::swap(control, command);
|
| +
|
| + int flags = (alt ? ui::EF_ALT_DOWN : 0) | (shift ? ui::EF_SHIFT_DOWN : 0) |
|
| (control ? ui::EF_CONTROL_DOWN : 0) |
|
| + (command ? ui::EF_COMMAND_DOWN : 0) |
|
| (caps_lock ? ui::EF_CAPS_LOCK_DOWN : 0);
|
| +
|
| + // If dispatching to the window, ask the event generator to generate
|
| + // events populated with native event information for each platform.
|
| + if (GetParamWithDefault() == DISPATCH_TO_WINDOW) {
|
| + event_generator_->PressKey(key_code, flags);
|
| + return;
|
| + }
|
| +
|
| ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, flags);
|
| input_method_->DispatchKeyEvent(event);
|
| }
|
|
|
| - void SendKeyEvent(ui::KeyboardCode key_code, bool shift, bool control) {
|
| - SendKeyEvent(key_code, false, shift, control, false);
|
| + void SendKeyEvent(ui::KeyboardCode key_code,
|
| + bool shift,
|
| + bool control_or_command) {
|
| + SendKeyEvent(key_code, false, shift, control_or_command, false);
|
| }
|
|
|
| void SendKeyEvent(ui::KeyboardCode key_code) {
|
| @@ -269,6 +326,7 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
|
| static_cast<ui::KeyboardCode>(ui::VKEY_A + ch - 'a');
|
| SendKeyEvent(code);
|
| } else {
|
| + // TODO(tapted): Support DISPATCH_TO_WINDOW here.
|
| ui::KeyEvent event(ch, ui::VKEY_UNKNOWN, ui::EF_NONE);
|
| input_method_->DispatchKeyEvent(event);
|
| }
|
| @@ -357,10 +415,57 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
|
| private:
|
| ui::ClipboardType copied_to_clipboard_;
|
| scoped_ptr<test::WidgetTest::FakeActivation> fake_activation_;
|
| + scoped_ptr<ui::test::EventGenerator> event_generator_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(TextfieldTest);
|
| };
|
|
|
| +// TextfieldTest that overrides GetParamWithDefault() to override the default
|
| +// using GetParam() from the gtest interface.
|
| +class TextfieldTestWithParam
|
| + : public TextfieldTest,
|
| + public ::testing::WithParamInterface<EventDispatchMethod> {
|
| + public:
|
| + TextfieldTestWithParam() {}
|
| +
|
| + void SendHomeEvent(bool shift) {
|
| + if (TestingNativeMac()) {
|
| + // Use Cmd+Left on native Mac. An RTL-agnostic "end" doesn't have a
|
| + // default key-binding on Mac.
|
| + SendKeyEvent(ui::VKEY_LEFT, shift /* shift */, true /* command */);
|
| + return;
|
| + }
|
| + SendKeyEvent(ui::VKEY_HOME, shift /* shift */, false /* control */);
|
| + }
|
| +
|
| + void SendEndEvent(bool shift) {
|
| + if (TestingNativeMac()) {
|
| + SendKeyEvent(ui::VKEY_RIGHT, shift, true); // Cmd+Right.
|
| + return;
|
| + }
|
| + SendKeyEvent(ui::VKEY_END, shift, false);
|
| + }
|
| +
|
| + // Sends {delete, move, select} word {forward, backward}.
|
| + void SendWordEvent(ui::KeyboardCode key, bool shift) {
|
| + bool alt = false;
|
| + bool control = true;
|
| + bool caps = false;
|
| + if (TestingNativeMac()) {
|
| + // Use Alt+Left/Right/Backspace on native Mac.
|
| + alt = true;
|
| + control = false;
|
| + }
|
| + SendKeyEvent(key, alt, shift, control, caps);
|
| + }
|
| +
|
| + // Overridden from TextfieldTest:
|
| + EventDispatchMethod GetParamWithDefault() override { return GetParam(); }
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(TextfieldTestWithParam);
|
| +};
|
| +
|
| TEST_F(TextfieldTest, ModelChangesTest) {
|
| InitTextfield();
|
|
|
| @@ -398,11 +503,11 @@ TEST_F(TextfieldTest, KeyTest) {
|
| EXPECT_STR_EQ("TexT!1!1", textfield_->text());
|
| }
|
|
|
| -TEST_F(TextfieldTest, ControlAndSelectTest) {
|
| +TEST_P(TextfieldTestWithParam, ControlAndSelectTest) {
|
| // Insert a test string in a textfield.
|
| InitTextfield();
|
| textfield_->SetText(ASCIIToUTF16("one two three"));
|
| - SendKeyEvent(ui::VKEY_HOME, false /* shift */, false /* control */);
|
| + SendHomeEvent(false);
|
| SendKeyEvent(ui::VKEY_RIGHT, true, false);
|
| SendKeyEvent(ui::VKEY_RIGHT, true, false);
|
| SendKeyEvent(ui::VKEY_RIGHT, true, false);
|
| @@ -410,13 +515,13 @@ TEST_F(TextfieldTest, ControlAndSelectTest) {
|
| EXPECT_STR_EQ("one", textfield_->GetSelectedText());
|
|
|
| // Test word select.
|
| - SendKeyEvent(ui::VKEY_RIGHT, true, true);
|
| + SendWordEvent(ui::VKEY_RIGHT, true);
|
| EXPECT_STR_EQ("one two", textfield_->GetSelectedText());
|
| - SendKeyEvent(ui::VKEY_RIGHT, true, true);
|
| + SendWordEvent(ui::VKEY_RIGHT, true);
|
| EXPECT_STR_EQ("one two three", textfield_->GetSelectedText());
|
| - SendKeyEvent(ui::VKEY_LEFT, true, true);
|
| + SendWordEvent(ui::VKEY_LEFT, true);
|
| EXPECT_STR_EQ("one two ", textfield_->GetSelectedText());
|
| - SendKeyEvent(ui::VKEY_LEFT, true, true);
|
| + SendWordEvent(ui::VKEY_LEFT, true);
|
| EXPECT_STR_EQ("one ", textfield_->GetSelectedText());
|
|
|
| // Replace the selected text.
|
| @@ -427,13 +532,13 @@ TEST_F(TextfieldTest, ControlAndSelectTest) {
|
| SendKeyEvent(ui::VKEY_SPACE, false, false);
|
| EXPECT_STR_EQ("ZERO two three", textfield_->text());
|
|
|
| - SendKeyEvent(ui::VKEY_END, true, false);
|
| + SendEndEvent(true);
|
| EXPECT_STR_EQ("two three", textfield_->GetSelectedText());
|
| - SendKeyEvent(ui::VKEY_HOME, true, false);
|
| + SendHomeEvent(true);
|
| EXPECT_STR_EQ("ZERO ", textfield_->GetSelectedText());
|
| }
|
|
|
| -TEST_F(TextfieldTest, InsertionDeletionTest) {
|
| +TEST_P(TextfieldTestWithParam, InsertionDeletionTest) {
|
| // Insert a test string in a textfield.
|
| InitTextfield();
|
| for (size_t i = 0; i < 10; i++)
|
| @@ -455,14 +560,17 @@ TEST_F(TextfieldTest, InsertionDeletionTest) {
|
| EXPECT_STR_EQ("k", textfield_->text());
|
|
|
| // Delete the previous word from cursor.
|
| + bool shift = false;
|
| textfield_->SetText(ASCIIToUTF16("one two three four"));
|
| - SendKeyEvent(ui::VKEY_END);
|
| - SendKeyEvent(ui::VKEY_BACK, false, false, true, false);
|
| + SendEndEvent(shift);
|
| + SendWordEvent(ui::VKEY_BACK, shift);
|
| EXPECT_STR_EQ("one two three ", textfield_->text());
|
|
|
| - // Delete to a line break on Linux and ChromeOS, to a word break on Windows.
|
| - SendKeyEvent(ui::VKEY_LEFT, false, false, true, false);
|
| - SendKeyEvent(ui::VKEY_BACK, false, true, true, false);
|
| + // Delete to a line break on Linux and ChromeOS, to a word break on Windows
|
| + // and Mac.
|
| + SendWordEvent(ui::VKEY_LEFT, shift);
|
| + shift = true;
|
| + SendWordEvent(ui::VKEY_BACK, shift);
|
| #if defined(OS_LINUX)
|
| EXPECT_STR_EQ("three ", textfield_->text());
|
| #else
|
| @@ -471,13 +579,16 @@ TEST_F(TextfieldTest, InsertionDeletionTest) {
|
|
|
| // Delete the next word from cursor.
|
| textfield_->SetText(ASCIIToUTF16("one two three four"));
|
| - SendKeyEvent(ui::VKEY_HOME);
|
| - SendKeyEvent(ui::VKEY_DELETE, false, false, true, false);
|
| + shift = false;
|
| + SendHomeEvent(shift);
|
| + SendWordEvent(ui::VKEY_DELETE, shift);
|
| EXPECT_STR_EQ(" two three four", textfield_->text());
|
|
|
| - // Delete to a line break on Linux and ChromeOS, to a word break on Windows.
|
| - SendKeyEvent(ui::VKEY_RIGHT, false, false, true, false);
|
| - SendKeyEvent(ui::VKEY_DELETE, false, true, true, false);
|
| + // Delete to a line break on Linux and ChromeOS, to a word break on Windows
|
| + // and Mac.
|
| + SendWordEvent(ui::VKEY_RIGHT, shift);
|
| + shift = true;
|
| + SendWordEvent(ui::VKEY_DELETE, shift);
|
| #if defined(OS_LINUX)
|
| EXPECT_STR_EQ(" two", textfield_->text());
|
| #else
|
| @@ -2115,4 +2226,12 @@ TEST_F(TextfieldTouchSelectionTest, TapOnSelection) {
|
| EXPECT_EQ(tap_range, range);
|
| }
|
|
|
| +// Instantiate parameterized tests. These are just the ones above using "TEST_P"
|
| +// rather than "TEST_F".
|
| +INSTANTIATE_TEST_CASE_P(
|
| + TextfieldTestWithParamInstance,
|
| + TextfieldTestWithParam,
|
| + ::testing::Values<EventDispatchMethod>(DISPATCH_TO_INPUT_METHOD,
|
| + DISPATCH_TO_WINDOW));
|
| +
|
| } // namespace views
|
|
|