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  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