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