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.
5 
6 #include <memory>
7 #include <vector>
8 
9 #include "flutter/fml/macros.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 
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 
67  FlutterWindowsEngineBuilder builder{GetContext()};
68 
69  engine_ = builder.Build();
70  }
71 
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