| Flutter Windows Embedder |

cursor_handler_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 #include "flutter/shell/platform/windows/cursor_handler.h"
5
6 #include <memory>
7 #include <vector>
8
9 #include "flutter/fml/macros.h"
10 #include "flutter/shell/platform/common/client_wrapper/include/flutter/method_result_functions.h"
11 #include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_message_codec.h"
12 #include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_method_codec.h"
13 #include "flutter/shell/platform/windows/flutter_windows_view.h"
14 #include "flutter/shell/platform/windows/testing/engine_modifier.h"
15 #include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h"
16 #include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
17 #include "flutter/shell/platform/windows/testing/test_binary_messenger.h"
18 #include "flutter/shell/platform/windows/testing/windows_test.h"
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21
22 namespace flutter {
23 namespace testing {
24
25 namespace {
26 using ::testing::_;
27 using ::testing::NotNull;
28 using ::testing::Return;
29
30 static constexpr char kChannelName[] = "flutter/mousecursor";
31
32 static constexpr char kActivateSystemCursorMethod[] = "activateSystemCursor";
33 static constexpr char kCreateCustomCursorMethod[] =
34 "createCustomCursor/windows";
35 static constexpr char kSetCustomCursorMethod[] = "setCustomCursor/windows";
36 static constexpr char kDeleteCustomCursorMethod[] =
37 "deleteCustomCursor/windows";
38
39 void SimulateCursorMessage(TestBinaryMessenger* messenger,
40 const std::string& method_name,
41 std::unique_ptr<EncodableValue> arguments,
42 MethodResult<EncodableValue>* result_handler) {
43 MethodCall<> call(method_name, std::move(arguments));
44
45 auto message = StandardMethodCodec::GetInstance().EncodeMethodCall(call);
46
47 EXPECT_TRUE(messenger->SimulateEngineMessage(
48 kChannelName, message->data(), message->size(),
49 [&result_handler](const uint8_t* reply, size_t reply_size) {
50 StandardMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope(
51 reply, reply_size, result_handler);
52 }));
53 }
54
55 } // namespace
56
57 class CursorHandlerTest : public WindowsTest {
58 public:
59 CursorHandlerTest() = default;
60 virtual ~CursorHandlerTest() = default;
61
62 protected:
63 FlutterWindowsEngine* engine() { return engine_.get(); }
64 FlutterWindowsView* view() { return view_.get(); }
65 MockWindowBindingHandler* window() { return window_; }
66
67 void UseHeadlessEngine() {
68 FlutterWindowsEngineBuilder builder{GetContext()};
69
70 engine_ = builder.Build();
71 }
72
73 void UseEngineWithView() {
74 FlutterWindowsEngineBuilder builder{GetContext()};
75
76 auto window = std::make_unique<MockWindowBindingHandler>();
77 EXPECT_CALL(*window.get(), SetView).Times(1);
78 EXPECT_CALL(*window.get(), GetWindowHandle).WillRepeatedly(Return(nullptr));
79
80 window_ = window.get();
81 engine_ = builder.Build();
82 view_ = std::make_unique<FlutterWindowsView>(kImplicitViewId, engine_.get(),
83 std::move(window));
84
85 EngineModifier modifier{engine_.get()};
86 modifier.SetImplicitView(view_.get());
87 }
88
89 private:
90 std::unique_ptr<FlutterWindowsEngine> engine_;
91 std::unique_ptr<FlutterWindowsView> view_;
92 MockWindowBindingHandler* window_;
93
94 FML_DISALLOW_COPY_AND_ASSIGN(CursorHandlerTest);
95 };
96
97 TEST_F(CursorHandlerTest, ActivateSystemCursor) {
98 UseEngineWithView();
99
100 TestBinaryMessenger messenger;
101 CursorHandler cursor_handler(&messenger, engine());
102
103 EXPECT_CALL(*window(), UpdateFlutterCursor("click")).Times(1);
104
105 bool success = false;
106 MethodResultFunctions<> result_handler(
107 [&success](const EncodableValue* result) {
108 success = true;
109 EXPECT_EQ(result, nullptr);
110 },
111 nullptr, nullptr);
112
113 SimulateCursorMessage(&messenger, kActivateSystemCursorMethod,
114 std::make_unique<EncodableValue>(EncodableMap{
115 {EncodableValue("device"), EncodableValue(0)},
116 {EncodableValue("kind"), EncodableValue("click")},
117 }),
118 &result_handler);
119
120 EXPECT_TRUE(success);
121 }
122
123 TEST_F(CursorHandlerTest, ActivateSystemCursorRequiresView) {
124 UseHeadlessEngine();
125
126 TestBinaryMessenger messenger;
127 CursorHandler cursor_handler(&messenger, engine());
128
129 bool error = false;
130 MethodResultFunctions<> result_handler(
131 nullptr,
132 [&error](const std::string& error_code, const std::string& error_message,
133 const EncodableValue* value) {
134 error = true;
135 EXPECT_EQ(error_message,
136 "Cursor is not available in Windows headless mode");
137 },
138 nullptr);
139
140 SimulateCursorMessage(&messenger, kActivateSystemCursorMethod,
141 std::make_unique<EncodableValue>(EncodableMap{
142 {EncodableValue("device"), EncodableValue(0)},
143 {EncodableValue("kind"), EncodableValue("click")},
144 }),
145 &result_handler);
146
147 EXPECT_TRUE(error);
148 }
149
150 TEST_F(CursorHandlerTest, CreateCustomCursor) {
151 UseEngineWithView();
152
153 TestBinaryMessenger messenger;
154 CursorHandler cursor_handler(&messenger, engine());
155
156 // Create a 4x4 raw BGRA test cursor buffer.
157 std::vector<uint8_t> buffer(4 * 4 * 4, 0);
158
159 bool success = false;
160 MethodResultFunctions<> result_handler(
161 [&success](const EncodableValue* result) {
162 success = true;
163 EXPECT_EQ(std::get<std::string>(*result), "hello");
164 },
165 nullptr, nullptr);
166
167 SimulateCursorMessage(&messenger, kCreateCustomCursorMethod,
168 std::make_unique<EncodableValue>(EncodableMap{
169 {EncodableValue("name"), EncodableValue("hello")},
170 {EncodableValue("buffer"), EncodableValue(buffer)},
171 {EncodableValue("width"), EncodableValue(4)},
172 {EncodableValue("height"), EncodableValue(4)},
173 {EncodableValue("hotX"), EncodableValue(0.0)},
174 {EncodableValue("hotY"), EncodableValue(0.0)},
175 }),
176 &result_handler);
177
178 EXPECT_TRUE(success);
179 }
180
181 TEST_F(CursorHandlerTest, SetCustomCursor) {
182 UseEngineWithView();
183
184 TestBinaryMessenger messenger;
185 CursorHandler cursor_handler(&messenger, engine());
186
187 // Create a 4x4 raw BGRA test cursor buffer.
188 std::vector<uint8_t> buffer(4 * 4 * 4, 0);
189
190 bool success = false;
191 MethodResultFunctions<> create_result_handler(nullptr, nullptr, nullptr);
192 MethodResultFunctions<> set_result_handler(
193 [&success](const EncodableValue* result) {
194 success = true;
195 EXPECT_EQ(result, nullptr);
196 },
197 nullptr, nullptr);
198
199 EXPECT_CALL(*window(), SetFlutterCursor(/*cursor=*/NotNull())).Times(1);
200
201 SimulateCursorMessage(&messenger, kCreateCustomCursorMethod,
202 std::make_unique<EncodableValue>(EncodableMap{
203 {EncodableValue("name"), EncodableValue("hello")},
204 {EncodableValue("buffer"), EncodableValue(buffer)},
205 {EncodableValue("width"), EncodableValue(4)},
206 {EncodableValue("height"), EncodableValue(4)},
207 {EncodableValue("hotX"), EncodableValue(0.0)},
208 {EncodableValue("hotY"), EncodableValue(0.0)},
209 }),
210 &create_result_handler);
211
212 SimulateCursorMessage(&messenger, kSetCustomCursorMethod,
213 std::make_unique<EncodableValue>(EncodableMap{
214 {EncodableValue("name"), EncodableValue("hello")},
215 }),
216 &set_result_handler);
217
218 EXPECT_TRUE(success);
219 }
220
221 TEST_F(CursorHandlerTest, SetCustomCursorRequiresView) {
222 UseHeadlessEngine();
223
224 TestBinaryMessenger messenger;
225 CursorHandler cursor_handler(&messenger, engine());
226
227 // Create a 4x4 raw BGRA test cursor buffer.
228 std::vector<uint8_t> buffer(4 * 4 * 4, 0);
229
230 bool error = false;
231 MethodResultFunctions<> create_result_handler(nullptr, nullptr, nullptr);
232 MethodResultFunctions<> set_result_handler(
233 nullptr,
234 [&error](const std::string& error_code, const std::string& error_message,
235 const EncodableValue* value) {
236 error = true;
237 EXPECT_EQ(error_message,
238 "Cursor is not available in Windows headless mode");
239 },
240 nullptr);
241
242 SimulateCursorMessage(&messenger, kCreateCustomCursorMethod,
243 std::make_unique<EncodableValue>(EncodableMap{
244 {EncodableValue("name"), EncodableValue("hello")},
245 {EncodableValue("buffer"), EncodableValue(buffer)},
246 {EncodableValue("width"), EncodableValue(4)},
247 {EncodableValue("height"), EncodableValue(4)},
248 {EncodableValue("hotX"), EncodableValue(0.0)},
249 {EncodableValue("hotY"), EncodableValue(0.0)},
250 }),
251 &create_result_handler);
252
253 SimulateCursorMessage(&messenger, kSetCustomCursorMethod,
254 std::make_unique<EncodableValue>(EncodableMap{
255 {EncodableValue("name"), EncodableValue("hello")},
256 }),
257 &set_result_handler);
258
259 EXPECT_TRUE(error);
260 }
261
262 TEST_F(CursorHandlerTest, SetNonexistentCustomCursor) {
263 UseEngineWithView();
264
265 TestBinaryMessenger messenger;
266 CursorHandler cursor_handler(&messenger, engine());
267
268 bool error = false;
269 MethodResultFunctions<> result_handler(
270 nullptr,
271 [&error](const std::string& error_code, const std::string& error_message,
272 const EncodableValue* value) {
273 error = true;
274 EXPECT_EQ(
275 error_message,
276 "The custom cursor identified by the argument key cannot be found");
277 },
278 nullptr);
279
280 EXPECT_CALL(*window(), SetFlutterCursor).Times(0);
281
282 SimulateCursorMessage(&messenger, kSetCustomCursorMethod,
283 std::make_unique<EncodableValue>(EncodableMap{
284 {EncodableValue("name"), EncodableValue("hello")},
285 }),
286 &result_handler);
287
288 EXPECT_TRUE(error);
289 }
290
291 TEST_F(CursorHandlerTest, DeleteCustomCursor) {
292 UseEngineWithView();
293
294 TestBinaryMessenger messenger;
295 CursorHandler cursor_handler(&messenger, engine());
296
297 // Create a 4x4 raw BGRA test cursor buffer.
298 std::vector<uint8_t> buffer(4 * 4 * 4, 0);
299
300 bool success = false;
301 MethodResultFunctions<> create_result_handler(nullptr, nullptr, nullptr);
302 MethodResultFunctions<> delete_result_handler(
303 [&success](const EncodableValue* result) {
304 success = true;
305 EXPECT_EQ(result, nullptr);
306 },
307 nullptr, nullptr);
308
309 SimulateCursorMessage(&messenger, kCreateCustomCursorMethod,
310 std::make_unique<EncodableValue>(EncodableMap{
311 {EncodableValue("name"), EncodableValue("hello")},
312 {EncodableValue("buffer"), EncodableValue(buffer)},
313 {EncodableValue("width"), EncodableValue(4)},
314 {EncodableValue("height"), EncodableValue(4)},
315 {EncodableValue("hotX"), EncodableValue(0.0)},
316 {EncodableValue("hotY"), EncodableValue(0.0)},
317 }),
318 &create_result_handler);
319
320 SimulateCursorMessage(&messenger, kDeleteCustomCursorMethod,
321 std::make_unique<EncodableValue>(EncodableMap{
322 {EncodableValue("name"), EncodableValue("hello")},
323 }),
324 &delete_result_handler);
325
326 EXPECT_TRUE(success);
327 }
328
329 TEST_F(CursorHandlerTest, DeleteNonexistentCustomCursor) {
330 UseEngineWithView();
331
332 TestBinaryMessenger messenger;
333 CursorHandler cursor_handler(&messenger, engine());
334
335 bool success = false;
336 MethodResultFunctions<> result_handler(
337 [&success](const EncodableValue* result) {
338 success = true;
339 EXPECT_EQ(result, nullptr);
340 },
341 nullptr, nullptr);
342
343 SimulateCursorMessage(&messenger, kDeleteCustomCursorMethod,
344 std::make_unique<EncodableValue>(EncodableMap{
345 {EncodableValue("name"), EncodableValue("fake")},
346 }),
347 &result_handler);
348
349 EXPECT_TRUE(success);
350 }
351
352 } // namespace testing
353 } // namespace flutter
flutter::CursorHandler
Definition: cursor_handler.h:22
flutter::EncodableValue
Definition: encodable_value.h:165
flutter::FlutterWindowsEngine
Definition: flutter_windows_engine.h:90
flutter::FlutterWindowsView
Definition: flutter_windows_view.h:34
flutter::MethodCodec::EncodeMethodCall
std::unique_ptr< std::vector< uint8_t > > EncodeMethodCall(const MethodCall< T > &method_call) const
Definition: method_codec.h:48
flutter::MethodResultFunctions
Definition: method_result_functions.h:31
flutter::StandardMethodCodec::GetInstance
static const StandardMethodCodec & GetInstance(const StandardCodecSerializer *serializer=nullptr)
Definition: standard_codec.cc:340
flutter::testing::CursorHandlerTest
Definition: cursor_handler_unittests.cc:57
flutter::testing::CursorHandlerTest::UseHeadlessEngine
void UseHeadlessEngine()
Definition: cursor_handler_unittests.cc:67
flutter::testing::CursorHandlerTest::UseEngineWithView
void UseEngineWithView()
Definition: cursor_handler_unittests.cc:73
flutter::testing::CursorHandlerTest::CursorHandlerTest
CursorHandlerTest()=default
flutter::testing::CursorHandlerTest::window
MockWindowBindingHandler * window()
Definition: cursor_handler_unittests.cc:65
flutter::testing::CursorHandlerTest::view
FlutterWindowsView * view()
Definition: cursor_handler_unittests.cc:64
flutter::testing::CursorHandlerTest::engine
FlutterWindowsEngine * engine()
Definition: cursor_handler_unittests.cc:63
flutter::testing::CursorHandlerTest::~CursorHandlerTest
virtual ~CursorHandlerTest()=default
kDeleteCustomCursorMethod
static constexpr char kDeleteCustomCursorMethod[]
Definition: cursor_handler.cc:42
kActivateSystemCursorMethod
static constexpr char kActivateSystemCursorMethod[]
Definition: cursor_handler.cc:15
kChannelName
static constexpr char kChannelName[]
Definition: cursor_handler.cc:13
kCreateCustomCursorMethod
static constexpr char kCreateCustomCursorMethod[]
Definition: cursor_handler.cc:20
kSetCustomCursorMethod
static constexpr char kSetCustomCursorMethod[]
Definition: cursor_handler.cc:38
cursor_handler.h
flutter_windows_view.h
message
Win32Message message
Definition: keyboard_unittests.cc:137
method_result_functions.h
flutter::testing::TEST_F
TEST_F(CompositorOpenGLTest, CreateBackingStore)
Definition: compositor_opengl_unittests.cc:125
flutter
Definition: accessibility_bridge_windows.cc:11
flutter::EncodableMap
std::map< EncodableValue, EncodableValue > EncodableMap
Definition: encodable_value.h:95
flutter::kImplicitViewId
constexpr FlutterViewId kImplicitViewId
Definition: flutter_windows_engine.h:55
standard_message_codec.h
standard_method_codec.h