Flutter Engine
The Flutter Engine
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
22namespace flutter {
23namespace testing {
24
25namespace {
26using ::testing::_;
27using ::testing::NotNull;
28using ::testing::Return;
29
30static constexpr char kChannelName[] = "flutter/mousecursor";
31
32static constexpr char kActivateSystemCursorMethod[] = "activateSystemCursor";
33static constexpr char kCreateCustomCursorMethod[] =
34 "createCustomCursor/windows";
35static constexpr char kSetCustomCursorMethod[] = "setCustomCursor/windows";
36static constexpr char kDeleteCustomCursorMethod[] =
37 "deleteCustomCursor/windows";
38
39void 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
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
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
69
70 engine_ = builder.Build();
71 }
72
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_;
93
94 FML_DISALLOW_COPY_AND_ASSIGN(CursorHandlerTest);
95};
96
97TEST_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
123TEST_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
148}
149
150TEST_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")},
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
181TEST_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")},
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
221TEST_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")},
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
260}
261
262TEST_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
289}
290
291TEST_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")},
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
329TEST_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
static NSString *const kChannelName
static NSString *const kActivateSystemCursorMethod
std::unique_ptr< std::vector< uint8_t > > EncodeMethodCall(const MethodCall< T > &method_call) const
Definition: method_codec.h:48
static const StandardMethodCodec & GetInstance(const StandardCodecSerializer *serializer=nullptr)
WindowsTestContext & GetContext()
Definition: windows_test.cc:21
static constexpr char kDeleteCustomCursorMethod[]
static constexpr char kCreateCustomCursorMethod[]
static constexpr char kSetCustomCursorMethod[]
GLFWwindow * window
Definition: main.cc:45
FlutterEngine engine
Definition: main.cc:68
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
GAsyncResult * result
Win32Message message
def call(args)
Definition: dom.py:159
TEST_F(DisplayListTest, Defaults)
constexpr int64_t kImplicitViewId
std::map< EncodableValue, EncodableValue > EncodableMap
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678