• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4 
5 #include "include/base/cef_callback.h"
6 #include "include/cef_pack_strings.h"
7 #include "include/views/cef_textfield.h"
8 #include "include/views/cef_textfield_delegate.h"
9 #include "include/wrapper/cef_closure_task.h"
10 #include "tests/ceftests/thread_helper.h"
11 #include "tests/ceftests/views/test_window_delegate.h"
12 #include "tests/gtest/include/gtest/gtest.h"
13 
14 // See ui/events/keycodes/keyboard_codes.h
15 #define VKEY_UNKNOWN 0
16 #if defined(OS_WIN)
17 #define VKEY_A 'A'
18 #define VKEY_SPACE VK_SPACE
19 #define VKEY_RETURN VK_RETURN
20 #elif defined(OS_POSIX)
21 #define VKEY_A 0x41
22 #define VKEY_SPACE 0x20
23 #define VKEY_RETURN 0x0D
24 #else
25 #error "Unsupported platform"
26 #endif
27 
28 #define TEXTFIELD_TEST(name) UI_THREAD_TEST(ViewsTextfieldTest, name)
29 #define TEXTFIELD_TEST_ASYNC(name) \
30   UI_THREAD_TEST_ASYNC(ViewsTextfieldTest, name)
31 
32 namespace {
33 
RunTextfieldContents(CefRefPtr<CefWindow> window)34 void RunTextfieldContents(CefRefPtr<CefWindow> window) {
35   CefRefPtr<CefTextfield> textfield = CefTextfield::CreateTextfield(nullptr);
36   EXPECT_TRUE(textfield.get());
37   EXPECT_TRUE(textfield->AsTextfield().get());
38 
39   // Must be added to a parent window before retrieving the style to avoid
40   // a CHECK() in View::GetNativeTheme(). See https://crbug.com/1056756.
41   window->AddChildView(textfield);
42   window->Layout();
43 
44   // Test defaults.
45   EXPECT_TRUE(textfield->GetText().empty());
46   EXPECT_FALSE(textfield->HasSelection());
47   EXPECT_EQ(CefRange(0, 0), textfield->GetSelectedRange());
48   EXPECT_EQ(0U, textfield->GetCursorPosition());
49 
50   // Test set/get text.
51   const char kText[] = "My test message!";
52   textfield->SetText(kText);
53   EXPECT_STREQ(kText, textfield->GetText().ToString().c_str());
54 
55   size_t cursor_pos = sizeof(kText) - 1;
56   EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
57 
58   // Test append text.
59   const char kAppendText[] = " And more.";
60   textfield->AppendText(kAppendText);
61   EXPECT_STREQ((std::string(kText) + kAppendText).c_str(),
62                textfield->GetText().ToString().c_str());
63   EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
64 
65   // Test select range.
66   EXPECT_FALSE(textfield->HasSelection());
67   EXPECT_EQ(
68       CefRange(static_cast<int>(cursor_pos), static_cast<int>(cursor_pos)),
69       textfield->GetSelectedRange());
70   textfield->SelectRange(CefRange(0, static_cast<int>(cursor_pos)));
71   EXPECT_TRUE(textfield->HasSelection());
72   EXPECT_EQ(CefRange(0, static_cast<int>(cursor_pos)),
73             textfield->GetSelectedRange());
74   EXPECT_STREQ(kText, textfield->GetSelectedText().ToString().c_str());
75   EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
76 
77   // Test insert or replace.
78   const char kReplaceText[] = "Other text.";
79   textfield->InsertOrReplaceText(kReplaceText);
80   EXPECT_STREQ((std::string(kReplaceText) + kAppendText).c_str(),
81                textfield->GetText().ToString().c_str());
82 
83   cursor_pos = sizeof(kReplaceText) - 1;
84   EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
85 
86   // Test select all.
87   EXPECT_FALSE(textfield->HasSelection());
88   textfield->SelectAll(false);
89   EXPECT_TRUE(textfield->HasSelection());
90 
91   cursor_pos = sizeof(kReplaceText) + sizeof(kAppendText) - 2;
92   EXPECT_EQ(CefRange(0, static_cast<int>(cursor_pos)),
93             textfield->GetSelectedRange());
94   EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
95 
96   // Test clear selection.
97   textfield->ClearSelection();
98   EXPECT_FALSE(textfield->HasSelection());
99   EXPECT_EQ(
100       CefRange(static_cast<int>(cursor_pos), static_cast<int>(cursor_pos)),
101       textfield->GetSelectedRange());
102   EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
103 
104   // Test selection with command.
105   EXPECT_TRUE(textfield->IsCommandEnabled(CEF_TFC_SELECT_ALL));
106   textfield->ExecuteCommand(CEF_TFC_SELECT_ALL);
107   EXPECT_TRUE(textfield->HasSelection());
108   EXPECT_EQ(CefRange(0, static_cast<int>(cursor_pos)),
109             textfield->GetSelectedRange());
110   EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
111 
112   textfield->ClearEditHistory();
113 }
114 
TextfieldContentsImpl(CefRefPtr<CefWaitableEvent> event)115 void TextfieldContentsImpl(CefRefPtr<CefWaitableEvent> event) {
116   auto config = std::make_unique<TestWindowDelegate::Config>();
117   config->on_window_created = base::BindOnce(RunTextfieldContents);
118   TestWindowDelegate::RunTest(event, std::move(config));
119 }
120 
RunTextfieldStyle(CefRefPtr<CefWindow> window)121 void RunTextfieldStyle(CefRefPtr<CefWindow> window) {
122   CefRefPtr<CefTextfield> textfield = CefTextfield::CreateTextfield(nullptr);
123   EXPECT_TRUE(textfield.get());
124 
125   // Must be added to a parent window before retrieving the style to avoid
126   // a CHECK() in View::GetNativeTheme(). See https://crbug.com/1056756.
127   window->AddChildView(textfield);
128   window->Layout();
129 
130   // Test defaults.
131   EXPECT_FALSE(textfield->IsPasswordInput());
132   EXPECT_FALSE(textfield->IsReadOnly());
133 
134   // Test password input.
135   textfield->SetPasswordInput(true);
136   EXPECT_TRUE(textfield->IsPasswordInput());
137   textfield->SetPasswordInput(false);
138   EXPECT_FALSE(textfield->IsPasswordInput());
139 
140   // Test read only.
141   textfield->SetReadOnly(true);
142   EXPECT_TRUE(textfield->IsReadOnly());
143   textfield->SetReadOnly(false);
144   EXPECT_FALSE(textfield->IsReadOnly());
145 
146   // Test colors.
147   const cef_color_t color = CefColorSetARGB(255, 255, 0, 255);
148 
149   EXPECT_NE(color, textfield->GetTextColor());
150   textfield->SetTextColor(color);
151   EXPECT_EQ(color, textfield->GetTextColor());
152 
153   EXPECT_NE(color, textfield->GetSelectionTextColor());
154   textfield->SetSelectionTextColor(color);
155   EXPECT_EQ(color, textfield->GetSelectionTextColor());
156 
157   EXPECT_NE(color, textfield->GetSelectionBackgroundColor());
158   textfield->SetSelectionBackgroundColor(color);
159   EXPECT_EQ(color, textfield->GetSelectionBackgroundColor());
160 
161   textfield->SetPlaceholderTextColor(color);
162 
163   // Test fonts.
164   textfield->SetFontList("Arial, 14px");
165 
166   // Test format ranges.
167   const char kText[] = "test text";
168   textfield->SetText(kText);
169   textfield->ApplyTextColor(color, CefRange(0, 5));
170   textfield->ApplyTextStyle(CEF_TEXT_STYLE_BOLD, true, CefRange(0, 5));
171 
172   // Test placeholder text.
173   textfield->SetPlaceholderText(kText);
174   EXPECT_STREQ(kText, textfield->GetPlaceholderText().ToString().c_str());
175 
176   textfield->SetAccessibleName("MyTextfield");
177 }
178 
TextfieldStyleImpl(CefRefPtr<CefWaitableEvent> event)179 void TextfieldStyleImpl(CefRefPtr<CefWaitableEvent> event) {
180   auto config = std::make_unique<TestWindowDelegate::Config>();
181   config->on_window_created = base::BindOnce(RunTextfieldStyle);
182   TestWindowDelegate::RunTest(event, std::move(config));
183 }
184 
185 }  // namespace
186 
187 // Test Textfield getters/setters.
188 TEXTFIELD_TEST_ASYNC(TextfieldContents)
189 TEXTFIELD_TEST_ASYNC(TextfieldStyle)
190 
191 namespace {
192 
193 const int kTextfieldID = 1;
194 
195 // Contents need to be supported by the TranslateKey function.
196 const char kTestInputMessage[] = "Test Message";
197 
TranslateKey(int c,int * keycode,uint32 * modifiers)198 void TranslateKey(int c, int* keycode, uint32* modifiers) {
199   *keycode = VKEY_UNKNOWN;
200   *modifiers = 0;
201 
202   if (c >= 'a' && c <= 'z') {
203     *keycode = VKEY_A + (c - 'a');
204   } else if (c >= 'A' && c <= 'Z') {
205     *keycode = VKEY_A + (c - 'A');
206     *modifiers = EVENTFLAG_SHIFT_DOWN;
207   } else if (c == ' ') {
208     *keycode = VKEY_SPACE;
209   }
210 }
211 
212 class TestTextfieldDelegate : public CefTextfieldDelegate {
213  public:
TestTextfieldDelegate()214   TestTextfieldDelegate() {}
215 
OnKeyEvent(CefRefPtr<CefTextfield> textfield,const CefKeyEvent & event)216   bool OnKeyEvent(CefRefPtr<CefTextfield> textfield,
217                   const CefKeyEvent& event) override {
218     EXPECT_TRUE(textfield.get());
219     EXPECT_EQ(textfield->GetID(), kTextfieldID);
220 
221     if (event.type == KEYEVENT_RAWKEYDOWN &&
222         event.windows_key_code == VKEY_RETURN) {
223       // Got the whole string. Finish the test asynchronously.
224       CefPostTask(TID_UI, base::BindOnce(&TestTextfieldDelegate::FinishTest,
225                                          this, textfield));
226       return true;
227     }
228 
229     if (event.type == KEYEVENT_CHAR) {
230       int keycode;
231       uint32 modifiers;
232       TranslateKey(kTestInputMessage[index_++], &keycode, &modifiers);
233 
234       EXPECT_EQ(keycode, event.windows_key_code);
235       EXPECT_EQ(modifiers, event.modifiers);
236     }
237 
238     return false;
239   }
240 
OnAfterUserAction(CefRefPtr<CefTextfield> textfield)241   void OnAfterUserAction(CefRefPtr<CefTextfield> textfield) override {
242     after_user_action_ct_++;
243   }
244 
245  private:
FinishTest(CefRefPtr<CefTextfield> textfield)246   void FinishTest(CefRefPtr<CefTextfield> textfield) {
247     // OnAfterUserAction() should be called for each unhandled character.
248     EXPECT_EQ(sizeof(kTestInputMessage) - 1, after_user_action_ct_);
249 
250     // Verify the completed contents.
251     EXPECT_STREQ(kTestInputMessage, textfield->GetText().ToString().c_str());
252 
253     // Close the window to end the test.
254     textfield->GetWindow()->Close();
255   }
256 
257   int index_ = 0;
258   size_t after_user_action_ct_ = 0;
259 
260   IMPLEMENT_REFCOUNTING(TestTextfieldDelegate);
261   DISALLOW_COPY_AND_ASSIGN(TestTextfieldDelegate);
262 };
263 
RunTextfieldKeyEvent(CefRefPtr<CefWindow> window)264 void RunTextfieldKeyEvent(CefRefPtr<CefWindow> window) {
265   CefRefPtr<CefTextfield> textfield =
266       CefTextfield::CreateTextfield(new TestTextfieldDelegate());
267   textfield->SetID(kTextfieldID);
268 
269   EXPECT_TRUE(textfield->AsTextfield());
270   EXPECT_EQ(kTextfieldID, textfield->GetID());
271   EXPECT_TRUE(textfield->IsVisible());
272   EXPECT_FALSE(textfield->IsDrawn());
273 
274   window->AddChildView(textfield);
275   window->Layout();
276 
277   EXPECT_TRUE(window->IsSame(textfield->GetWindow()));
278   EXPECT_TRUE(window->IsSame(textfield->GetParentView()));
279   EXPECT_TRUE(textfield->IsSame(window->GetViewForID(kTextfieldID)));
280   EXPECT_TRUE(textfield->IsVisible());
281   EXPECT_TRUE(textfield->IsDrawn());
282 
283   window->Show();
284 
285   // Give input focus to the textfield.
286   textfield->RequestFocus();
287 
288   // Send the contents of |kTestInputMessage| to the textfield.
289   for (size_t i = 0; i < sizeof(kTestInputMessage) - 1; ++i) {
290     int keycode;
291     uint32 modifiers;
292     TranslateKey(kTestInputMessage[i], &keycode, &modifiers);
293     window->SendKeyPress(keycode, modifiers);
294   }
295 
296   // Send return to end the text input.
297   window->SendKeyPress(VKEY_RETURN, 0);
298 }
299 
TextfieldKeyEventImpl(CefRefPtr<CefWaitableEvent> event)300 void TextfieldKeyEventImpl(CefRefPtr<CefWaitableEvent> event) {
301   auto config = std::make_unique<TestWindowDelegate::Config>();
302   config->on_window_created = base::BindOnce(RunTextfieldKeyEvent);
303   config->close_window = false;
304   TestWindowDelegate::RunTest(event, std::move(config));
305 }
306 
307 }  // namespace
308 
309 // Test Textfield input and events. This is primarily to exercise exposed CEF
310 // APIs and is not intended to comprehensively test Textfield-related behavior
311 // (which we presume that Chromium is testing).
312 TEXTFIELD_TEST_ASYNC(TextfieldKeyEvent)
313