Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
fl_binary_messenger_test.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
5// Included first as it collides with the X11 headers.
7#include "gtest/gtest.h"
8
9#include <pthread.h>
10#include <cstring>
11
18
20
21// Checks can send a message.
23 StartEngine();
24
25 FlutterDataCallback response_callback;
26 void* response_callback_user_data;
29 PlatformMessageCreateResponseHandle,
30 ([&response_callback, &response_callback_user_data](
31 auto engine, FlutterDataCallback data_callback, void* user_data,
33 response_callback = data_callback;
34 response_callback_user_data = user_data;
35 return kSuccess;
36 }));
38 SendPlatformMessage,
39 ([&response_callback, &response_callback_user_data](
41 EXPECT_STREQ(message->channel, "test");
42 g_autofree gchar* text =
43 g_strndup(reinterpret_cast<const gchar*>(message->message),
44 message->message_size);
45 EXPECT_STREQ(text, "Marco!");
46
47 const gchar* response = "Polo!";
48 response_callback(reinterpret_cast<const uint8_t*>(response),
49 strlen(response), response_callback_user_data);
50
51 return kSuccess;
52 }));
53
54 g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine);
55 const char* text = "Marco!";
56 g_autoptr(GBytes) message = g_bytes_new(text, strlen(text));
58 messenger, "test", message, nullptr,
59 [](GObject* object, GAsyncResult* result, gpointer user_data) {
60 g_autoptr(GError) error = nullptr;
62 FL_BINARY_MESSENGER(object), result, &error);
63 EXPECT_NE(message, nullptr);
64 EXPECT_EQ(error, nullptr);
65
66 g_autofree gchar* text = g_strndup(
67 static_cast<const gchar*>(g_bytes_get_data(message, nullptr)),
68 g_bytes_get_size(message));
69 EXPECT_STREQ(text, "Polo!");
70
71 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
72 },
73 loop);
74
75 g_main_loop_run(loop);
76}
77
78// Checks sending nullptr for a message works.
80 StartEngine();
81
82 bool called = false;
84 SendPlatformMessage,
85 ([&called](auto engine, const FlutterPlatformMessage* message) {
86 called = true;
87
88 EXPECT_STREQ(message->channel, "test");
89 // Note we don't check message->message as it could be nullptr or a
90 // pointer to an buffer - either way it wouldn't be accessed.
91 EXPECT_EQ(message->message_size, static_cast<size_t>(0));
92
93 return kSuccess;
94 }));
95
96 g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine);
97 fl_binary_messenger_send_on_channel(messenger, "test", nullptr, nullptr,
98 nullptr, nullptr);
99 EXPECT_TRUE(called);
100}
101
102// Checks sending a zero length message works.
104 StartEngine();
105
106 bool called = false;
108 SendPlatformMessage,
109 ([&called](auto engine, const FlutterPlatformMessage* message) {
110 called = true;
111
112 EXPECT_STREQ(message->channel, "test");
113 EXPECT_EQ(message->message_size, static_cast<size_t>(0));
114
115 return kSuccess;
116 }));
117 g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine);
118 g_autoptr(GBytes) message = g_bytes_new(nullptr, 0);
119 fl_binary_messenger_send_on_channel(messenger, "test", message, nullptr,
120 nullptr, nullptr);
121 EXPECT_TRUE(called);
122}
123
124// Checks the engine returning a nullptr message work.
125TEST_F(FlBinaryMessengerTest, NullptrResponse) {
126 StartEngine();
127
128 FlutterDataCallback response_callback;
129 void* response_callback_user_data;
132 PlatformMessageCreateResponseHandle,
133 ([&response_callback, &response_callback_user_data](
134 auto engine, FlutterDataCallback data_callback, void* user_data,
136 response_callback = data_callback;
137 response_callback_user_data = user_data;
138 return kSuccess;
139 }));
141 SendPlatformMessage,
142 ([&response_callback, &response_callback_user_data](
144 EXPECT_STREQ(message->channel, "test");
145 g_autofree gchar* text =
146 g_strndup(reinterpret_cast<const gchar*>(message->message),
147 message->message_size);
148 EXPECT_STREQ(text, "Hello World!");
149
150 response_callback(nullptr, 0, response_callback_user_data);
151
152 return kSuccess;
153 }));
154
155 g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine);
156 const char* text = "Hello World!";
157 g_autoptr(GBytes) message = g_bytes_new(text, strlen(text));
159 messenger, "test", message, nullptr,
160 [](GObject* object, GAsyncResult* result, gpointer user_data) {
161 g_autoptr(GError) error = nullptr;
163 FL_BINARY_MESSENGER(object), result, &error);
164 EXPECT_NE(message, nullptr);
165 EXPECT_EQ(error, nullptr);
166
167 EXPECT_EQ(g_bytes_get_size(message), static_cast<gsize>(0));
168
169 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
170 },
171 loop);
172
173 g_main_loop_run(loop);
174}
175
176// Checks the engine reporting a send failure is handled.
178 StartEngine();
179
181 MOCK_ENGINE_PROC(SendPlatformMessage,
182 ([](auto engine, const FlutterPlatformMessage* message) {
183 EXPECT_STREQ(message->channel, "test");
185 }));
186
187 g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine);
189 messenger, "test", nullptr, nullptr,
190 [](GObject* object, GAsyncResult* result, gpointer user_data) {
191 g_autoptr(GError) error = nullptr;
193 FL_BINARY_MESSENGER(object), result, &error);
194 EXPECT_EQ(message, nullptr);
195 EXPECT_NE(error, nullptr);
196 EXPECT_STREQ(error->message, "Failed to send platform messages");
197
198 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
199 },
200 loop);
201
202 g_main_loop_run(loop);
203}
204
205// Checks can receive a message.
207 StartEngine();
208
209 bool called = false;
212 SendPlatformMessageResponse,
213 ([&called](auto engine,
215 const uint8_t* data, size_t data_length) {
216 called = true;
217
218 int fake_handle = *reinterpret_cast<const int*>(handle);
219 EXPECT_EQ(fake_handle, 42);
220
221 g_autofree gchar* text =
222 g_strndup(reinterpret_cast<const gchar*>(data), data_length);
223 EXPECT_STREQ(text, "Polo!");
224
225 return kSuccess;
226 }));
227
228 FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(engine);
229
230 // Listen for message.
232 messenger, "test",
233 [](FlBinaryMessenger* messenger, const gchar* channel, GBytes* message,
234 FlBinaryMessengerResponseHandle* response_handle, gpointer user_data) {
235 g_autofree gchar* text = g_strndup(
236 static_cast<const gchar*>(g_bytes_get_data(message, nullptr)),
237 g_bytes_get_size(message));
238 EXPECT_STREQ(text, "Marco!");
239
240 const char* response_text = "Polo!";
241 g_autoptr(GBytes) response =
242 g_bytes_new(response_text, strlen(response_text));
243 g_autoptr(GError) error = nullptr;
245 messenger, response_handle, response, &error));
246 EXPECT_EQ(error, nullptr);
247 },
248 nullptr, nullptr);
249
250 // Send message from engine.
251 const char* message_text = "Marco!";
252 g_autoptr(GBytes) message = g_bytes_new(message_text, strlen(message_text));
253 int fake_handle = 42;
255 messenger, "test", message,
256 reinterpret_cast<const FlutterPlatformMessageResponseHandle*>(
257 &fake_handle));
258
259 EXPECT_TRUE(called);
260}
261
262// Checks receieved messages can be responded to on a thread.
263TEST_F(FlBinaryMessengerTest, ReceiveRespondThread) {
264 StartEngine();
265
268 SendPlatformMessageResponse,
269 ([this](auto engine,
271 const uint8_t* data, size_t data_length) {
272 int fake_handle = *reinterpret_cast<const int*>(handle);
273 EXPECT_EQ(fake_handle, 42);
274
275 g_autofree gchar* text =
276 g_strndup(reinterpret_cast<const gchar*>(data), data_length);
277 EXPECT_STREQ(text, "Polo!");
278
279 g_main_loop_quit(loop);
280
281 return kSuccess;
282 }));
283
284 FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(engine);
285
286 // Listen for message.
288 messenger, "test",
289 [](FlBinaryMessenger* messenger, const gchar* channel, GBytes* message,
290 FlBinaryMessengerResponseHandle* response_handle, gpointer user_data) {
291 g_autofree gchar* text = g_strndup(
292 static_cast<const gchar*>(g_bytes_get_data(message, nullptr)),
293 g_bytes_get_size(message));
294 EXPECT_STREQ(text, "Marco!");
295
296 // Respond on a thread.
297 typedef struct {
298 FlBinaryMessenger* messenger;
299 FlBinaryMessengerResponseHandle* response_handle;
300 } ThreadData;
301 ThreadData* data = g_new0(ThreadData, 1);
302 data->messenger =
303 static_cast<FlBinaryMessenger*>(g_object_ref(messenger));
304 data->response_handle = static_cast<FlBinaryMessengerResponseHandle*>(
305 g_object_ref(response_handle));
306 g_autoptr(GThread) thread = g_thread_new(
307 nullptr,
308 [](gpointer user_data) {
309 g_autofree ThreadData* data = static_cast<ThreadData*>(user_data);
310 g_autoptr(FlBinaryMessenger) messenger = data->messenger;
311 g_autoptr(FlBinaryMessengerResponseHandle) response_handle =
312 data->response_handle;
313
314 const char* response_text = "Polo!";
315 g_autoptr(GBytes) response =
316 g_bytes_new(response_text, strlen(response_text));
317 g_autoptr(GError) error = nullptr;
319 data->messenger, data->response_handle, response, &error));
320 EXPECT_EQ(error, nullptr);
321
322 return static_cast<gpointer>(nullptr);
323 },
324 data);
325 },
326 nullptr, nullptr);
327
328 // Send message from engine.
329 const char* message_text = "Marco!";
330 g_autoptr(GBytes) message = g_bytes_new(message_text, strlen(message_text));
331 int fake_handle = 42;
333 messenger, "test", message,
334 reinterpret_cast<const FlutterPlatformMessageResponseHandle*>(
335 &fake_handle));
336
337 g_main_loop_run(loop);
338}
339
340// MOCK_ENGINE_PROC is leaky by design.
341// NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)
342
343// Checks if the 'resize' command is sent and is well-formed.
345 bool called = false;
346
350 SendPlatformMessage,
351 ([&called, old_handler](auto engine,
353 // Expect to receive a message on the "control" channel.
354 if (strcmp(message->channel, "dev.flutter/channel-buffers") != 0) {
355 return old_handler(engine, message);
356 }
357
358 called = true;
359
360 // The expected content was created from the following Dart code:
361 // MethodCall call = MethodCall('resize', ['flutter/test',3]);
362 // StandardMethodCodec().encodeMethodCall(call).buffer.asUint8List();
363 const int expected_message_size = 29;
364 EXPECT_EQ(message->message_size,
365 static_cast<size_t>(expected_message_size));
366 int expected[expected_message_size] = {
367 7, 6, 114, 101, 115, 105, 122, 101, 12, 2,
368 7, 12, 102, 108, 117, 116, 116, 101, 114, 47,
369 116, 101, 115, 116, 3, 3, 0, 0, 0};
370 for (size_t i = 0; i < expected_message_size; i++) {
371 EXPECT_EQ(message->message[i], expected[i]);
372 }
373
374 return kSuccess;
375 }));
376
377 StartEngine();
378
379 g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine);
380 fl_binary_messenger_resize_channel(messenger, "flutter/test", 3);
381
382 EXPECT_TRUE(called);
383}
384
385// Checks if the 'overflow' command is sent and is well-formed.
386TEST_F(FlBinaryMessengerTest, WarnsOnOverflowChannel) {
387 bool called = false;
388
392 SendPlatformMessage,
393 ([&called, old_handler](auto engine,
395 // Expect to receive a message on the "control" channel.
396 if (strcmp(message->channel, "dev.flutter/channel-buffers") != 0) {
397 return old_handler(engine, message);
398 }
399
400 called = true;
401
402 // The expected content was created from the following Dart code:
403 // MethodCall call = MethodCall('overflow',['flutter/test', true]);
404 // StandardMethodCodec().encodeMethodCall(call).buffer.asUint8List();
405 const int expected_message_size = 27;
406 EXPECT_EQ(message->message_size,
407 static_cast<size_t>(expected_message_size));
408 int expected[expected_message_size] = {
409 7, 8, 111, 118, 101, 114, 102, 108, 111, 119, 12, 2, 7, 12,
410 102, 108, 117, 116, 116, 101, 114, 47, 116, 101, 115, 116, 1};
411 for (size_t i = 0; i < expected_message_size; i++) {
412 EXPECT_EQ(message->message[i], expected[i]);
413 }
414
415 return kSuccess;
416 }));
417
418 StartEngine();
419
420 g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine);
422 false);
423
424 EXPECT_TRUE(called);
425}
426
427// Checks if error returned when invoking a command on the control channel
428// are handled.
429TEST_F(FlBinaryMessengerTest, ControlChannelErrorResponse) {
430 StartEngine();
431
432 g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine);
433 bool called = false;
437 SendPlatformMessage,
438 ([&called, old_handler, this](auto engine,
440 // Expect to receive a message on the "control" channel.
441 if (strcmp(message->channel, "dev.flutter/channel-buffers") != 0) {
442 return old_handler(engine, message);
443 }
444
445 called = true;
446
447 // Register a callback to quit the main loop when binary messenger work
448 // ends.
449 g_idle_add(
450 [](gpointer user_data) {
451 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
452 return G_SOURCE_REMOVE;
453 },
454 loop);
455
456 // Simulates an internal error.
457 return kInvalidArguments;
458 }));
459
461 false);
462
463 EXPECT_TRUE(called);
464
465 g_main_loop_run(loop);
466}
467
468// NOLINTEND(clang-analyzer-core.StackAddressEscape)
469
470TEST_F(FlBinaryMessengerTest, DeletingEngineClearsHandlers) {
471 StartEngine();
472
473 FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(engine);
474
475 // Add handler to check the destroy_notify is called.
476 gboolean destroy_notify_called = FALSE;
478 messenger, "test",
479 [](FlBinaryMessenger* messenger, const gchar* channel, GBytes* message,
480 FlBinaryMessengerResponseHandle* response_handle,
481 gpointer user_data) {},
482 &destroy_notify_called,
483 [](gpointer user_data) { *static_cast<gboolean*>(user_data) = TRUE; });
484
485 g_clear_object(&engine);
486
487 ASSERT_TRUE(destroy_notify_called);
488}
void(* FlutterDataCallback)(const uint8_t *, size_t, void *)
Definition embedder.h:1508
FlutterEngineResult(* FlutterEngineSendPlatformMessageFnPtr)(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterPlatformMessage *message)
Definition embedder.h:3665
@ kInternalInconsistency
Definition embedder.h:76
@ kInvalidArguments
Definition embedder.h:75
@ kSuccess
Definition embedder.h:73
FlutterEngine engine
Definition main.cc:84
const char * message
g_autoptr(FlEngine) engine
G_MODULE_EXPORT GBytes * fl_binary_messenger_send_on_channel_finish(FlBinaryMessenger *self, GAsyncResult *result, GError **error)
G_MODULE_EXPORT void fl_binary_messenger_resize_channel(FlBinaryMessenger *self, const gchar *channel, int64_t new_size)
G_MODULE_EXPORT void fl_binary_messenger_set_message_handler_on_channel(FlBinaryMessenger *self, const gchar *channel, FlBinaryMessengerMessageHandler handler, gpointer user_data, GDestroyNotify destroy_notify)
G_MODULE_EXPORT void fl_binary_messenger_send_on_channel(FlBinaryMessenger *self, const gchar *channel, GBytes *message, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
FlBinaryMessenger * fl_binary_messenger_new(FlEngine *engine)
G_MODULE_EXPORT gboolean fl_binary_messenger_send_response(FlBinaryMessenger *self, FlBinaryMessengerResponseHandle *response_handle, GBytes *response, GError **error)
G_MODULE_EXPORT void fl_binary_messenger_set_warns_on_channel_overflow(FlBinaryMessenger *self, const gchar *channel, bool warns)
gboolean fl_binary_messenger_handle_message(FlBinaryMessenger *messenger, const gchar *channel, GBytes *message, const FlutterPlatformMessageResponseHandle *response_handle)
TEST_F(FlBinaryMessengerTest, Send)
return TRUE
FlutterEngineProcTable * fl_engine_get_embedder_api(FlEngine *self)
Definition fl_engine.cc:920
G_MODULE_EXPORT FlBinaryMessenger * fl_engine_get_binary_messenger(FlEngine *self)
const gchar * channel
const uint8_t uint32_t uint32_t GError ** error
std::u16string text
#define MOCK_ENGINE_PROC(proc, mock_impl)
FlutterEngineSendPlatformMessageFnPtr SendPlatformMessage
Definition embedder.h:3777
FlutterEnginePlatformMessageCreateResponseHandleFnPtr PlatformMessageCreateResponseHandle
Definition embedder.h:3779
FlutterEngineSendPlatformMessageResponseFnPtr SendPlatformMessageResponse
Definition embedder.h:3782