| // Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights |
| // reserved. Use of this source code is governed by a BSD-style license that |
| // can be found in the LICENSE file. |
| |
| #include "include/base/cef_bind.h" |
| #include "include/cef_pack_strings.h" |
| #include "include/views/cef_textfield.h" |
| #include "include/views/cef_textfield_delegate.h" |
| #include "include/wrapper/cef_closure_task.h" |
| #include "tests/ceftests/thread_helper.h" |
| #include "tests/ceftests/views/test_window_delegate.h" |
| #include "tests/gtest/include/gtest/gtest.h" |
| |
| // See ui/events/keycodes/keyboard_codes.h |
| #define VKEY_UNKNOWN 0 |
| #if defined(OS_WIN) |
| #define VKEY_A 'A' |
| #define VKEY_SPACE VK_SPACE |
| #define VKEY_RETURN VK_RETURN |
| #elif defined(OS_POSIX) |
| #define VKEY_A 0x41 |
| #define VKEY_SPACE 0x20 |
| #define VKEY_RETURN 0x0D |
| #else |
| #error "Unsupported platform" |
| #endif |
| |
| #define TEXTFIELD_TEST(name) UI_THREAD_TEST(ViewsTextfieldTest, name) |
| #define TEXTFIELD_TEST_ASYNC(name) \ |
| UI_THREAD_TEST_ASYNC(ViewsTextfieldTest, name) |
| |
| namespace { |
| |
| void TextfieldContentsImpl() { |
| CefRefPtr<CefTextfield> textfield = CefTextfield::CreateTextfield(nullptr); |
| EXPECT_TRUE(textfield.get()); |
| EXPECT_TRUE(textfield->AsTextfield().get()); |
| |
| // Test defaults. |
| EXPECT_TRUE(textfield->GetText().empty()); |
| EXPECT_FALSE(textfield->HasSelection()); |
| EXPECT_EQ(CefRange(0, 0), textfield->GetSelectedRange()); |
| EXPECT_EQ(0U, textfield->GetCursorPosition()); |
| |
| // Test set/get text. |
| const char kText[] = "My test message!"; |
| textfield->SetText(kText); |
| EXPECT_STREQ(kText, textfield->GetText().ToString().c_str()); |
| |
| size_t cursor_pos = sizeof(kText) - 1; |
| EXPECT_EQ(cursor_pos, textfield->GetCursorPosition()); |
| |
| // Test append text. |
| const char kAppendText[] = " And more."; |
| textfield->AppendText(kAppendText); |
| EXPECT_STREQ((std::string(kText) + kAppendText).c_str(), |
| textfield->GetText().ToString().c_str()); |
| EXPECT_EQ(cursor_pos, textfield->GetCursorPosition()); |
| |
| // Test select range. |
| EXPECT_FALSE(textfield->HasSelection()); |
| EXPECT_EQ( |
| CefRange(static_cast<int>(cursor_pos), static_cast<int>(cursor_pos)), |
| textfield->GetSelectedRange()); |
| textfield->SelectRange(CefRange(0, static_cast<int>(cursor_pos))); |
| EXPECT_TRUE(textfield->HasSelection()); |
| EXPECT_EQ(CefRange(0, static_cast<int>(cursor_pos)), |
| textfield->GetSelectedRange()); |
| EXPECT_STREQ(kText, textfield->GetSelectedText().ToString().c_str()); |
| EXPECT_EQ(cursor_pos, textfield->GetCursorPosition()); |
| |
| // Test insert or replace. |
| const char kReplaceText[] = "Other text."; |
| textfield->InsertOrReplaceText(kReplaceText); |
| EXPECT_STREQ((std::string(kReplaceText) + kAppendText).c_str(), |
| textfield->GetText().ToString().c_str()); |
| |
| cursor_pos = sizeof(kReplaceText) - 1; |
| EXPECT_EQ(cursor_pos, textfield->GetCursorPosition()); |
| |
| // Test select all. |
| EXPECT_FALSE(textfield->HasSelection()); |
| textfield->SelectAll(false); |
| EXPECT_TRUE(textfield->HasSelection()); |
| |
| cursor_pos = sizeof(kReplaceText) + sizeof(kAppendText) - 2; |
| EXPECT_EQ(CefRange(0, static_cast<int>(cursor_pos)), |
| textfield->GetSelectedRange()); |
| EXPECT_EQ(cursor_pos, textfield->GetCursorPosition()); |
| |
| // Test clear selection. |
| textfield->ClearSelection(); |
| EXPECT_FALSE(textfield->HasSelection()); |
| EXPECT_EQ( |
| CefRange(static_cast<int>(cursor_pos), static_cast<int>(cursor_pos)), |
| textfield->GetSelectedRange()); |
| EXPECT_EQ(cursor_pos, textfield->GetCursorPosition()); |
| |
| // Test selection with command. |
| EXPECT_TRUE(textfield->IsCommandEnabled(IDS_APP_SELECT_ALL)); |
| textfield->ExecuteCommand(IDS_APP_SELECT_ALL); |
| EXPECT_TRUE(textfield->HasSelection()); |
| EXPECT_EQ(CefRange(0, static_cast<int>(cursor_pos)), |
| textfield->GetSelectedRange()); |
| EXPECT_EQ(cursor_pos, textfield->GetCursorPosition()); |
| |
| textfield->ClearEditHistory(); |
| } |
| |
| void TextfieldStyleImpl() { |
| CefRefPtr<CefTextfield> textfield = CefTextfield::CreateTextfield(nullptr); |
| EXPECT_TRUE(textfield.get()); |
| |
| // Test defaults. |
| EXPECT_FALSE(textfield->IsPasswordInput()); |
| EXPECT_FALSE(textfield->IsReadOnly()); |
| |
| // Test password input. |
| textfield->SetPasswordInput(true); |
| EXPECT_TRUE(textfield->IsPasswordInput()); |
| textfield->SetPasswordInput(false); |
| EXPECT_FALSE(textfield->IsPasswordInput()); |
| |
| // Test read only. |
| textfield->SetReadOnly(true); |
| EXPECT_TRUE(textfield->IsReadOnly()); |
| textfield->SetReadOnly(false); |
| EXPECT_FALSE(textfield->IsReadOnly()); |
| |
| // Test colors. |
| const cef_color_t color = CefColorSetARGB(255, 255, 0, 255); |
| |
| EXPECT_NE(color, textfield->GetTextColor()); |
| textfield->SetTextColor(color); |
| EXPECT_EQ(color, textfield->GetTextColor()); |
| |
| EXPECT_NE(color, textfield->GetSelectionTextColor()); |
| textfield->SetSelectionTextColor(color); |
| EXPECT_EQ(color, textfield->GetSelectionTextColor()); |
| |
| EXPECT_NE(color, textfield->GetSelectionBackgroundColor()); |
| textfield->SetSelectionBackgroundColor(color); |
| EXPECT_EQ(color, textfield->GetSelectionBackgroundColor()); |
| |
| textfield->SetPlaceholderTextColor(color); |
| |
| // Test fonts. |
| textfield->SetFontList("Arial, 14px"); |
| |
| // Test format ranges. |
| const char kText[] = "test text"; |
| textfield->SetText(kText); |
| textfield->ApplyTextColor(color, CefRange(0, 5)); |
| textfield->ApplyTextStyle(CEF_TEXT_STYLE_BOLD, true, CefRange(0, 5)); |
| |
| // Test placeholder text. |
| textfield->SetPlaceholderText(kText); |
| EXPECT_STREQ(kText, textfield->GetPlaceholderText().ToString().c_str()); |
| |
| textfield->SetAccessibleName("MyTextfield"); |
| } |
| |
| } // namespace |
| |
| // Test Textfield getters/setters. |
| TEXTFIELD_TEST(TextfieldContents) |
| TEXTFIELD_TEST(TextfieldStyle) |
| |
| namespace { |
| |
| const int kTextfieldID = 1; |
| |
| // Contents need to be supported by the TranslateKey function. |
| const char kTestInputMessage[] = "Test Message"; |
| |
| void TranslateKey(int c, int* keycode, uint32* modifiers) { |
| *keycode = VKEY_UNKNOWN; |
| *modifiers = 0; |
| |
| if (c >= 'a' && c <= 'z') { |
| *keycode = VKEY_A + (c - 'a'); |
| } else if (c >= 'A' && c <= 'Z') { |
| *keycode = VKEY_A + (c - 'A'); |
| *modifiers = EVENTFLAG_SHIFT_DOWN; |
| } else if (c == ' ') { |
| *keycode = VKEY_SPACE; |
| } |
| } |
| |
| class TestTextfieldDelegate : public CefTextfieldDelegate { |
| public: |
| TestTextfieldDelegate() {} |
| |
| bool OnKeyEvent(CefRefPtr<CefTextfield> textfield, |
| const CefKeyEvent& event) override { |
| EXPECT_TRUE(textfield.get()); |
| EXPECT_EQ(textfield->GetID(), kTextfieldID); |
| |
| if (event.type == KEYEVENT_RAWKEYDOWN && |
| event.windows_key_code == VKEY_RETURN) { |
| // Got the whole string. Finish the test asynchronously. |
| CefPostTask(TID_UI, base::Bind(&TestTextfieldDelegate::FinishTest, this, |
| textfield)); |
| return true; |
| } |
| |
| if (event.type == KEYEVENT_CHAR) { |
| int keycode; |
| uint32 modifiers; |
| TranslateKey(kTestInputMessage[index_++], &keycode, &modifiers); |
| |
| EXPECT_EQ(keycode, event.windows_key_code); |
| EXPECT_EQ(modifiers, event.modifiers); |
| } |
| |
| return false; |
| } |
| |
| void OnAfterUserAction(CefRefPtr<CefTextfield> textfield) override { |
| after_user_action_ct_++; |
| } |
| |
| private: |
| void FinishTest(CefRefPtr<CefTextfield> textfield) { |
| // OnAfterUserAction() should be called for each unhandled character. |
| EXPECT_EQ(sizeof(kTestInputMessage) - 1, after_user_action_ct_); |
| |
| // Verify the completed contents. |
| EXPECT_STREQ(kTestInputMessage, textfield->GetText().ToString().c_str()); |
| |
| // Close the window to end the test. |
| textfield->GetWindow()->Close(); |
| } |
| |
| int index_ = 0; |
| size_t after_user_action_ct_ = 0; |
| |
| IMPLEMENT_REFCOUNTING(TestTextfieldDelegate); |
| DISALLOW_COPY_AND_ASSIGN(TestTextfieldDelegate); |
| }; |
| |
| void RunTextfieldKeyEvent(CefRefPtr<CefWindow> window) { |
| CefRefPtr<CefTextfield> textfield = |
| CefTextfield::CreateTextfield(new TestTextfieldDelegate()); |
| textfield->SetID(kTextfieldID); |
| |
| EXPECT_TRUE(textfield->AsTextfield()); |
| EXPECT_EQ(kTextfieldID, textfield->GetID()); |
| EXPECT_TRUE(textfield->IsVisible()); |
| EXPECT_FALSE(textfield->IsDrawn()); |
| |
| window->AddChildView(textfield); |
| window->Layout(); |
| |
| EXPECT_TRUE(window->IsSame(textfield->GetWindow())); |
| EXPECT_TRUE(window->IsSame(textfield->GetParentView())); |
| EXPECT_TRUE(textfield->IsSame(window->GetViewForID(kTextfieldID))); |
| EXPECT_TRUE(textfield->IsVisible()); |
| EXPECT_TRUE(textfield->IsDrawn()); |
| |
| window->Show(); |
| |
| // Give input focus to the textfield. |
| textfield->RequestFocus(); |
| |
| // Send the contents of |kTestInputMessage| to the textfield. |
| for (size_t i = 0; i < sizeof(kTestInputMessage) - 1; ++i) { |
| int keycode; |
| uint32 modifiers; |
| TranslateKey(kTestInputMessage[i], &keycode, &modifiers); |
| window->SendKeyPress(keycode, modifiers); |
| } |
| |
| // Send return to end the text input. |
| window->SendKeyPress(VKEY_RETURN, 0); |
| } |
| |
| void TextfieldKeyEventImpl(CefRefPtr<CefWaitableEvent> event) { |
| TestWindowDelegate::Config config; |
| config.on_window_created = base::Bind(RunTextfieldKeyEvent); |
| config.close_window = false; |
| TestWindowDelegate::RunTest(event, config); |
| } |
| |
| } // namespace |
| |
| // Test Textfield input and events. This is primarily to exercise exposed CEF |
| // APIs and is not intended to comprehensively test Textfield-related behavior |
| // (which we presume that Chromium is testing). |
| TEXTFIELD_TEST_ASYNC(TextfieldKeyEvent) |