| 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 UseHeadlessEngine() {
67 FlutterWindowsEngineBuilder builder{GetContext()};
68
69 engine_ = builder.Build();
70 }
71
72 void UseEngineWithView() {
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
80 engine_ = builder.Build();
81 view_ = std::make_unique<FlutterWindowsView>(std::move(window));
82
83 engine_->SetView(view_.get());
84 }
85
86 private:
87 std::unique_ptr<FlutterWindowsEngine> engine_;
88 std::unique_ptr<FlutterWindowsView> view_;
89 MockWindowBindingHandler* window_;
90
91 FML_DISALLOW_COPY_AND_ASSIGN(CursorHandlerTest);
92 };
93
94 TEST_F(CursorHandlerTest, ActivateSystemCursor) {
95 UseEngineWithView();
96
97 TestBinaryMessenger messenger;
98 CursorHandler cursor_handler(&messenger, engine());
99
100 EXPECT_CALL(*window(), UpdateFlutterCursor("click")).Times(1);
101
102 bool success = false;
103 MethodResultFunctions<> result_handler(
104 [&success](const EncodableValue* result) {
105 success = true;
106 EXPECT_EQ(result, nullptr);
107 },
108 nullptr, nullptr);
109
110 SimulateCursorMessage(&messenger, kActivateSystemCursorMethod,
111 std::make_unique<EncodableValue>(EncodableMap{
112 {EncodableValue("device"), EncodableValue(0)},
113 {EncodableValue("kind"), EncodableValue("click")},
114 }),
115 &result_handler);
116
117 EXPECT_TRUE(success);
118 }
119
120 TEST_F(CursorHandlerTest, ActivateSystemCursorRequiresView) {
121 UseHeadlessEngine();
122
123 TestBinaryMessenger messenger;
124 CursorHandler cursor_handler(&messenger, engine());
125
126 bool error = false;
127 MethodResultFunctions<> result_handler(
128 nullptr,
129 [&error](const std::string& error_code, const std::string& error_message,
130 const EncodableValue* value) {
131 error = true;
132 EXPECT_EQ(error_message,
133 "Cursor is not available in Windows headless mode");
134 },
135 nullptr);
136
137 SimulateCursorMessage(&messenger, kActivateSystemCursorMethod,
138 std::make_unique<EncodableValue>(EncodableMap{
139 {EncodableValue("device"), EncodableValue(0)},
140 {EncodableValue("kind"), EncodableValue("click")},
141 }),
142 &result_handler);
143
144 EXPECT_TRUE(error);
145 }
146
147 TEST_F(CursorHandlerTest, CreateCustomCursor) {
148 UseEngineWithView();
149
150 TestBinaryMessenger messenger;
151 CursorHandler cursor_handler(&messenger, engine());
152
153 // Create a 4x4 raw BGRA test cursor buffer.
154 std::vector<uint8_t> buffer(4 * 4 * 4, 0);
155
156 bool success = false;
157 MethodResultFunctions<> result_handler(
158 [&success](const EncodableValue* result) {
159 success = true;
160 EXPECT_EQ(std::get<std::string>(*result), "hello");
161 },
162 nullptr, nullptr);
163
164 SimulateCursorMessage(&messenger, kCreateCustomCursorMethod,
165 std::make_unique<EncodableValue>(EncodableMap{
166 {EncodableValue("name"), EncodableValue("hello")},
167 {EncodableValue("buffer"), EncodableValue(buffer)},
168 {EncodableValue("width"), EncodableValue(4)},
169 {EncodableValue("height"), EncodableValue(4)},
170 {EncodableValue("hotX"), EncodableValue(0.0)},
171 {EncodableValue("hotY"), EncodableValue(0.0)},
172 }),
173 &result_handler);
174
175 EXPECT_TRUE(success);
176 }
177
178 TEST_F(CursorHandlerTest, SetCustomCursor) {
179 UseEngineWithView();
180
181 TestBinaryMessenger messenger;
182 CursorHandler cursor_handler(&messenger, engine());
183
184 // Create a 4x4 raw BGRA test cursor buffer.
185 std::vector<uint8_t> buffer(4 * 4 * 4, 0);
186
187 bool success = false;
188 MethodResultFunctions<> create_result_handler(nullptr, nullptr, nullptr);
189 MethodResultFunctions<> set_result_handler(
190 [&success](const EncodableValue* result) {
191 success = true;
192 EXPECT_EQ(result, nullptr);
193 },
194 nullptr, nullptr);
195
196 EXPECT_CALL(*window(), SetFlutterCursor(/*cursor=*/NotNull())).Times(1);
197
198 SimulateCursorMessage(&messenger, kCreateCustomCursorMethod,
199 std::make_unique<EncodableValue>(EncodableMap{
200 {EncodableValue("name"), EncodableValue("hello")},
201 {EncodableValue("buffer"), EncodableValue(buffer)},
202 {EncodableValue("width"), EncodableValue(4)},
203 {EncodableValue("height"), EncodableValue(4)},
204 {EncodableValue("hotX"), EncodableValue(0.0)},
205 {EncodableValue("hotY"), EncodableValue(0.0)},
206 }),
207 &create_result_handler);
208
209 SimulateCursorMessage(&messenger, kSetCustomCursorMethod,
210 std::make_unique<EncodableValue>(EncodableMap{
211 {EncodableValue("name"), EncodableValue("hello")},
212 }),
213 &set_result_handler);
214
215 EXPECT_TRUE(success);
216 }
217
218 TEST_F(CursorHandlerTest, SetCustomCursorRequiresView) {
219 UseHeadlessEngine();
220
221 TestBinaryMessenger messenger;
222 CursorHandler cursor_handler(&messenger, engine());
223
224 // Create a 4x4 raw BGRA test cursor buffer.
225 std::vector<uint8_t> buffer(4 * 4 * 4, 0);
226
227 bool error = false;
228 MethodResultFunctions<> create_result_handler(nullptr, nullptr, nullptr);
229 MethodResultFunctions<> set_result_handler(
230 nullptr,
231 [&error](const std::string& error_code, const std::string& error_message,
232 const EncodableValue* value) {
233 error = true;
234 EXPECT_EQ(error_message,
235 "Cursor is not available in Windows headless mode");
236 },
237 nullptr);
238
239 SimulateCursorMessage(&messenger, kCreateCustomCursorMethod,
240 std::make_unique<EncodableValue>(EncodableMap{
241 {EncodableValue("name"), EncodableValue("hello")},
242 {EncodableValue("buffer"), EncodableValue(buffer)},
243 {EncodableValue("width"), EncodableValue(4)},
244 {EncodableValue("height"), EncodableValue(4)},
245 {EncodableValue("hotX"), EncodableValue(0.0)},
246 {EncodableValue("hotY"), EncodableValue(0.0)},
247 }),
248 &create_result_handler);
249
250 SimulateCursorMessage(&messenger, kSetCustomCursorMethod,
251 std::make_unique<EncodableValue>(EncodableMap{
252 {EncodableValue("name"), EncodableValue("hello")},
253 }),
254 &set_result_handler);
255
256 EXPECT_TRUE(error);
257 }
258
259 TEST_F(CursorHandlerTest, SetNonexistentCustomCursor) {
260 UseEngineWithView();
261
262 TestBinaryMessenger messenger;
263 CursorHandler cursor_handler(&messenger, engine());
264
265 bool error = false;
266 MethodResultFunctions<> result_handler(
267 nullptr,
268 [&error](const std::string& error_code, const std::string& error_message,
269 const EncodableValue* value) {
270 error = true;
271 EXPECT_EQ(
272 error_message,
273 "The custom cursor identified by the argument key cannot be found");
274 },
275 nullptr);
276
277 EXPECT_CALL(*window(), SetFlutterCursor).Times(0);
278
279 SimulateCursorMessage(&messenger, kSetCustomCursorMethod,
280 std::make_unique<EncodableValue>(EncodableMap{
281 {EncodableValue("name"), EncodableValue("hello")},
282 }),
283 &result_handler);
284
285 EXPECT_TRUE(error);
286 }
287
288 TEST_F(CursorHandlerTest, DeleteCustomCursor) {
289 UseEngineWithView();
290
291 TestBinaryMessenger messenger;
292 CursorHandler cursor_handler(&messenger, engine());
293
294 // Create a 4x4 raw BGRA test cursor buffer.
295 std::vector<uint8_t> buffer(4 * 4 * 4, 0);
296
297 bool success = false;
298 MethodResultFunctions<> create_result_handler(nullptr, nullptr, nullptr);
299 MethodResultFunctions<> delete_result_handler(
300 [&success](const EncodableValue* result) {
301 success = true;
302 EXPECT_EQ(result, nullptr);
303 },
304 nullptr, nullptr);
305
306 SimulateCursorMessage(&messenger, kCreateCustomCursorMethod,
307 std::make_unique<EncodableValue>(EncodableMap{
308 {EncodableValue("name"), EncodableValue("hello")},
309 {EncodableValue("buffer"), EncodableValue(buffer)},
310 {EncodableValue("width"), EncodableValue(4)},
311 {EncodableValue("height"), EncodableValue(4)},
312 {EncodableValue("hotX"), EncodableValue(0.0)},
313 {EncodableValue("hotY"), EncodableValue(0.0)},
314 }),
315 &create_result_handler);
316
317 SimulateCursorMessage(&messenger, kDeleteCustomCursorMethod,
318 std::make_unique<EncodableValue>(EncodableMap{
319 {EncodableValue("name"), EncodableValue("hello")},
320 }),
321 &delete_result_handler);
322
323 EXPECT_TRUE(success);
324 }
325
326 TEST_F(CursorHandlerTest, DeleteNonexistentCustomCursor) {
327 UseEngineWithView();
328
329 TestBinaryMessenger messenger;
330 CursorHandler cursor_handler(&messenger, engine());
331
332 bool success = false;
333 MethodResultFunctions<> result_handler(
334 [&success](const EncodableValue* result) {
335 success = true;
336 EXPECT_EQ(result, nullptr);
337 },
338 nullptr, nullptr);
339
340 SimulateCursorMessage(&messenger, kDeleteCustomCursorMethod,
341 std::make_unique<EncodableValue>(EncodableMap{
342 {EncodableValue("name"), EncodableValue("fake")},
343 }),
344 &result_handler);
345
346 EXPECT_TRUE(success);
347 }
348
349 } // namespace testing
350 } // 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:94
standard_message_codec.h
flutter::testing::CursorHandlerTest::UseEngineWithView
void UseEngineWithView()
Definition: cursor_handler_unittests.cc:72
flutter::testing::CursorHandlerTest::view
FlutterWindowsView * view()
Definition: cursor_handler_unittests.cc:63
flutter::testing::CursorHandlerTest::UseHeadlessEngine
void UseHeadlessEngine()
Definition: cursor_handler_unittests.cc:66
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
message
Win32Message message
Definition: keyboard_unittests.cc:137
cursor_handler.h
flutter::EncodableMap
std::map< EncodableValue, EncodableValue > EncodableMap
Definition: encodable_value.h:95
flutter::StandardMethodCodec::GetInstance
static const StandardMethodCodec & GetInstance(const StandardCodecSerializer *serializer=nullptr)
Definition: standard_codec.cc:340
flutter::MethodResultFunctions
Definition: method_result_functions.h:31