// 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/unittests/thread_helper.h" #include "tests/unittests/views/test_window_delegate.h" #include "testing/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 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(cursor_pos), static_cast(cursor_pos)), textfield->GetSelectedRange()); textfield->SelectRange(CefRange(0, static_cast(cursor_pos))); EXPECT_TRUE(textfield->HasSelection()); EXPECT_EQ(CefRange(0, static_cast(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(cursor_pos)), textfield->GetSelectedRange()); EXPECT_EQ(cursor_pos, textfield->GetCursorPosition()); // Test clear selection. textfield->ClearSelection(); EXPECT_FALSE(textfield->HasSelection()); EXPECT_EQ(CefRange(static_cast(cursor_pos), static_cast(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(cursor_pos)), textfield->GetSelectedRange()); EXPECT_EQ(cursor_pos, textfield->GetCursorPosition()); textfield->ClearEditHistory(); } void TextfieldStyleImpl() { CefRefPtr 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 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 textfield) override { after_user_action_ct_++; } private: void FinishTest(CefRefPtr 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 window) { CefRefPtr 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 event) { TestWindowDelegate::RunTest(event, base::Bind(RunTextfieldKeyEvent), false, false); } } // 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);