6 #include "gtest/gtest.h"
8 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
13 #include "flutter/shell/platform/linux/testing/fl_test.h"
19 TEST(FlEngineTest, WindowMetrics) {
24 embedder_api->SendWindowMetricsEvent = MOCK_ENGINE_PROC(
25 SendWindowMetricsEvent,
26 ([&called](
auto engine,
const FlutterWindowMetricsEvent*
event) {
28 EXPECT_EQ(
event->view_id, 1);
29 EXPECT_EQ(
event->width,
static_cast<size_t>(3840));
30 EXPECT_EQ(
event->height,
static_cast<size_t>(2160));
31 EXPECT_EQ(
event->pixel_ratio, 2.0);
36 g_autoptr(GError)
error =
nullptr;
38 EXPECT_EQ(
error,
nullptr);
45 TEST(FlEngineTest, MousePointer) {
50 embedder_api->SendPointerEvent = MOCK_ENGINE_PROC(
52 ([&called](
auto engine,
const FlutterPointerEvent* events,
53 size_t events_count) {
55 EXPECT_EQ(events_count,
static_cast<size_t>(1));
56 EXPECT_EQ(events[0].view_id, 1);
57 EXPECT_EQ(events[0].phase, kDown);
58 EXPECT_EQ(events[0].timestamp,
static_cast<size_t>(1234567890));
59 EXPECT_EQ(events[0].x, 800);
60 EXPECT_EQ(events[0].y, 600);
61 EXPECT_EQ(events[0].device,
static_cast<int32_t
>(0));
62 EXPECT_EQ(events[0].signal_kind, kFlutterPointerSignalKindScroll);
63 EXPECT_EQ(events[0].scroll_delta_x, 1.2);
64 EXPECT_EQ(events[0].scroll_delta_y, -3.4);
65 EXPECT_EQ(events[0].device_kind, kFlutterPointerDeviceKindMouse);
66 EXPECT_EQ(events[0].buttons, kFlutterPointerButtonMouseSecondary);
71 g_autoptr(GError)
error =
nullptr;
73 EXPECT_EQ(
error,
nullptr);
75 kFlutterPointerDeviceKindMouse, 1.2, -3.4,
76 kFlutterPointerButtonMouseSecondary);
82 TEST(FlEngineTest, PointerPanZoom) {
87 embedder_api->SendPointerEvent = MOCK_ENGINE_PROC(
89 ([&called](
auto engine,
const FlutterPointerEvent* events,
90 size_t events_count) {
92 EXPECT_EQ(events_count,
static_cast<size_t>(1));
93 EXPECT_EQ(events[0].view_id, 1);
94 EXPECT_EQ(events[0].phase, kPanZoomUpdate);
95 EXPECT_EQ(events[0].timestamp,
static_cast<size_t>(1234567890));
96 EXPECT_EQ(events[0].x, 800);
97 EXPECT_EQ(events[0].y, 600);
98 EXPECT_EQ(events[0].device,
static_cast<int32_t
>(1));
99 EXPECT_EQ(events[0].signal_kind, kFlutterPointerSignalKindNone);
100 EXPECT_EQ(events[0].pan_x, 1.5);
101 EXPECT_EQ(events[0].pan_y, 2.5);
102 EXPECT_EQ(events[0].scale, 3.5);
103 EXPECT_EQ(events[0].rotation, 4.5);
104 EXPECT_EQ(events[0].device_kind, kFlutterPointerDeviceKindTrackpad);
105 EXPECT_EQ(events[0].buttons, 0);
110 g_autoptr(GError)
error =
nullptr;
112 EXPECT_EQ(
error,
nullptr);
114 kPanZoomUpdate, 1.5, 2.5, 3.5, 4.5);
120 TEST(FlEngineTest, DispatchSemanticsAction) {
125 embedder_api->DispatchSemanticsAction = MOCK_ENGINE_PROC(
126 DispatchSemanticsAction,
127 ([&called](
auto engine, uint64_t
id, FlutterSemanticsAction action,
128 const uint8_t* data,
size_t data_length) {
129 EXPECT_EQ(
id,
static_cast<uint64_t
>(42));
130 EXPECT_EQ(action, kFlutterSemanticsActionTap);
131 EXPECT_EQ(data_length,
static_cast<size_t>(4));
132 EXPECT_EQ(data[0],
't');
133 EXPECT_EQ(data[1],
'e');
134 EXPECT_EQ(data[2],
's');
135 EXPECT_EQ(data[3],
't');
141 g_autoptr(GError)
error =
nullptr;
143 EXPECT_EQ(
error,
nullptr);
144 g_autoptr(GBytes) data = g_bytes_new_static(
"test", 4);
152 TEST(FlEngineTest, PlatformMessage) {
157 FlutterEngineSendPlatformMessageFnPtr old_handler =
158 embedder_api->SendPlatformMessage;
159 embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC(
161 ([&called, old_handler](
auto engine,
162 const FlutterPlatformMessage* message) {
163 if (strcmp(message->channel,
"test") != 0) {
164 return old_handler(engine, message);
169 EXPECT_EQ(message->message_size,
static_cast<size_t>(4));
170 EXPECT_EQ(message->message[0],
't');
171 EXPECT_EQ(message->message[1],
'e');
172 EXPECT_EQ(message->message[2],
's');
173 EXPECT_EQ(message->message[3],
't');
178 g_autoptr(GError)
error =
nullptr;
180 EXPECT_EQ(
error,
nullptr);
181 g_autoptr(GBytes) message = g_bytes_new_static(
"test", 4);
189 TEST(FlEngineTest, PlatformMessageResponse) {
194 embedder_api->SendPlatformMessageResponse = MOCK_ENGINE_PROC(
195 SendPlatformMessageResponse,
196 ([&called](
auto engine,
197 const FlutterPlatformMessageResponseHandle* handle,
198 const uint8_t* data,
size_t data_length) {
203 reinterpret_cast<const FlutterPlatformMessageResponseHandle*
>(42));
204 EXPECT_EQ(data_length,
static_cast<size_t>(4));
205 EXPECT_EQ(data[0],
't');
206 EXPECT_EQ(data[1],
'e');
207 EXPECT_EQ(data[2],
's');
208 EXPECT_EQ(data[3],
't');
213 g_autoptr(GError)
error =
nullptr;
215 EXPECT_EQ(
error,
nullptr);
216 g_autoptr(GBytes) response = g_bytes_new_static(
"test", 4);
218 engine,
reinterpret_cast<const FlutterPlatformMessageResponseHandle*
>(42),
220 EXPECT_EQ(
error,
nullptr);
226 TEST(FlEngineTest, SettingsHandler) {
231 embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC(
233 ([&called](
auto engine,
const FlutterPlatformMessage* message) {
236 EXPECT_STREQ(message->channel,
"flutter/settings");
239 g_autoptr(GBytes) data =
240 g_bytes_new(message->message, message->message_size);
241 g_autoptr(GError)
error =
nullptr;
243 FL_MESSAGE_CODEC(codec), data, &
error);
244 EXPECT_NE(settings,
nullptr);
245 EXPECT_EQ(
error,
nullptr);
249 EXPECT_NE(text_scale_factor,
nullptr);
252 FlValue* always_use_24hr_format =
254 EXPECT_NE(always_use_24hr_format,
nullptr);
260 EXPECT_NE(platform_brightness,
nullptr);
266 g_autoptr(GError)
error =
nullptr;
268 EXPECT_EQ(
error,
nullptr);
274 int* count =
reinterpret_cast<int*
>(
user_data);
279 TEST(FlEngineTest, OnPreEngineRestart) {
283 OnPreEngineRestartCallback
callback;
284 void* callback_user_data;
287 embedder_api->Initialize = MOCK_ENGINE_PROC(
288 Initialize, ([&
callback, &callback_user_data, &called](
289 size_t version,
const FlutterRendererConfig* config,
291 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
299 g_autoptr(GError)
error =
nullptr;
301 EXPECT_EQ(
error,
nullptr);
315 g_signal_connect(engine,
"on-pre-engine-restart",
322 TEST(FlEngineTest, DartEntrypointArgs) {
325 GPtrArray* args_array = g_ptr_array_new();
326 g_ptr_array_add(args_array,
const_cast<char*
>(
"arg_one"));
327 g_ptr_array_add(args_array,
const_cast<char*
>(
"arg_two"));
328 g_ptr_array_add(args_array,
const_cast<char*
>(
"arg_three"));
329 g_ptr_array_add(args_array,
nullptr);
330 gchar**
args =
reinterpret_cast<gchar**
>(g_ptr_array_free(args_array,
false));
334 g_autoptr(FlEngine) engine = make_mock_engine_with_project(project);
338 embedder_api->Initialize = MOCK_ENGINE_PROC(
339 Initialize, ([&called, &set_args =
args](
340 size_t version,
const FlutterRendererConfig* config,
342 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
344 EXPECT_NE(set_args,
args->dart_entrypoint_argv);
345 EXPECT_EQ(
args->dart_entrypoint_argc, 3);
350 g_autoptr(GError)
error =
nullptr;
352 EXPECT_EQ(
error,
nullptr);
358 g_autofree gchar* initial_language = g_strdup(g_getenv(
"LANGUAGE"));
359 g_setenv(
"LANGUAGE",
"de:en_US",
TRUE);
362 g_autoptr(FlEngine) engine = make_mock_engine_with_project(project);
366 embedder_api->UpdateLocales = MOCK_ENGINE_PROC(
367 UpdateLocales, ([&called](
auto engine,
const FlutterLocale** locales,
368 size_t locales_count) {
371 EXPECT_EQ(locales_count,
static_cast<size_t>(4));
373 EXPECT_STREQ(locales[0]->language_code,
"de");
374 EXPECT_STREQ(locales[0]->country_code,
nullptr);
375 EXPECT_STREQ(locales[0]->script_code,
nullptr);
376 EXPECT_STREQ(locales[0]->variant_code,
nullptr);
378 EXPECT_STREQ(locales[1]->language_code,
"en");
379 EXPECT_STREQ(locales[1]->country_code,
"US");
380 EXPECT_STREQ(locales[1]->script_code,
nullptr);
381 EXPECT_STREQ(locales[1]->variant_code,
nullptr);
383 EXPECT_STREQ(locales[2]->language_code,
"en");
384 EXPECT_STREQ(locales[2]->country_code,
nullptr);
385 EXPECT_STREQ(locales[2]->script_code,
nullptr);
386 EXPECT_STREQ(locales[2]->variant_code,
nullptr);
388 EXPECT_STREQ(locales[3]->language_code,
"C");
389 EXPECT_STREQ(locales[3]->country_code,
nullptr);
390 EXPECT_STREQ(locales[3]->script_code,
nullptr);
391 EXPECT_STREQ(locales[3]->variant_code,
nullptr);
396 g_autoptr(GError)
error =
nullptr;
398 EXPECT_EQ(
error,
nullptr);
402 if (initial_language) {
403 g_setenv(
"LANGUAGE", initial_language,
TRUE);
405 g_unsetenv(
"LANGUAGE");
410 g_autofree gchar* initial_language = g_strdup(g_getenv(
"LANGUAGE"));
411 g_setenv(
"LANGUAGE",
"C",
TRUE);
414 g_autoptr(FlEngine) engine = make_mock_engine_with_project(project);
418 embedder_api->UpdateLocales = MOCK_ENGINE_PROC(
419 UpdateLocales, ([&called](
auto engine,
const FlutterLocale** locales,
420 size_t locales_count) {
423 EXPECT_EQ(locales_count,
static_cast<size_t>(1));
425 EXPECT_STREQ(locales[0]->language_code,
"C");
426 EXPECT_STREQ(locales[0]->country_code,
nullptr);
427 EXPECT_STREQ(locales[0]->script_code,
nullptr);
428 EXPECT_STREQ(locales[0]->variant_code,
nullptr);
433 g_autoptr(GError)
error =
nullptr;
435 EXPECT_EQ(
error,
nullptr);
439 if (initial_language) {
440 g_setenv(
"LANGUAGE", initial_language,
TRUE);
442 g_unsetenv(
"LANGUAGE");
446 TEST(FlEngineTest, DuplicateLocale) {
447 g_autofree gchar* initial_language = g_strdup(g_getenv(
"LANGUAGE"));
448 g_setenv(
"LANGUAGE",
"en:en",
TRUE);
451 g_autoptr(FlEngine) engine = make_mock_engine_with_project(project);
455 embedder_api->UpdateLocales = MOCK_ENGINE_PROC(
456 UpdateLocales, ([&called](
auto engine,
const FlutterLocale** locales,
457 size_t locales_count) {
460 EXPECT_EQ(locales_count,
static_cast<size_t>(2));
462 EXPECT_STREQ(locales[0]->language_code,
"en");
463 EXPECT_STREQ(locales[0]->country_code,
nullptr);
464 EXPECT_STREQ(locales[0]->script_code,
nullptr);
465 EXPECT_STREQ(locales[0]->variant_code,
nullptr);
467 EXPECT_STREQ(locales[1]->language_code,
"C");
468 EXPECT_STREQ(locales[1]->country_code,
nullptr);
469 EXPECT_STREQ(locales[1]->script_code,
nullptr);
470 EXPECT_STREQ(locales[1]->variant_code,
nullptr);
475 g_autoptr(GError)
error =
nullptr;
477 EXPECT_EQ(
error,
nullptr);
481 if (initial_language) {
482 g_setenv(
"LANGUAGE", initial_language,
TRUE);
484 g_unsetenv(
"LANGUAGE");
488 TEST(FlEngineTest, EmptyLocales) {
489 g_autofree gchar* initial_language = g_strdup(g_getenv(
"LANGUAGE"));
490 g_setenv(
"LANGUAGE",
"de:: :en_US",
TRUE);
493 g_autoptr(FlEngine) engine = make_mock_engine_with_project(project);
497 embedder_api->UpdateLocales = MOCK_ENGINE_PROC(
498 UpdateLocales, ([&called](
auto engine,
const FlutterLocale** locales,
499 size_t locales_count) {
502 EXPECT_EQ(locales_count,
static_cast<size_t>(4));
504 EXPECT_STREQ(locales[0]->language_code,
"de");
505 EXPECT_STREQ(locales[0]->country_code,
nullptr);
506 EXPECT_STREQ(locales[0]->script_code,
nullptr);
507 EXPECT_STREQ(locales[0]->variant_code,
nullptr);
509 EXPECT_STREQ(locales[1]->language_code,
"en");
510 EXPECT_STREQ(locales[1]->country_code,
"US");
511 EXPECT_STREQ(locales[1]->script_code,
nullptr);
512 EXPECT_STREQ(locales[1]->variant_code,
nullptr);
514 EXPECT_STREQ(locales[2]->language_code,
"en");
515 EXPECT_STREQ(locales[2]->country_code,
nullptr);
516 EXPECT_STREQ(locales[2]->script_code,
nullptr);
517 EXPECT_STREQ(locales[2]->variant_code,
nullptr);
519 EXPECT_STREQ(locales[3]->language_code,
"C");
520 EXPECT_STREQ(locales[3]->country_code,
nullptr);
521 EXPECT_STREQ(locales[3]->script_code,
nullptr);
522 EXPECT_STREQ(locales[3]->variant_code,
nullptr);
527 g_autoptr(GError)
error =
nullptr;
529 EXPECT_EQ(
error,
nullptr);
533 if (initial_language) {
534 g_setenv(
"LANGUAGE", initial_language,
TRUE);
536 g_unsetenv(
"LANGUAGE");
540 TEST(FlEngineTest, SwitchesEmpty) {
544 unsetenv(
"FLUTTER_ENGINE_SWITCHES");
548 EXPECT_EQ(switches->len, 0U);
554 g_autoptr(GError)
error =
nullptr;
557 EXPECT_EQ(
error,
nullptr);
559 g_main_loop_quit(
static_cast<GMainLoop*
>(
user_data));
563 g_autoptr(GMainLoop) loop = g_main_loop_new(
nullptr, 0);
569 embedder_api->AddView = MOCK_ENGINE_PROC(
570 AddView, ([&called](
auto engine,
const FlutterAddViewInfo* info) {
572 EXPECT_EQ(info->view_metrics->width, 123u);
573 EXPECT_EQ(info->view_metrics->height, 456u);
574 EXPECT_EQ(info->view_metrics->pixel_ratio, 2.0);
576 FlutterAddViewResult
result;
577 result.struct_size =
sizeof(FlutterAddViewResult);
579 result.user_data = info->user_data;
580 info->add_view_callback(&
result);
585 FlutterViewId view_id =
587 EXPECT_GT(view_id, 0);
591 g_main_loop_run(loop);
597 g_autoptr(GError)
error =
nullptr;
600 EXPECT_NE(
error,
nullptr);
602 g_main_loop_quit(
static_cast<GMainLoop*
>(
user_data));
605 TEST(FlEngineTest, AddViewError) {
606 g_autoptr(GMainLoop) loop = g_main_loop_new(
nullptr, 0);
611 embedder_api->AddView = MOCK_ENGINE_PROC(
612 AddView, ([](
auto engine,
const FlutterAddViewInfo* info) {
613 FlutterAddViewResult
result;
614 result.struct_size =
sizeof(FlutterAddViewResult);
616 result.user_data = info->user_data;
617 info->add_view_callback(&
result);
624 EXPECT_GT(view_id, 0);
627 g_main_loop_run(loop);
633 g_autoptr(GError)
error =
nullptr;
636 EXPECT_NE(
error,
nullptr);
638 g_main_loop_quit(
static_cast<GMainLoop*
>(
user_data));
641 TEST(FlEngineTest, AddViewEngineError) {
642 g_autoptr(GMainLoop) loop = g_main_loop_new(
nullptr, 0);
647 embedder_api->AddView = MOCK_ENGINE_PROC(
648 AddView, ([](
auto engine,
const FlutterAddViewInfo* info) {
649 return kInvalidArguments;
654 EXPECT_GT(view_id, 0);
657 g_main_loop_run(loop);
663 g_autoptr(GError)
error =
nullptr;
666 EXPECT_EQ(
error,
nullptr);
668 g_main_loop_quit(
static_cast<GMainLoop*
>(
user_data));
671 TEST(FlEngineTest, RemoveView) {
672 g_autoptr(GMainLoop) loop = g_main_loop_new(
nullptr, 0);
678 embedder_api->RemoveView = MOCK_ENGINE_PROC(
679 RemoveView, ([&called](
auto engine,
const FlutterRemoveViewInfo* info) {
681 EXPECT_EQ(info->view_id, 123);
683 FlutterRemoveViewResult
result;
684 result.struct_size =
sizeof(FlutterRemoveViewResult);
686 result.user_data = info->user_data;
687 info->remove_view_callback(&
result);
696 g_main_loop_run(loop);
702 g_autoptr(GError)
error =
nullptr;
705 EXPECT_NE(
error,
nullptr);
707 g_main_loop_quit(
static_cast<GMainLoop*
>(
user_data));
710 TEST(FlEngineTest, RemoveViewError) {
711 g_autoptr(GMainLoop) loop = g_main_loop_new(
nullptr, 0);
716 embedder_api->RemoveView = MOCK_ENGINE_PROC(
717 RemoveView, ([](
auto engine,
const FlutterRemoveViewInfo* info) {
718 FlutterRemoveViewResult
result;
719 result.struct_size =
sizeof(FlutterRemoveViewResult);
721 result.user_data = info->user_data;
722 info->remove_view_callback(&
result);
730 g_main_loop_run(loop);
736 g_autoptr(GError)
error =
nullptr;
739 EXPECT_NE(
error,
nullptr);
741 g_main_loop_quit(
static_cast<GMainLoop*
>(
user_data));
744 TEST(FlEngineTest, RemoveViewEngineError) {
745 g_autoptr(GMainLoop) loop = g_main_loop_new(
nullptr, 0);
750 embedder_api->RemoveView = MOCK_ENGINE_PROC(
751 RemoveView, ([](
auto engine,
const FlutterRemoveViewInfo* info) {
752 return kInvalidArguments;
759 g_main_loop_run(loop);
762 #ifndef FLUTTER_RELEASE
766 setenv(
"FLUTTER_ENGINE_SWITCHES",
"2", 1);
767 setenv(
"FLUTTER_ENGINE_SWITCH_1",
"abc", 1);
768 setenv(
"FLUTTER_ENGINE_SWITCH_2",
"foo=\"bar, baz\"", 1);
771 EXPECT_EQ(switches->len, 2U);
772 EXPECT_STREQ(
static_cast<const char*
>(g_ptr_array_index(switches, 0)),
774 EXPECT_STREQ(
static_cast<const char*
>(g_ptr_array_index(switches, 1)),
775 "--foo=\"bar, baz\"");
777 unsetenv(
"FLUTTER_ENGINE_SWITCHES");
778 unsetenv(
"FLUTTER_ENGINE_SWITCH_1");
779 unsetenv(
"FLUTTER_ENGINE_SWITCH_2");
781 #endif // !FLUTTER_RELEASE