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/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 
22 namespace flutter {
23 namespace testing {
24 
25 namespace {
26 using ::testing::_;
27 using ::testing::NotNull;
28 using ::testing::Return;
29 
30 static constexpr char kChannelName[] = "flutter/mousecursor";
31 
32 static constexpr char kActivateSystemCursorMethod[] = "activateSystemCursor";
33 static constexpr char kCreateCustomCursorMethod[] =
34  "createCustomCursor/windows";
35 static constexpr char kSetCustomCursorMethod[] = "setCustomCursor/windows";
36 static constexpr char kDeleteCustomCursorMethod[] =
37  "deleteCustomCursor/windows";
38 
39 void 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 
57 class CursorHandlerTest : public WindowsTest {
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 
68  FlutterWindowsEngineBuilder builder{GetContext()};
69 
70  engine_ = builder.Build();
71  }
72 
74  FlutterWindowsEngineBuilder builder{GetContext()};
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_;
92  MockWindowBindingHandler* window_;
93 
94  FML_DISALLOW_COPY_AND_ASSIGN(CursorHandlerTest);
95 };
96 
97 TEST_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 
123 TEST_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 
147  EXPECT_TRUE(error);
148 }
149 
150 TEST_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")},
170  {EncodableValue("buffer"), EncodableValue(buffer)},
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 
181 TEST_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")},
204  {EncodableValue("buffer"), EncodableValue(buffer)},
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 
221 TEST_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")},
245  {EncodableValue("buffer"), EncodableValue(buffer)},
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 
259  EXPECT_TRUE(error);
260 }
261 
262 TEST_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 
288  EXPECT_TRUE(error);
289 }
290 
291 TEST_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")},
312  {EncodableValue("buffer"), EncodableValue(buffer)},
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 
329 TEST_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
flutter::testing::CursorHandlerTest::CursorHandlerTest
CursorHandlerTest()=default
flutter::kImplicitViewId
constexpr FlutterViewId kImplicitViewId
Definition: flutter_windows_engine.h:54
flutter::FlutterWindowsView
Definition: flutter_windows_view.h:34
flutter::testing::CursorHandlerTest::window
MockWindowBindingHandler * window()
Definition: cursor_handler_unittests.cc:65
flutter::CursorHandler
Definition: cursor_handler.h:22
method_result_functions.h
flutter::FlutterWindowsEngine
Definition: flutter_windows_engine.h:89
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:57
kActivateSystemCursorMethod
static constexpr char kActivateSystemCursorMethod[]
Definition: cursor_handler.cc:15
flutter_windows_view.h
standard_message_codec.h
flutter::testing::CursorHandlerTest::UseEngineWithView
void UseEngineWithView()
Definition: cursor_handler_unittests.cc:73
flutter::testing::CursorHandlerTest::view
FlutterWindowsView * view()
Definition: cursor_handler_unittests.cc:64
flutter::testing::CursorHandlerTest::UseHeadlessEngine
void UseHeadlessEngine()
Definition: cursor_handler_unittests.cc:67
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:63
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::testing::TEST_F
TEST_F(CompositorOpenGLTest, CreateBackingStore)
Definition: compositor_opengl_unittests.cc:128
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