diff --git a/shell/platform/linux/fl_event_channel_test.cc b/shell/platform/linux/fl_event_channel_test.cc index 934a374fb39d0..a532978be06de 100644 --- a/shell/platform/linux/fl_event_channel_test.cc +++ b/shell/platform/linux/fl_event_channel_test.cc @@ -5,459 +5,386 @@ // Included first as it collides with the X11 headers. #include "gtest/gtest.h" -#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" -#include "flutter/shell/platform/linux/fl_engine_private.h" -#include "flutter/shell/platform/linux/fl_method_codec_private.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_event_channel.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" -#include "flutter/shell/platform/linux/testing/mock_renderer.h" - -// Data passed in tests. -typedef struct { - GMainLoop* loop; - int count; -} TestData; - -// Creates a mock engine that responds to platform messages. -static FlEngine* make_mock_engine() { - g_autoptr(FlDartProject) project = fl_dart_project_new(); - g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new(); - g_autoptr(FlEngine) engine = - fl_engine_new_with_renderer(project, FL_RENDERER(renderer)); - g_autoptr(GError) engine_error = nullptr; - EXPECT_TRUE(fl_engine_start(engine, &engine_error)); - EXPECT_EQ(engine_error, nullptr); - - return static_cast(g_object_ref(engine)); -} - -// Triggers the engine to start listening to the channel. -static void listen_channel(FlBinaryMessenger* messenger, FlValue* args) { - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(FlMethodChannel) channel = fl_method_channel_new( - messenger, "test/standard-method", FL_METHOD_CODEC(codec)); - - // Trigger the engine to make a method call. - g_autoptr(FlValue) invoke_args = fl_value_new_list(); - fl_value_append_take(invoke_args, fl_value_new_string("test/standard-event")); - fl_value_append_take(invoke_args, fl_value_new_string("listen")); - g_autoptr(FlValue) value = - args != nullptr ? fl_value_ref(args) : fl_value_new_null(); - fl_value_append(invoke_args, value); - fl_method_channel_invoke_method(channel, "InvokeMethod", invoke_args, nullptr, - nullptr, nullptr); -} - -// Triggers the engine to cancel the subscription to the channel. -static void cancel_channel(FlBinaryMessenger* messenger, FlValue* args) { - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(FlMethodChannel) channel = fl_method_channel_new( - messenger, "test/standard-method", FL_METHOD_CODEC(codec)); - - // Trigger the engine to make a method call. - g_autoptr(FlValue) invoke_args = fl_value_new_list(); - fl_value_append_take(invoke_args, fl_value_new_string("test/standard-event")); - fl_value_append_take(invoke_args, fl_value_new_string("cancel")); - g_autoptr(FlValue) value = - args != nullptr ? fl_value_ref(args) : fl_value_new_null(); - fl_value_append(invoke_args, value); - fl_method_channel_invoke_method(channel, "InvokeMethod", invoke_args, nullptr, - nullptr, nullptr); -} - -// Called when the remote end starts listening on the channel. -static FlMethodErrorResponse* listen_listen_cb(FlEventChannel* channel, - FlValue* args, - gpointer user_data) { - EXPECT_EQ(fl_value_get_type(args), FL_VALUE_TYPE_NULL); - - g_main_loop_quit(static_cast(user_data)); - - return nullptr; -} +#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h" // Checks we detect a listen event. TEST(FlEventChannelTest, Listen) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - FlEventChannel* channel = fl_event_channel_new( - messenger, "test/standard-event", FL_METHOD_CODEC(codec)); - fl_event_channel_set_stream_handlers(channel, listen_listen_cb, nullptr, loop, - nullptr); - - listen_channel(messenger, nullptr); - - // Blocks here until listen_listen_cb called. - g_main_loop_run(loop); - - // Manually unref because the compiler complains 'channel' is unused. - g_object_unref(channel); -} - -// Called when the remote end starts listening on the channel. -static FlMethodErrorResponse* listen_exception_listen_cb( - FlEventChannel* channel, - FlValue* args, - gpointer user_data) { - return fl_method_error_response_new("LISTEN-ERROR", "LISTEN-ERROR-MESSAGE", - nullptr); -} - -// Called when a the test engine notifies us what response we sent in the -// ListenException test. -static void listen_exception_response_cb( - FlBinaryMessenger* messenger, - const gchar* channel, - GBytes* message, - FlBinaryMessengerResponseHandle* response_handle, - gpointer user_data) { - fl_binary_messenger_send_response(messenger, response_handle, nullptr, - nullptr); - - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(GError) error = nullptr; - g_autoptr(FlMethodResponse) response = - fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error); - EXPECT_NE(response, nullptr); - EXPECT_EQ(error, nullptr); - - EXPECT_TRUE(FL_IS_METHOD_ERROR_RESPONSE(response)); - EXPECT_STREQ( - fl_method_error_response_get_code(FL_METHOD_ERROR_RESPONSE(response)), - "LISTEN-ERROR"); - EXPECT_STREQ( - fl_method_error_response_get_message(FL_METHOD_ERROR_RESPONSE(response)), - "LISTEN-ERROR-MESSAGE"); - - g_main_loop_quit(static_cast(user_data)); + g_autoptr(FlEventChannel) channel = fl_event_channel_new( + FL_BINARY_MESSENGER(messenger), "test", FL_METHOD_CODEC(codec)); + fl_event_channel_set_stream_handlers( + channel, + [](FlEventChannel* channel, FlValue* args, gpointer user_data) { + EXPECT_EQ(fl_value_get_type(args), FL_VALUE_TYPE_NULL); + + return static_cast(nullptr); + }, + nullptr, nullptr, nullptr); + + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "listen", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + FlValue* result = fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)); + EXPECT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_NULL); + }, + &called); + EXPECT_TRUE(called); } // Checks we can generate a listen exception. TEST(FlEventChannelTest, ListenException) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - FlEventChannel* channel = fl_event_channel_new( - messenger, "test/standard-event", FL_METHOD_CODEC(codec)); - fl_event_channel_set_stream_handlers(channel, listen_exception_listen_cb, - nullptr, loop, nullptr); - - // Listen for response to the engine. - fl_binary_messenger_set_message_handler_on_channel( - messenger, "test/responses", listen_exception_response_cb, loop, nullptr); - - listen_channel(messenger, nullptr); - - // Blocks here until listen_exception_response_cb called. - g_main_loop_run(loop); - - // Manually unref because the compiler complains 'channel' is unused. - g_object_unref(channel); -} - -// Called when the remote end cancels their subscription. -static FlMethodErrorResponse* cancel_cancel_cb(FlEventChannel* channel, - FlValue* args, - gpointer user_data) { - EXPECT_EQ(fl_value_get_type(args), FL_VALUE_TYPE_NULL); - - g_main_loop_quit(static_cast(user_data)); - - return nullptr; + g_autoptr(FlEventChannel) channel = fl_event_channel_new( + FL_BINARY_MESSENGER(messenger), "test", FL_METHOD_CODEC(codec)); + fl_event_channel_set_stream_handlers( + channel, + [](FlEventChannel* channel, FlValue* args, gpointer user_data) { + return fl_method_error_response_new("LISTEN-ERROR", + "LISTEN-ERROR-MESSAGE", nullptr); + }, + nullptr, nullptr, nullptr); + + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "listen", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_ERROR_RESPONSE(response)); + EXPECT_STREQ(fl_method_error_response_get_code( + FL_METHOD_ERROR_RESPONSE(response)), + "LISTEN-ERROR"); + EXPECT_STREQ(fl_method_error_response_get_message( + FL_METHOD_ERROR_RESPONSE(response)), + "LISTEN-ERROR-MESSAGE"); + }, + &called); + EXPECT_TRUE(called); } // Checks we detect a cancel event. TEST(FlEventChannelTest, Cancel) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - FlEventChannel* channel = fl_event_channel_new( - messenger, "test/standard-event", FL_METHOD_CODEC(codec)); - fl_event_channel_set_stream_handlers(channel, nullptr, cancel_cancel_cb, loop, - nullptr); - - listen_channel(messenger, nullptr); - cancel_channel(messenger, nullptr); - - // Blocks here until cancel_cancel_cb called. - g_main_loop_run(loop); - - // Manually unref because the compiler complains 'channel' is unused. - g_object_unref(channel); -} - -// Called when the remote end cancels their subscription. -static FlMethodErrorResponse* cancel_exception_cancel_cb( - FlEventChannel* channel, - FlValue* args, - gpointer user_data) { - return fl_method_error_response_new("CANCEL-ERROR", "CANCEL-ERROR-MESSAGE", - nullptr); -} - -// Called when a the test engine notifies us what response we sent in the -// CancelException test. -static void cancel_exception_response_cb( - FlBinaryMessenger* messenger, - const gchar* channel, - GBytes* message, - FlBinaryMessengerResponseHandle* response_handle, - gpointer user_data) { - TestData* data = static_cast(user_data); - - fl_binary_messenger_send_response(messenger, response_handle, nullptr, - nullptr); - - data->count++; - if (data->count == 2) { - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(GError) error = nullptr; - g_autoptr(FlMethodResponse) response = fl_method_codec_decode_response( - FL_METHOD_CODEC(codec), message, &error); - EXPECT_NE(response, nullptr); - EXPECT_EQ(error, nullptr); - - EXPECT_TRUE(FL_IS_METHOD_ERROR_RESPONSE(response)); - EXPECT_STREQ( - fl_method_error_response_get_code(FL_METHOD_ERROR_RESPONSE(response)), - "CANCEL-ERROR"); - EXPECT_STREQ(fl_method_error_response_get_message( - FL_METHOD_ERROR_RESPONSE(response)), - "CANCEL-ERROR-MESSAGE"); - - g_main_loop_quit(data->loop); - } + g_autoptr(FlEventChannel) channel = fl_event_channel_new( + FL_BINARY_MESSENGER(messenger), "test", FL_METHOD_CODEC(codec)); + fl_event_channel_set_stream_handlers( + channel, nullptr, + [](FlEventChannel* channel, FlValue* args, gpointer user_data) { + EXPECT_EQ(fl_value_get_type(args), FL_VALUE_TYPE_NULL); + + return static_cast(nullptr); + }, + nullptr, nullptr); + + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "listen", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) {}, + nullptr); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "cancel", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + FlValue* result = fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)); + EXPECT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_NULL); + }, + &called); + EXPECT_TRUE(called); } // Checks we can generate a cancel exception. TEST(FlEventChannelTest, CancelException) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - TestData data; - data.loop = loop; - data.count = 0; - - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - FlEventChannel* channel = fl_event_channel_new( - messenger, "test/standard-event", FL_METHOD_CODEC(codec)); + g_autoptr(FlEventChannel) channel = fl_event_channel_new( + FL_BINARY_MESSENGER(messenger), "test", FL_METHOD_CODEC(codec)); fl_event_channel_set_stream_handlers( - channel, nullptr, cancel_exception_cancel_cb, &data, nullptr); - - // Listen for response to the engine. - fl_binary_messenger_set_message_handler_on_channel( - messenger, "test/responses", cancel_exception_response_cb, &data, + channel, nullptr, + [](FlEventChannel* channel, FlValue* args, gpointer user_data) { + return fl_method_error_response_new("CANCEL-ERROR", + "CANCEL-ERROR-MESSAGE", nullptr); + }, + nullptr, nullptr); + + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "listen", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) {}, nullptr); - - listen_channel(messenger, nullptr); - cancel_channel(messenger, nullptr); - - // Blocks here until cancel_exception_response_cb called. - g_main_loop_run(loop); - - // Manually unref because the compiler complains 'channel' is unused. - g_object_unref(channel); -} - -// Called when the remote end starts listening on the channel. -static FlMethodErrorResponse* args_listen_cb(FlEventChannel* channel, - FlValue* args, - gpointer user_data) { - g_autoptr(FlValue) expected_args = fl_value_new_string("LISTEN-ARGS"); - EXPECT_TRUE(fl_value_equal(args, expected_args)); - - return nullptr; -} - -// Called when the remote end cancels their subscription. -static FlMethodErrorResponse* args_cancel_cb(FlEventChannel* channel, - FlValue* args, - gpointer user_data) { - g_autoptr(FlValue) expected_args = fl_value_new_string("CANCEL-ARGS"); - EXPECT_TRUE(fl_value_equal(args, expected_args)); - - g_main_loop_quit(static_cast(user_data)); - - return nullptr; + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "cancel", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_ERROR_RESPONSE(response)); + EXPECT_STREQ(fl_method_error_response_get_code( + FL_METHOD_ERROR_RESPONSE(response)), + "CANCEL-ERROR"); + EXPECT_STREQ(fl_method_error_response_get_message( + FL_METHOD_ERROR_RESPONSE(response)), + "CANCEL-ERROR-MESSAGE"); + }, + &called); + EXPECT_TRUE(called); } // Checks args are passed to listen/cancel. TEST(FlEventChannelTest, Args) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - FlEventChannel* channel = fl_event_channel_new( - messenger, "test/standard-event", FL_METHOD_CODEC(codec)); - fl_event_channel_set_stream_handlers(channel, args_listen_cb, args_cancel_cb, - loop, nullptr); + g_autoptr(FlEventChannel) channel = fl_event_channel_new( + FL_BINARY_MESSENGER(messenger), "test", FL_METHOD_CODEC(codec)); + int call_count = 0; + fl_event_channel_set_stream_handlers( + channel, + [](FlEventChannel* channel, FlValue* args, gpointer user_data) { + int* call_count = static_cast(user_data); + EXPECT_EQ(*call_count, 0); + (*call_count)++; - g_autoptr(FlValue) listen_args = fl_value_new_string("LISTEN-ARGS"); - listen_channel(messenger, listen_args); - g_autoptr(FlValue) cancel_args = fl_value_new_string("CANCEL-ARGS"); - cancel_channel(messenger, cancel_args); + g_autoptr(FlValue) expected_args = fl_value_new_string("LISTEN-ARGS"); + EXPECT_TRUE(fl_value_equal(args, expected_args)); - // Blocks here until args_cancel_cb called. - g_main_loop_run(loop); + return static_cast(nullptr); + }, + [](FlEventChannel* channel, FlValue* args, gpointer user_data) { + int* call_count = static_cast(user_data); + EXPECT_EQ(*call_count, 1); + (*call_count)++; - // Manually unref because the compiler complains 'channel' is unused. - g_object_unref(channel); -} + g_autoptr(FlValue) expected_args = fl_value_new_string("CANCEL-ARGS"); + EXPECT_TRUE(fl_value_equal(args, expected_args)); -// Called when the remote end starts listening on the channel. -static FlMethodErrorResponse* send_events_listen_cb(FlEventChannel* channel, - FlValue* args, - gpointer user_data) { - // Send some events. - for (int i = 0; i < 5; i++) { - g_autoptr(FlValue) event = fl_value_new_int(i); - g_autoptr(GError) error = nullptr; - EXPECT_TRUE(fl_event_channel_send(channel, event, nullptr, &error)); - EXPECT_EQ(error, nullptr); - } - - return nullptr; -} + return static_cast(nullptr); + }, + &call_count, nullptr); -// Called when a the test engine notifies us what event we sent in the -// Test test. -static void send_events_events_cb( - FlBinaryMessenger* messenger, - const gchar* channel, - GBytes* message, - FlBinaryMessengerResponseHandle* response_handle, - gpointer user_data) { - TestData* data = static_cast(user_data); + g_autoptr(FlValue) listen_args = fl_value_new_string("LISTEN-ARGS"); + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "listen", listen_args, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) {}, + nullptr); + g_autoptr(FlValue) cancel_args = fl_value_new_string("CANCEL-ARGS"); + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "cancel", cancel_args, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) {}, + nullptr); - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(GError) error = nullptr; - g_autoptr(FlMethodResponse) response = - fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error); - EXPECT_NE(response, nullptr); - EXPECT_EQ(error, nullptr); - - FlValue* result = fl_method_response_get_result(response, &error); - EXPECT_NE(result, nullptr); - EXPECT_EQ(error, nullptr); - - EXPECT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_INT); - EXPECT_EQ(fl_value_get_int(result), data->count); - data->count++; - - fl_binary_messenger_send_response(messenger, response_handle, nullptr, - nullptr); - - // Got all the results! - if (data->count == 5) { - g_main_loop_quit(data->loop); - } + EXPECT_EQ(call_count, 2); } // Checks can send events. -TEST(FlEventChannelTest, Test) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - TestData data; - data.loop = loop; - data.count = 0; - - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - FlEventChannel* channel = fl_event_channel_new( - messenger, "test/standard-event", FL_METHOD_CODEC(codec)); - fl_event_channel_set_stream_handlers(channel, send_events_listen_cb, nullptr, - &data, nullptr); - - // Listen for events from the engine. - fl_binary_messenger_set_message_handler_on_channel( - messenger, "test/events", send_events_events_cb, &data, nullptr); - - listen_channel(messenger, nullptr); - cancel_channel(messenger, nullptr); +TEST(FlEventChannelTest, SendEvents) { + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); + int event_count = 0; + fl_mock_binary_messenger_set_standard_event_channel( + messenger, "test", + [](FlMockBinaryMessenger* messenger, FlValue* event, gpointer user_data) { + int* event_count = static_cast(user_data); + + EXPECT_EQ(fl_value_get_type(event), FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(event), *event_count); + + (*event_count)++; + }, + [](FlMockBinaryMessenger* messenger, const gchar* code, + const gchar* message, FlValue* details, gpointer user_data) {}, + &event_count); - // Blocks here until send_events_events_cb receives the last event. - g_main_loop_run(loop); + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + g_autoptr(FlEventChannel) channel = fl_event_channel_new( + FL_BINARY_MESSENGER(messenger), "test", FL_METHOD_CODEC(codec)); + fl_event_channel_set_stream_handlers( + channel, + [](FlEventChannel* channel, FlValue* args, gpointer user_data) { + // Send some events. + for (int i = 0; i < 5; i++) { + g_autoptr(FlValue) event = fl_value_new_int(i); + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_event_channel_send(channel, event, nullptr, &error)); + EXPECT_EQ(error, nullptr); + } + + return static_cast(nullptr); + }, + nullptr, nullptr, nullptr); + + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "listen", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) {}, + nullptr); + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "cancel", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) {}, + nullptr); - // Manually unref because the compiler complains 'channel' is unused. - g_object_unref(channel); + EXPECT_EQ(event_count, 5); } // Check can register an event channel with the same name as one previously // used. TEST(FlEventChannelTest, ReuseChannel) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - TestData data; - data.loop = loop; - data.count = 0; - - // Register an event channel. - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); + int event_count = 0; + fl_mock_binary_messenger_set_standard_event_channel( + messenger, "test", + [](FlMockBinaryMessenger* messenger, FlValue* event, gpointer user_data) { + int* event_count = static_cast(user_data); + + EXPECT_EQ(fl_value_get_type(event), FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(event), *event_count); + + (*event_count)++; + }, + [](FlMockBinaryMessenger* messenger, const gchar* code, + const gchar* message, FlValue* details, gpointer user_data) {}, + &event_count); + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); FlEventChannel* channel1 = fl_event_channel_new( - messenger, "test/standard-event", FL_METHOD_CODEC(codec)); - fl_event_channel_set_stream_handlers(channel1, send_events_listen_cb, nullptr, - &data, nullptr); + FL_BINARY_MESSENGER(messenger), "test", FL_METHOD_CODEC(codec)); + fl_event_channel_set_stream_handlers( + channel1, + [](FlEventChannel* channel, FlValue* args, gpointer user_data) { + // Send some events. + for (int i = 0; i < 5; i++) { + g_autoptr(FlValue) event = fl_value_new_int(100 + i); + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_event_channel_send(channel, event, nullptr, &error)); + EXPECT_EQ(error, nullptr); + } + + return static_cast(nullptr); + }, + nullptr, nullptr, nullptr); // Remove this channel g_object_unref(channel1); // Register a second channel with the same name. g_autoptr(FlEventChannel) channel2 = fl_event_channel_new( - messenger, "test/standard-event", FL_METHOD_CODEC(codec)); - fl_event_channel_set_stream_handlers(channel2, send_events_listen_cb, nullptr, - &data, nullptr); - - // Listen for events from the engine. - fl_binary_messenger_set_message_handler_on_channel( - messenger, "test/events", send_events_events_cb, &data, nullptr); - - listen_channel(messenger, nullptr); - cancel_channel(messenger, nullptr); + FL_BINARY_MESSENGER(messenger), "test", FL_METHOD_CODEC(codec)); + fl_event_channel_set_stream_handlers( + channel2, + [](FlEventChannel* channel, FlValue* args, gpointer user_data) { + // Send some events. + for (int i = 0; i < 5; i++) { + g_autoptr(FlValue) event = fl_value_new_int(i); + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_event_channel_send(channel, event, nullptr, &error)); + EXPECT_EQ(error, nullptr); + } + + return static_cast(nullptr); + }, + nullptr, nullptr, nullptr); + + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "listen", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) {}, + nullptr); + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "cancel", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) {}, + nullptr); - // Blocks here until send_events_events_cb receives the last event. - g_main_loop_run(loop); + EXPECT_EQ(event_count, 5); } // Check can register an event channel replacing an existing one. TEST(FlEventChannelTest, ReplaceChannel) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - TestData data; - data.loop = loop; - data.count = 0; - - // Register an event channel. - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); + int event_count = 0; + fl_mock_binary_messenger_set_standard_event_channel( + messenger, "test", + [](FlMockBinaryMessenger* messenger, FlValue* event, gpointer user_data) { + int* event_count = static_cast(user_data); + + EXPECT_EQ(fl_value_get_type(event), FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(event), *event_count); + + (*event_count)++; + }, + [](FlMockBinaryMessenger* messenger, const gchar* code, + const gchar* message, FlValue* details, gpointer user_data) {}, + &event_count); + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); FlEventChannel* channel1 = fl_event_channel_new( - messenger, "test/standard-event", FL_METHOD_CODEC(codec)); - fl_event_channel_set_stream_handlers(channel1, send_events_listen_cb, nullptr, - &data, nullptr); + FL_BINARY_MESSENGER(messenger), "test", FL_METHOD_CODEC(codec)); + fl_event_channel_set_stream_handlers( + channel1, + [](FlEventChannel* channel, FlValue* args, gpointer user_data) { + // Send some events. + for (int i = 0; i < 5; i++) { + g_autoptr(FlValue) event = fl_value_new_int(100 + i); + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_event_channel_send(channel, event, nullptr, &error)); + EXPECT_EQ(error, nullptr); + } + + return static_cast(nullptr); + }, + nullptr, nullptr, nullptr); // Register a second channel with the same name. g_autoptr(FlEventChannel) channel2 = fl_event_channel_new( - messenger, "test/standard-event", FL_METHOD_CODEC(codec)); - fl_event_channel_set_stream_handlers(channel2, send_events_listen_cb, nullptr, - &data, nullptr); - - // Listen for events from the engine. - fl_binary_messenger_set_message_handler_on_channel( - messenger, "test/events", send_events_events_cb, &data, nullptr); - - listen_channel(messenger, nullptr); - cancel_channel(messenger, nullptr); + FL_BINARY_MESSENGER(messenger), "test", FL_METHOD_CODEC(codec)); + fl_event_channel_set_stream_handlers( + channel2, + [](FlEventChannel* channel, FlValue* args, gpointer user_data) { + // Send some events. + for (int i = 0; i < 5; i++) { + g_autoptr(FlValue) event = fl_value_new_int(i); + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_event_channel_send(channel, event, nullptr, &error)); + EXPECT_EQ(error, nullptr); + } + + return static_cast(nullptr); + }, + nullptr, nullptr, nullptr); + + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "listen", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) {}, + nullptr); + fl_mock_binary_messenger_invoke_standard_method( + messenger, "test", "cancel", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) {}, + nullptr); - // Blocks here until send_events_events_cb receives the last event. - g_main_loop_run(loop); + EXPECT_EQ(event_count, 5); } diff --git a/shell/platform/linux/testing/fl_mock_binary_messenger.cc b/shell/platform/linux/testing/fl_mock_binary_messenger.cc index a2d37b71580db..5ca2fee59f318 100644 --- a/shell/platform/linux/testing/fl_mock_binary_messenger.cc +++ b/shell/platform/linux/testing/fl_mock_binary_messenger.cc @@ -57,6 +57,7 @@ struct _FlMockBinaryMessenger { GHashTable* mock_channels; GHashTable* mock_message_channels; GHashTable* mock_method_channels; + GHashTable* mock_event_channels; GHashTable* mock_error_channels; }; @@ -122,6 +123,31 @@ static void mock_method_channel_free(MockMethodChannel* channel) { g_free(channel); } +typedef struct { + FlMethodCodec* codec; + FlMockBinaryMessengerEventChannelHandler callback; + FlMockBinaryMessengerEventChannelErrorHandler error_callback; + gpointer user_data; +} MockEventChannel; + +static MockEventChannel* mock_event_channel_new( + FlMockBinaryMessengerEventChannelHandler callback, + FlMockBinaryMessengerEventChannelErrorHandler error_callback, + FlMethodCodec* codec, + gpointer user_data) { + MockEventChannel* channel = g_new0(MockEventChannel, 1); + channel->codec = FL_METHOD_CODEC(g_object_ref(codec)); + channel->callback = callback; + channel->error_callback = error_callback; + channel->user_data = user_data; + return channel; +} + +static void mock_event_channel_free(MockEventChannel* channel) { + g_object_unref(channel->codec); + g_free(channel); +} + typedef struct { gint code; gchar* message; @@ -217,6 +243,8 @@ static void fl_mock_binary_messenger_send_on_channel( g_hash_table_lookup(self->mock_message_channels, channel)); MockMethodChannel* mock_method_channel = static_cast( g_hash_table_lookup(self->mock_method_channels, channel)); + MockEventChannel* mock_event_channel = static_cast( + g_hash_table_lookup(self->mock_event_channels, channel)); MockErrorChannel* mock_error_channel = static_cast( g_hash_table_lookup(self->mock_error_channels, channel)); g_autoptr(GBytes) response = nullptr; @@ -254,6 +282,29 @@ static void fl_mock_binary_messenger_send_on_channel( g_warning("Failed to encode method response: %s", error->message); } } + } else if (mock_event_channel != nullptr) { + g_autoptr(GError) error = nullptr; + g_autoptr(FlMethodResponse) response = fl_method_codec_decode_response( + mock_event_channel->codec, message, &error); + if (response == nullptr) { + g_warning("Failed to decode event response: %s", error->message); + } else if (FL_IS_METHOD_SUCCESS_RESPONSE(response)) { + mock_event_channel->callback(self, + fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + mock_event_channel->user_data); + } else if (FL_IS_METHOD_ERROR_RESPONSE(response)) { + mock_event_channel->error_callback( + self, + fl_method_error_response_get_code(FL_METHOD_ERROR_RESPONSE(response)), + fl_method_error_response_get_message( + FL_METHOD_ERROR_RESPONSE(response)), + fl_method_error_response_get_details( + FL_METHOD_ERROR_RESPONSE(response)), + mock_event_channel->user_data); + } else { + g_warning("Unknown event response"); + } } else if (mock_error_channel != nullptr) { g_task_return_new_error(task, fl_binary_messenger_codec_error_quark(), mock_error_channel->code, "%s", @@ -295,6 +346,7 @@ static void fl_mock_binary_messenger_dispose(GObject* object) { g_clear_pointer(&self->mock_channels, g_hash_table_unref); g_clear_pointer(&self->mock_message_channels, g_hash_table_unref); g_clear_pointer(&self->mock_method_channels, g_hash_table_unref); + g_clear_pointer(&self->mock_event_channels, g_hash_table_unref); g_clear_pointer(&self->mock_error_channels, g_hash_table_unref); G_OBJECT_CLASS(fl_mock_binary_messenger_parent_class)->dispose(object); @@ -331,6 +383,8 @@ static void fl_mock_binary_messenger_init(FlMockBinaryMessenger* self) { self->mock_method_channels = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)mock_method_channel_free); + self->mock_event_channels = g_hash_table_new_full( + g_str_hash, g_str_equal, g_free, (GDestroyNotify)mock_event_channel_free); self->mock_error_channels = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, (GDestroyNotify)mock_error_channel_free); } @@ -440,6 +494,44 @@ void fl_mock_binary_messenger_set_json_method_channel( self, channel, FL_METHOD_CODEC(codec), handler, user_data); } +void fl_mock_binary_messenger_set_event_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMethodCodec* codec, + FlMockBinaryMessengerEventChannelHandler handler, + FlMockBinaryMessengerEventChannelErrorHandler error_handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_hash_table_insert( + self->mock_event_channels, g_strdup(channel), + mock_event_channel_new(handler, error_handler, codec, user_data)); +} + +void fl_mock_binary_messenger_set_standard_event_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerEventChannelHandler handler, + FlMockBinaryMessengerEventChannelErrorHandler error_handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + fl_mock_binary_messenger_set_event_channel( + self, channel, FL_METHOD_CODEC(codec), handler, error_handler, user_data); +} + +void fl_mock_binary_messenger_set_json_event_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerEventChannelHandler handler, + FlMockBinaryMessengerEventChannelErrorHandler error_handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); + fl_mock_binary_messenger_set_event_channel( + self, channel, FL_METHOD_CODEC(codec), handler, error_handler, user_data); +} + void fl_mock_binary_messenger_set_error_channel(FlMockBinaryMessenger* self, const gchar* channel, gint code, diff --git a/shell/platform/linux/testing/fl_mock_binary_messenger.h b/shell/platform/linux/testing/fl_mock_binary_messenger.h index 22a10413da263..43d8e6ee0096f 100644 --- a/shell/platform/linux/testing/fl_mock_binary_messenger.h +++ b/shell/platform/linux/testing/fl_mock_binary_messenger.h @@ -33,6 +33,18 @@ typedef FlMethodResponse* (*FlMockBinaryMessengerMethodChannelHandler)( FlValue* args, gpointer user_data); +typedef void (*FlMockBinaryMessengerEventChannelHandler)( + FlMockBinaryMessenger* messenger, + FlValue* event, + gpointer user_data); + +typedef void (*FlMockBinaryMessengerEventChannelErrorHandler)( + FlMockBinaryMessenger* messenger, + const gchar* code, + const gchar* message, + FlValue* details, + gpointer user_data); + typedef void (*FlMockBinaryMessengerCallback)(FlMockBinaryMessenger* messenger, GBytes* response, gpointer user_data); @@ -102,6 +114,28 @@ void fl_mock_binary_messenger_set_json_method_channel( FlMockBinaryMessengerMethodChannelHandler handler, gpointer user_data); +void fl_mock_binary_messenger_set_event_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMethodCodec* codec, + FlMockBinaryMessengerEventChannelHandler handler, + FlMockBinaryMessengerEventChannelErrorHandler error_handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_standard_event_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerEventChannelHandler handler, + FlMockBinaryMessengerEventChannelErrorHandler error_handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_json_event_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerEventChannelHandler handler, + FlMockBinaryMessengerEventChannelErrorHandler error_handler, + gpointer user_data); + void fl_mock_binary_messenger_set_error_channel(FlMockBinaryMessenger* self, const gchar* channel, gint code, diff --git a/shell/platform/linux/testing/mock_engine.cc b/shell/platform/linux/testing/mock_engine.cc index f986cf25ef06f..5db5d3704b397 100644 --- a/shell/platform/linux/testing/mock_engine.cc +++ b/shell/platform/linux/testing/mock_engine.cc @@ -321,10 +321,6 @@ FlutterEngineResult FlutterEngineSendPlatformMessage( // Sends a null response. send_response(engine, message->channel, message->response_handle, nullptr, 0); - } else if (strcmp(message->channel, "test/standard-event") == 0) { - // Send a message so the shell can check the events sent. - send_message(engine, "test/events", message->message, - message->message_size); } else if (strcmp(message->channel, "test/failure") == 0) { // Generates an internal error. return kInternalInconsistency;