--- /dev/null
+// 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);