Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
window_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <array>
6
11#include "gmock/gmock.h"
12#include "gtest/gtest.h"
13
14using testing::_;
15using testing::Eq;
16using testing::InSequence;
17using testing::Invoke;
18using testing::Return;
19
20namespace flutter {
21namespace testing {
22
23TEST(MockWindow, CreateDestroy) {
25 ASSERT_TRUE(TRUE);
26}
27
28TEST(MockWindow, GetDpiAfterCreate) {
30 ASSERT_TRUE(window.GetDpi() > 0);
31}
32
33TEST(MockWindow, VerticalScroll) {
35 const int scroll_amount = 10;
36 // Vertical scroll should be passed along, adjusted for scroll tick size
37 // and direction.
38 EXPECT_CALL(window, OnScroll(0, -scroll_amount / 120.0,
40 .Times(1);
41
42 window.InjectWindowMessage(WM_MOUSEWHEEL, MAKEWPARAM(0, scroll_amount), 0);
43}
44
45TEST(MockWindow, OnImeCompositionCompose) {
46 auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
47 auto* text_input_manager = new MockTextInputManager();
48 std::unique_ptr<TextInputManager> text_input_manager_ptr(text_input_manager);
49 MockWindow window(std::move(windows_proc_table),
50 std::move(text_input_manager_ptr));
51 EXPECT_CALL(*text_input_manager, GetComposingString())
52 .WillRepeatedly(
53 Return(std::optional<std::u16string>(std::u16string(u"nihao"))));
54 EXPECT_CALL(*text_input_manager, GetResultString())
55 .WillRepeatedly(
56 Return(std::optional<std::u16string>(std::u16string(u"`}"))));
57 EXPECT_CALL(*text_input_manager, GetComposingCursorPosition())
58 .WillRepeatedly(Return((int)0));
59
60 EXPECT_CALL(window, OnComposeChange(std::u16string(u"nihao"), 0)).Times(1);
61 EXPECT_CALL(window, OnComposeChange(std::u16string(u"`}"), 0)).Times(0);
62 EXPECT_CALL(window, OnComposeCommit()).Times(0);
63 ON_CALL(window, OnImeComposition)
64 .WillByDefault(Invoke(&window, &MockWindow::CallOnImeComposition));
65 EXPECT_CALL(window, OnImeComposition(_, _, _)).Times(1);
66
67 // Send an IME_COMPOSITION event that contains just the composition string.
68 window.InjectWindowMessage(WM_IME_COMPOSITION, 0, GCS_COMPSTR);
69}
70
71TEST(MockWindow, OnImeCompositionResult) {
72 auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
73 auto* text_input_manager = new MockTextInputManager();
74 std::unique_ptr<TextInputManager> text_input_manager_ptr(text_input_manager);
75 MockWindow window(std::move(windows_proc_table),
76 std::move(text_input_manager_ptr));
77 EXPECT_CALL(*text_input_manager, GetComposingString())
78 .WillRepeatedly(
79 Return(std::optional<std::u16string>(std::u16string(u"nihao"))));
80 EXPECT_CALL(*text_input_manager, GetResultString())
81 .WillRepeatedly(
82 Return(std::optional<std::u16string>(std::u16string(u"`}"))));
83 EXPECT_CALL(*text_input_manager, GetComposingCursorPosition())
84 .WillRepeatedly(Return((int)0));
85
86 EXPECT_CALL(window, OnComposeChange(std::u16string(u"nihao"), 0)).Times(0);
87 EXPECT_CALL(window, OnComposeChange(std::u16string(u"`}"), 0)).Times(1);
88 EXPECT_CALL(window, OnComposeCommit()).Times(1);
89 ON_CALL(window, OnImeComposition)
90 .WillByDefault(Invoke(&window, &MockWindow::CallOnImeComposition));
91 EXPECT_CALL(window, OnImeComposition(_, _, _)).Times(1);
92
93 // Send an IME_COMPOSITION event that contains just the result string.
94 window.InjectWindowMessage(WM_IME_COMPOSITION, 0, GCS_RESULTSTR);
95}
96
97TEST(MockWindow, OnImeCompositionResultAndCompose) {
98 auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
99 auto* text_input_manager = new MockTextInputManager();
100 std::unique_ptr<TextInputManager> text_input_manager_ptr(text_input_manager);
101 MockWindow window(std::move(windows_proc_table),
102 std::move(text_input_manager_ptr));
103
104 // This situation is that Google Japanese Input finished composing "今日" in
105 // "今日は" but is still composing "は".
106 {
107 InSequence dummy;
108 EXPECT_CALL(*text_input_manager, GetResultString())
109 .WillRepeatedly(
110 Return(std::optional<std::u16string>(std::u16string(u"今日"))));
111 EXPECT_CALL(*text_input_manager, GetComposingString())
112 .WillRepeatedly(
113 Return(std::optional<std::u16string>(std::u16string(u"は"))));
114 }
115 {
116 InSequence dummy;
117 EXPECT_CALL(window, OnComposeChange(std::u16string(u"今日"), 0)).Times(1);
118 EXPECT_CALL(window, OnComposeCommit()).Times(1);
119 EXPECT_CALL(window, OnComposeChange(std::u16string(u"は"), 0)).Times(1);
120 }
121
122 EXPECT_CALL(*text_input_manager, GetComposingCursorPosition())
123 .WillRepeatedly(Return((int)0));
124
125 ON_CALL(window, OnImeComposition)
126 .WillByDefault(Invoke(&window, &MockWindow::CallOnImeComposition));
127 EXPECT_CALL(window, OnImeComposition(_, _, _)).Times(1);
128
129 // send an IME_COMPOSITION event that contains both the result string and the
130 // composition string.
131 window.InjectWindowMessage(WM_IME_COMPOSITION, 0,
132 GCS_COMPSTR | GCS_RESULTSTR);
133}
134
135TEST(MockWindow, OnImeCompositionClearChange) {
136 auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
137 auto* text_input_manager = new MockTextInputManager();
138 std::unique_ptr<TextInputManager> text_input_manager_ptr(text_input_manager);
139 MockWindow window(std::move(windows_proc_table),
140 std::move(text_input_manager_ptr));
141 EXPECT_CALL(window, OnComposeChange(std::u16string(u""), 0)).Times(1);
142 EXPECT_CALL(window, OnComposeCommit()).Times(1);
143 ON_CALL(window, OnImeComposition)
144 .WillByDefault(Invoke(&window, &MockWindow::CallOnImeComposition));
145 EXPECT_CALL(window, OnImeComposition(_, _, _)).Times(1);
146
147 // send an IME_COMPOSITION event that contains both the result string and the
148 // composition string.
149 window.InjectWindowMessage(WM_IME_COMPOSITION, 0, 0);
150}
151
152TEST(MockWindow, HorizontalScroll) {
154 const int scroll_amount = 10;
155 // Vertical scroll should be passed along, adjusted for scroll tick size.
156 EXPECT_CALL(window, OnScroll(scroll_amount / 120.0, 0,
158 .Times(1);
159
160 window.InjectWindowMessage(WM_MOUSEHWHEEL, MAKEWPARAM(0, scroll_amount), 0);
161}
162
163TEST(MockWindow, MouseLeave) {
165 const double mouse_x = 10.0;
166 const double mouse_y = 20.0;
167
168 EXPECT_CALL(window, OnPointerMove(mouse_x, mouse_y,
170 .Times(1);
171 EXPECT_CALL(window, OnPointerLeave(mouse_x, mouse_y,
173 .Times(1);
174
175 window.InjectWindowMessage(WM_MOUSEMOVE, 0, MAKELPARAM(mouse_x, mouse_y));
176 window.InjectWindowMessage(WM_MOUSELEAVE, 0, 0);
177}
178
179TEST(MockWindow, KeyDown) {
181 EXPECT_CALL(window, OnKey(_, _, _, _, _, _, _)).Times(1);
182 LPARAM lparam = CreateKeyEventLparam(42, false, false);
183 // send a "Shift" key down event.
184 window.InjectWindowMessage(WM_KEYDOWN, 16, lparam);
185}
186
189 EXPECT_CALL(window, OnKey(_, _, _, _, _, _, _)).Times(1);
190 LPARAM lparam = CreateKeyEventLparam(42, false, true);
191 // send a "Shift" key up event.
192 window.InjectWindowMessage(WM_KEYUP, 16, lparam);
193}
194
195TEST(MockWindow, SysKeyDown) {
197 EXPECT_CALL(window, OnKey(_, _, _, _, _, _, _)).Times(1);
198 LPARAM lparam = CreateKeyEventLparam(42, false, false);
199 // send a "Shift" key down event.
200 window.InjectWindowMessage(WM_SYSKEYDOWN, 16, lparam);
201}
202
203TEST(MockWindow, SysKeyUp) {
205 EXPECT_CALL(window, OnKey(_, _, _, _, _, _, _)).Times(1);
206 // Prevent default proc for WM_SYSKEYUP which unfocuses the window and sends
207 // WM_MOUSELEAVE.
208 EXPECT_CALL(window, Win32DefWindowProc(_, _, _, _)).Times(0);
209 LPARAM lparam = CreateKeyEventLparam(42, false, true);
210 // send a "Shift" key up event.
211 window.InjectWindowMessage(WM_SYSKEYUP, 16, lparam);
212}
213
214TEST(MockWindow, KeyDownPrintable) {
216 LPARAM lparam = CreateKeyEventLparam(30, false, false);
217
218 auto respond_false = [](int key, int scancode, int action, char32_t character,
219 bool extended, bool was_down,
220 std::function<void(bool)> callback) {
221 callback(false);
222 };
223 EXPECT_CALL(window, OnKey(65, 30, WM_KEYDOWN, 0, false, false, _))
224 .Times(1)
225 .WillOnce(respond_false);
226 EXPECT_CALL(window, OnText(_)).Times(1);
227 std::array<Win32Message, 2> messages = {
228 Win32Message{WM_KEYDOWN, 65, lparam, kWmResultDontCheck},
229 Win32Message{WM_CHAR, 65, lparam, kWmResultDontCheck}};
230 window.InjectMessageList(2, messages.data());
231}
232
233TEST(MockWindow, KeyDownWithCtrl) {
235
236 // Simulate CONTROL pressed
237 std::array<BYTE, 256> keyboard_state;
238 keyboard_state[VK_CONTROL] = -1;
239 SetKeyboardState(keyboard_state.data());
240
241 LPARAM lparam = CreateKeyEventLparam(30, false, false);
242
243 // Expect OnKey, but not OnText, because Control + Key is not followed by
244 // WM_CHAR
245 EXPECT_CALL(window, OnKey(65, 30, WM_KEYDOWN, 0, false, false, _)).Times(1);
246 EXPECT_CALL(window, OnText(_)).Times(0);
247
248 window.InjectWindowMessage(WM_KEYDOWN, 65, lparam);
249
250 keyboard_state.fill(0);
251 SetKeyboardState(keyboard_state.data());
252}
253
254TEST(MockWindow, KeyDownWithCtrlToggled) {
256
257 auto respond_false = [](int key, int scancode, int action, char32_t character,
258 bool extended, bool was_down,
259 std::function<void(bool)> callback) {
260 callback(false);
261 };
262
263 // Simulate CONTROL toggled
264 std::array<BYTE, 256> keyboard_state;
265 keyboard_state[VK_CONTROL] = 1;
266 SetKeyboardState(keyboard_state.data());
267
268 LPARAM lparam = CreateKeyEventLparam(30, false, false);
269
270 EXPECT_CALL(window, OnKey(65, 30, WM_KEYDOWN, 0, false, false, _))
271 .Times(1)
272 .WillOnce(respond_false);
273 EXPECT_CALL(window, OnText(_)).Times(1);
274
275 // send a "A" key down event.
276 Win32Message messages[] = {{WM_KEYDOWN, 65, lparam, kWmResultDontCheck},
277 {WM_CHAR, 65, lparam, kWmResultDontCheck}};
278 window.InjectMessageList(2, messages);
279
280 keyboard_state.fill(0);
281 SetKeyboardState(keyboard_state.data());
282}
283
286 EXPECT_CALL(window, OnPaint()).Times(1);
287 window.InjectWindowMessage(WM_PAINT, 0, 0);
288}
289
290// Verify direct manipulation isn't notified of pointer hit tests.
291TEST(MockWindow, PointerHitTest) {
292 UINT32 pointer_id = 123;
293 auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
294 auto text_input_manager = std::make_unique<MockTextInputManager>();
295
296 EXPECT_CALL(*windows_proc_table, GetPointerType(Eq(pointer_id), _))
297 .Times(1)
298 .WillOnce([](UINT32 pointer_id, POINTER_INPUT_TYPE* type) {
299 *type = PT_POINTER;
300 return TRUE;
301 });
302
303 MockWindow window(std::move(windows_proc_table),
304 std::move(text_input_manager));
305
306 auto direct_manipulation =
307 std::make_unique<MockDirectManipulationOwner>(&window);
308
309 EXPECT_CALL(*direct_manipulation, SetContact).Times(0);
310
311 window.SetDirectManipulationOwner(std::move(direct_manipulation));
312 window.InjectWindowMessage(DM_POINTERHITTEST, MAKEWPARAM(pointer_id, 0), 0);
313}
314
315// Verify direct manipulation is notified of touchpad hit tests.
316TEST(MockWindow, TouchPadHitTest) {
317 UINT32 pointer_id = 123;
318 auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
319 auto text_input_manager = std::make_unique<MockTextInputManager>();
320
321 EXPECT_CALL(*windows_proc_table, GetPointerType(Eq(pointer_id), _))
322 .Times(1)
323 .WillOnce([](UINT32 pointer_id, POINTER_INPUT_TYPE* type) {
324 *type = PT_TOUCHPAD;
325 return TRUE;
326 });
327
328 MockWindow window(std::move(windows_proc_table),
329 std::move(text_input_manager));
330
331 auto direct_manipulation =
332 std::make_unique<MockDirectManipulationOwner>(&window);
333
334 EXPECT_CALL(*direct_manipulation, SetContact(Eq(pointer_id))).Times(1);
335
336 window.SetDirectManipulationOwner(std::move(direct_manipulation));
337 window.InjectWindowMessage(DM_POINTERHITTEST, MAKEWPARAM(pointer_id, 0), 0);
338}
339
340// Verify direct manipulation isn't notified of unknown hit tests.
341// This can happen if determining the pointer type fails, for example,
342// if GetPointerType is unsupported by the current Windows version.
343// See: https://github.com/flutter/flutter/issues/109412
344TEST(MockWindow, UnknownPointerTypeSkipsDirectManipulation) {
345 UINT32 pointer_id = 123;
346 auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
347 auto text_input_manager = std::make_unique<MockTextInputManager>();
348
349 EXPECT_CALL(*windows_proc_table, GetPointerType(Eq(pointer_id), _))
350 .Times(1)
351 .WillOnce(
352 [](UINT32 pointer_id, POINTER_INPUT_TYPE* type) { return FALSE; });
353
354 MockWindow window(std::move(windows_proc_table),
355 std::move(text_input_manager));
356
357 auto direct_manipulation =
358 std::make_unique<MockDirectManipulationOwner>(&window);
359
360 EXPECT_CALL(*direct_manipulation, SetContact).Times(0);
361
362 window.SetDirectManipulationOwner(std::move(direct_manipulation));
363 window.InjectWindowMessage(DM_POINTERHITTEST, MAKEWPARAM(pointer_id, 0), 0);
364}
365
366// Test that the root UIA object is queried by WM_GETOBJECT.
367TEST(MockWindow, DISABLED_GetObjectUia) {
369 bool uia_called = false;
370 ON_CALL(window, OnGetObject)
371 .WillByDefault([&uia_called](UINT msg, WPARAM wpar, LPARAM lpar) {
372#ifdef FLUTTER_ENGINE_USE_UIA
373 uia_called = true;
374#endif // FLUTTER_ENGINE_USE_UIA
375 return static_cast<LRESULT>(0);
376 });
377 EXPECT_CALL(window, OnGetObject).Times(1);
378
379 window.InjectWindowMessage(WM_GETOBJECT, 0, UiaRootObjectId);
380
381 EXPECT_TRUE(uia_called);
382}
383
384} // namespace testing
385} // namespace flutter
Mock for the |Window| base class.
Mock for the |FlutterWindow| base class.
Definition mock_window.h:17
LRESULT InjectWindowMessage(UINT const message, WPARAM const wparam, LPARAM const lparam)
void CallOnImeComposition(UINT const message, WPARAM const wparam, LPARAM const lparam)
@ kFlutterPointerDeviceKindMouse
Definition embedder.h:1310
GLFWwindow * window
Definition main.cc:60
return TRUE
FlutterDesktopBinaryReply callback
TEST(NativeAssetsManagerTest, NoAvailableAssets)
constexpr LRESULT kWmResultDontCheck
Definition wm_builders.h:16
LPARAM CreateKeyEventLparam(USHORT scancode, bool extended, bool was_down, USHORT repeat_count, bool context_code, bool transition_state)
impeller::ShaderType type
LONG_PTR LRESULT
unsigned int UINT
LONG_PTR LPARAM
UINT_PTR WPARAM