diff --git a/engine/src/flutter/shell/platform/linux/BUILD.gn b/engine/src/flutter/shell/platform/linux/BUILD.gn index 78b0bed8d8..55e8208a33 100644 --- a/engine/src/flutter/shell/platform/linux/BUILD.gn +++ b/engine/src/flutter/shell/platform/linux/BUILD.gn @@ -249,11 +249,10 @@ executable("flutter_linux_unittests") { "fl_view_test.cc", "fl_window_state_monitor_test.cc", "key_mapping_test.cc", + "testing/fl_mock_binary_messenger.cc", "testing/fl_test.cc", "testing/fl_test_gtk_logs.cc", "testing/fl_test_gtk_logs.h", - "testing/mock_binary_messenger.cc", - "testing/mock_binary_messenger_response_handle.cc", "testing/mock_engine.cc", "testing/mock_epoxy.cc", "testing/mock_im_context.cc", diff --git a/engine/src/flutter/shell/platform/linux/fl_binary_messenger_test.cc b/engine/src/flutter/shell/platform/linux/fl_binary_messenger_test.cc index 133f6e4b57..8f03eb5140 100644 --- a/engine/src/flutter/shell/platform/linux/fl_binary_messenger_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_binary_messenger_test.cc @@ -16,9 +16,34 @@ #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/fl_test.h" -#include "flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.h" #include "flutter/shell/platform/linux/testing/mock_renderer.h" +G_DECLARE_FINAL_TYPE(FlFakeBinaryMessengerResponseHandle, + fl_fake_binary_messenger_response_handle, + FL, + FAKE_BINARY_MESSENGER_RESPONSE_HANDLE, + FlBinaryMessengerResponseHandle) + +struct _FlFakeBinaryMessengerResponseHandle { + FlBinaryMessengerResponseHandle parent_instance; +}; + +G_DEFINE_TYPE(FlFakeBinaryMessengerResponseHandle, + fl_fake_binary_messenger_response_handle, + fl_binary_messenger_response_handle_get_type()); + +static void fl_fake_binary_messenger_response_handle_class_init( + FlFakeBinaryMessengerResponseHandleClass* klass) {} + +static void fl_fake_binary_messenger_response_handle_init( + FlFakeBinaryMessengerResponseHandle* self) {} + +FlFakeBinaryMessengerResponseHandle* +fl_fake_binary_messenger_response_handle_new() { + return FL_FAKE_BINARY_MESSENGER_RESPONSE_HANDLE( + g_object_new(fl_fake_binary_messenger_response_handle_get_type(), NULL)); +} + G_DECLARE_FINAL_TYPE(FlFakeBinaryMessenger, fl_fake_binary_messenger, FL, @@ -55,7 +80,7 @@ static gboolean send_message_cb(gpointer user_data) { g_autoptr(GBytes) message = g_bytes_new(text, strlen(text)); self->message_handler(FL_BINARY_MESSENGER(self), "CHANNEL", message, FL_BINARY_MESSENGER_RESPONSE_HANDLE( - fl_mock_binary_messenger_response_handle_new()), + fl_fake_binary_messenger_response_handle_new()), self->message_handler_user_data); return FALSE; @@ -83,7 +108,7 @@ static gboolean send_response(FlBinaryMessenger* messenger, GError** error) { FlFakeBinaryMessenger* self = FL_FAKE_BINARY_MESSENGER(messenger); - EXPECT_TRUE(FL_IS_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle)); + EXPECT_TRUE(FL_IS_FAKE_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle)); g_autofree gchar* text = g_strndup(static_cast(g_bytes_get_data(response, nullptr)), diff --git a/engine/src/flutter/shell/platform/linux/fl_key_channel_responder.cc b/engine/src/flutter/shell/platform/linux/fl_key_channel_responder.cc index 757cc5d893..5eadb6dc33 100644 --- a/engine/src/flutter/shell/platform/linux/fl_key_channel_responder.cc +++ b/engine/src/flutter/shell/platform/linux/fl_key_channel_responder.cc @@ -94,8 +94,6 @@ struct _FlKeyChannelResponder { GObject parent_instance; FlBasicMessageChannel* channel; - - FlKeyChannelResponderMock* mock; }; G_DEFINE_TYPE(FlKeyChannelResponder, fl_key_channel_responder, G_TYPE_OBJECT) @@ -117,9 +115,6 @@ static void handle_response(GObject* object, FlBasicMessageChannel* messageChannel = FL_BASIC_MESSAGE_CHANNEL(object); FlValue* message = fl_basic_message_channel_send_finish(messageChannel, result, &error); - if (self->mock != nullptr && self->mock->value_converter != nullptr) { - message = self->mock->value_converter(message); - } bool handled = false; if (error != nullptr) { g_warning("Unable to retrieve framework response: %s", error->message); @@ -152,22 +147,16 @@ static void fl_key_channel_responder_init(FlKeyChannelResponder* self) {} // Creates a new FlKeyChannelResponder instance, with a messenger used to send // messages to the framework, and an FlTextInputHandler that is used to handle -// key events that the framework doesn't handle. Mainly for testing purposes, it -// also takes an optional callback to call when a response is received, and an -// optional channel name to use when sending messages. +// key events that the framework doesn't handle. FlKeyChannelResponder* fl_key_channel_responder_new( - FlBinaryMessenger* messenger, - FlKeyChannelResponderMock* mock) { + FlBinaryMessenger* messenger) { g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER( g_object_new(fl_key_channel_responder_get_type(), nullptr)); - self->mock = mock; g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); - const char* channel_name = - mock == nullptr ? kChannelName : mock->channel_name; - self->channel = fl_basic_message_channel_new(messenger, channel_name, + self->channel = fl_basic_message_channel_new(messenger, kChannelName, FL_MESSAGE_CODEC(codec)); return self; diff --git a/engine/src/flutter/shell/platform/linux/fl_key_channel_responder.h b/engine/src/flutter/shell/platform/linux/fl_key_channel_responder.h index 66a47d22bd..13d7787527 100644 --- a/engine/src/flutter/shell/platform/linux/fl_key_channel_responder.h +++ b/engine/src/flutter/shell/platform/linux/fl_key_channel_responder.h @@ -11,27 +11,6 @@ typedef FlValue* (*FlValueConverter)(FlValue*); -/** - * FlKeyChannelResponderMock: - * - * Allows mocking of FlKeyChannelResponder methods and values. Only used in - * unittests. - */ -typedef struct _FlKeyChannelResponderMock { - /** - * FlKeyChannelResponderMock::value_converter: - * If #value_converter is not nullptr, then this function is applied to the - * reply of the message, whose return value is taken as the message reply. - */ - FlValueConverter value_converter; - - /** - * FlKeyChannelResponderMock::channel_name: - * Mocks the channel name to send the message. - */ - const char* channel_name; -} FlKeyChannelResponderMock; - G_BEGIN_DECLS G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, @@ -64,15 +43,13 @@ typedef void (*FlKeyChannelResponderAsyncCallback)(bool handled, /** * fl_key_channel_responder_new: * @messenger: the messenger that the message channel should be built on. - * @mock: options to mock several functionalities. Only used in unittests. * * Creates a new #FlKeyChannelResponder. * * Returns: a new #FlKeyChannelResponder. */ FlKeyChannelResponder* fl_key_channel_responder_new( - FlBinaryMessenger* messenger, - FlKeyChannelResponderMock* mock = nullptr); + FlBinaryMessenger* messenger); /** * fl_key_channel_responder_handle_event: diff --git a/engine/src/flutter/shell/platform/linux/fl_key_channel_responder_test.cc b/engine/src/flutter/shell/platform/linux/fl_key_channel_responder_test.cc index 2c68d40b0d..7b25eb2c95 100644 --- a/engine/src/flutter/shell/platform/linux/fl_key_channel_responder_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_key_channel_responder_test.cc @@ -7,64 +7,81 @@ #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/testing/fl_test.h" +#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h" -static const char* expected_value = nullptr; -static gboolean expected_handled = FALSE; +typedef struct { + const gchar* expected_message; + gboolean handled; +} KeyEventData; -static FlValue* echo_response_cb(FlValue* echoed_value) { - gchar* text = fl_value_to_string(echoed_value); - EXPECT_STREQ(text, expected_value); - g_free(text); +static FlValue* key_event_cb(FlMockBinaryMessenger* messenger, + FlValue* message, + gpointer user_data) { + KeyEventData* data = static_cast(user_data); - FlValue* value = fl_value_new_map(); - fl_value_set_string_take(value, "handled", - fl_value_new_bool(expected_handled)); - return value; + g_autofree gchar* message_string = fl_value_to_string(message); + EXPECT_STREQ(message_string, data->expected_message); + + FlValue* response = fl_value_new_map(); + fl_value_set_string_take(response, "handled", + fl_value_new_bool(data->handled)); + + free(data); + + return response; } -static void responder_callback(bool handled, gpointer user_data) { - EXPECT_EQ(handled, expected_handled); - g_main_loop_quit(static_cast(user_data)); +static void set_key_event_channel(FlMockBinaryMessenger* messenger, + const gchar* expected_message, + gboolean handled) { + KeyEventData* data = g_new0(KeyEventData, 1); + data->expected_message = expected_message; + data->handled = handled; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/keyevent", key_event_cb, data); } // Test sending a letter "A"; TEST(FlKeyChannelResponderTest, SendKeyEvent) { 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); - FlKeyChannelResponderMock mock{ - .value_converter = echo_response_cb, - .channel_name = "test/echo", - }; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlKeyChannelResponder) responder = - fl_key_channel_responder_new(messenger, &mock); + fl_key_channel_responder_new(FL_BINARY_MESSENGER(messenger)); + set_key_event_channel( + messenger, + "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " + "modifiers: 0, unicodeScalarValues: 65}", + FALSE); g_autoptr(FlKeyEvent) event1 = fl_key_event_new( 12345, TRUE, 0x04, GDK_KEY_A, static_cast(0), 0); - fl_key_channel_responder_handle_event(responder, event1, 0, - responder_callback, loop); - expected_value = - "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " - "modifiers: 0, unicodeScalarValues: 65}"; - expected_handled = FALSE; - - // Blocks here until echo_response_cb is called. + fl_key_channel_responder_handle_event( + responder, event1, 0, + [](bool handled, gpointer user_data) { + EXPECT_FALSE(handled); + g_main_loop_quit(static_cast(user_data)); + }, + loop); g_main_loop_run(loop); + set_key_event_channel( + messenger, + "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " + "modifiers: 0, unicodeScalarValues: 65}", + FALSE); g_autoptr(FlKeyEvent) event2 = fl_key_event_new( 23456, FALSE, 0x04, GDK_KEY_A, static_cast(0), 0); - fl_key_channel_responder_handle_event(responder, event2, 0, - responder_callback, loop); - expected_value = - "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " - "modifiers: 0, unicodeScalarValues: 65}"; - expected_handled = FALSE; - - // Blocks here until echo_response_cb is called. + fl_key_channel_responder_handle_event( + responder, event2, 0, + [](bool handled, gpointer user_data) { + EXPECT_FALSE(handled); + g_main_loop_quit(static_cast(user_data)); + }, + loop); g_main_loop_run(loop); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } void test_lock_event(guint key_code, @@ -72,34 +89,35 @@ void test_lock_event(guint key_code, const char* up_expected) { 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); - FlKeyChannelResponderMock mock{ - .value_converter = echo_response_cb, - .channel_name = "test/echo", - }; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlKeyChannelResponder) responder = - fl_key_channel_responder_new(messenger, &mock); + fl_key_channel_responder_new(FL_BINARY_MESSENGER(messenger)); + set_key_event_channel(messenger, down_expected, FALSE); g_autoptr(FlKeyEvent) event1 = fl_key_event_new( 12345, TRUE, 0x04, key_code, static_cast(0), 0); - fl_key_channel_responder_handle_event(responder, event1, 0, - responder_callback, loop); - expected_value = down_expected; - expected_handled = FALSE; - - // Blocks here until echo_response_cb is called. + fl_key_channel_responder_handle_event( + responder, event1, 0, + [](bool handled, gpointer user_data) { + EXPECT_FALSE(handled); + g_main_loop_quit(static_cast(user_data)); + }, + loop); g_main_loop_run(loop); - expected_value = up_expected; - expected_handled = FALSE; + set_key_event_channel(messenger, up_expected, FALSE); g_autoptr(FlKeyEvent) event2 = fl_key_event_new( 12346, FALSE, 0x04, key_code, static_cast(0), 0); - fl_key_channel_responder_handle_event(responder, event2, 0, - responder_callback, loop); - - // Blocks here until echo_response_cb is called. + fl_key_channel_responder_handle_event( + responder, event2, 0, + [](bool handled, gpointer user_data) { + EXPECT_FALSE(handled); + g_main_loop_quit(static_cast(user_data)); + }, + loop); g_main_loop_run(loop); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } // Test sending a "NumLock" keypress. @@ -132,50 +150,52 @@ TEST(FlKeyChannelResponderTest, SendShiftLockKeyEvent) { TEST(FlKeyChannelResponderTest, TestKeyEventHandledByFramework) { 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); - FlKeyChannelResponderMock mock{ - .value_converter = echo_response_cb, - .channel_name = "test/echo", - }; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlKeyChannelResponder) responder = - fl_key_channel_responder_new(messenger, &mock); + fl_key_channel_responder_new(FL_BINARY_MESSENGER(messenger)); + set_key_event_channel( + messenger, + "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " + "keyCode: 65, modifiers: 0, unicodeScalarValues: 65}", + TRUE); g_autoptr(FlKeyEvent) event = fl_key_event_new( 12345, TRUE, 0x04, GDK_KEY_A, static_cast(0), 0); - fl_key_channel_responder_handle_event(responder, event, 0, responder_callback, - loop); - expected_handled = TRUE; - expected_value = - "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " - "keyCode: 65, modifiers: 0, unicodeScalarValues: 65}"; - - // Blocks here until echo_response_cb is called. + fl_key_channel_responder_handle_event( + responder, event, 0, + [](bool handled, gpointer user_data) { + EXPECT_TRUE(handled); + g_main_loop_quit(static_cast(user_data)); + }, + loop); g_main_loop_run(loop); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlKeyChannelResponderTest, UseSpecifiedLogicalKey) { 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); - FlKeyChannelResponderMock mock{ - .value_converter = echo_response_cb, - .channel_name = "test/echo", - }; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlKeyChannelResponder) responder = - fl_key_channel_responder_new(messenger, &mock); + fl_key_channel_responder_new(FL_BINARY_MESSENGER(messenger)); - g_autoptr(FlKeyEvent) event = fl_key_event_new( - 12345, TRUE, 0x04, GDK_KEY_A, static_cast(0), 0); - fl_key_channel_responder_handle_event(responder, event, 888, - responder_callback, loop); - expected_handled = TRUE; - expected_value = + set_key_event_channel( + messenger, "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " "keyCode: 65, modifiers: 0, unicodeScalarValues: 65, " - "specifiedLogicalKey: 888}"; - - // Blocks here until echo_response_cb is called. + "specifiedLogicalKey: 888}", + TRUE); + g_autoptr(FlKeyEvent) event = fl_key_event_new( + 12345, TRUE, 0x04, GDK_KEY_A, static_cast(0), 0); + fl_key_channel_responder_handle_event( + responder, event, 888, + [](bool handled, gpointer user_data) { + EXPECT_TRUE(handled); + g_main_loop_quit(static_cast(user_data)); + }, + loop); g_main_loop_run(loop); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } diff --git a/engine/src/flutter/shell/platform/linux/fl_keyboard_handler_test.cc b/engine/src/flutter/shell/platform/linux/fl_keyboard_handler_test.cc index 26fd103263..5cb1f6c86b 100644 --- a/engine/src/flutter/shell/platform/linux/fl_keyboard_handler_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_keyboard_handler_test.cc @@ -4,9 +4,10 @@ #include "flutter/shell/platform/linux/fl_keyboard_handler.h" +#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" #include "flutter/shell/platform/linux/fl_method_codec_private.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" -#include "flutter/shell/platform/linux/testing/mock_binary_messenger.h" +#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -26,19 +27,6 @@ G_DECLARE_FINAL_TYPE(FlMockKeyboardHandlerDelegate, G_END_DECLS -MATCHER_P(MethodSuccessResponse, result, "") { - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(FlMethodResponse) response = - fl_method_codec_decode_response(FL_METHOD_CODEC(codec), arg, nullptr); - fl_method_response_get_result(response, nullptr); - if (fl_value_equal(fl_method_response_get_result(response, nullptr), - result)) { - return true; - } - *result_listener << ::testing::PrintToString(response); - return false; -} - struct _FlMockKeyboardHandlerDelegate { GObject parent_instance; }; @@ -74,8 +62,7 @@ static FlMockKeyboardHandlerDelegate* fl_mock_keyboard_handler_delegate_new() { } TEST(FlKeyboardHandlerTest, KeyboardChannelGetPressedState) { - ::testing::NiceMock messenger; - + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlEngine) engine = FL_ENGINE(g_object_new(fl_engine_get_type(), "binary-messenger", FL_BINARY_MESSENGER(messenger), nullptr)); @@ -95,21 +82,28 @@ TEST(FlKeyboardHandlerTest, KeyboardChannelGetPressedState) { }, nullptr); g_autoptr(FlKeyboardHandler) handler = - fl_keyboard_handler_new(messenger, manager); + fl_keyboard_handler_new(FL_BINARY_MESSENGER(messenger), manager); EXPECT_NE(handler, nullptr); - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), kGetKeyboardStateMethod, nullptr, nullptr); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_standard_method( + messenger, kKeyboardChannelName, kGetKeyboardStateMethod, nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; - g_autoptr(FlValue) response = fl_value_new_map(); - fl_value_set_take(response, fl_value_new_int(kMockPhysicalKey), - fl_value_new_int(kMockLogicalKey)); - EXPECT_CALL(messenger, - fl_binary_messenger_send_response( - ::testing::Eq(messenger), ::testing::_, - MethodSuccessResponse(response), ::testing::_)) - .WillOnce(::testing::Return(true)); + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - messenger.ReceiveMessage(kKeyboardChannelName, message); + g_autoptr(FlValue) expected_result = fl_value_new_map(); + fl_value_set_take(expected_result, fl_value_new_int(kMockPhysicalKey), + fl_value_new_int(kMockLogicalKey)); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } diff --git a/engine/src/flutter/shell/platform/linux/fl_method_channel.cc b/engine/src/flutter/shell/platform/linux/fl_method_channel.cc index 1177d63f05..e0d94e7bb3 100644 --- a/engine/src/flutter/shell/platform/linux/fl_method_channel.cc +++ b/engine/src/flutter/shell/platform/linux/fl_method_channel.cc @@ -220,34 +220,13 @@ gboolean fl_method_channel_respond( g_return_val_if_fail(FL_IS_METHOD_CHANNEL(self), FALSE); g_return_val_if_fail(FL_IS_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle), FALSE); - g_return_val_if_fail(FL_IS_METHOD_SUCCESS_RESPONSE(response) || - FL_IS_METHOD_ERROR_RESPONSE(response) || - FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response), - FALSE); + g_return_val_if_fail(FL_IS_METHOD_RESPONSE(response), FALSE); - g_autoptr(GBytes) message = nullptr; - if (FL_IS_METHOD_SUCCESS_RESPONSE(response)) { - FlMethodSuccessResponse* r = FL_METHOD_SUCCESS_RESPONSE(response); - message = fl_method_codec_encode_success_envelope( - self->codec, fl_method_success_response_get_result(r), error); - if (message == nullptr) { - return FALSE; - } - } else if (FL_IS_METHOD_ERROR_RESPONSE(response)) { - FlMethodErrorResponse* r = FL_METHOD_ERROR_RESPONSE(response); - message = fl_method_codec_encode_error_envelope( - self->codec, fl_method_error_response_get_code(r), - fl_method_error_response_get_message(r), - fl_method_error_response_get_details(r), error); - if (message == nullptr) { - return FALSE; - } - } else if (FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response)) { - message = nullptr; - } else { - g_assert_not_reached(); + g_autoptr(GBytes) message = + fl_method_codec_encode_response(self->codec, response, error); + if (message == nullptr) { + return FALSE; } - return fl_binary_messenger_send_response(self->messenger, response_handle, message, error); } diff --git a/engine/src/flutter/shell/platform/linux/fl_method_codec.cc b/engine/src/flutter/shell/platform/linux/fl_method_codec.cc index 5b6d87c47a..a0c023ca75 100644 --- a/engine/src/flutter/shell/platform/linux/fl_method_codec.cc +++ b/engine/src/flutter/shell/platform/linux/fl_method_codec.cc @@ -59,6 +59,32 @@ GBytes* fl_method_codec_encode_error_envelope(FlMethodCodec* self, self, code, message, details, error); } +GBytes* fl_method_codec_encode_response(FlMethodCodec* self, + FlMethodResponse* response, + GError** error) { + g_return_val_if_fail(FL_IS_METHOD_CODEC(self), nullptr); + g_return_val_if_fail(FL_IS_METHOD_SUCCESS_RESPONSE(response) || + FL_IS_METHOD_ERROR_RESPONSE(response) || + FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response), + nullptr); + + if (FL_IS_METHOD_SUCCESS_RESPONSE(response)) { + FlMethodSuccessResponse* r = FL_METHOD_SUCCESS_RESPONSE(response); + return fl_method_codec_encode_success_envelope( + self, fl_method_success_response_get_result(r), error); + } else if (FL_IS_METHOD_ERROR_RESPONSE(response)) { + FlMethodErrorResponse* r = FL_METHOD_ERROR_RESPONSE(response); + return fl_method_codec_encode_error_envelope( + self, fl_method_error_response_get_code(r), + fl_method_error_response_get_message(r), + fl_method_error_response_get_details(r), error); + } else if (FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response)) { + return g_bytes_new(nullptr, 0); + } else { + g_assert_not_reached(); + } +} + FlMethodResponse* fl_method_codec_decode_response(FlMethodCodec* self, GBytes* message, GError** error) { diff --git a/engine/src/flutter/shell/platform/linux/fl_method_codec_private.h b/engine/src/flutter/shell/platform/linux/fl_method_codec_private.h index 8912093adc..1880b09cd0 100644 --- a/engine/src/flutter/shell/platform/linux/fl_method_codec_private.h +++ b/engine/src/flutter/shell/platform/linux/fl_method_codec_private.h @@ -85,6 +85,21 @@ GBytes* fl_method_codec_encode_error_envelope(FlMethodCodec* codec, FlValue* details, GError** error); +/** + * fl_method_codec_encode_response: + * @codec: an #FlMethodCodec. + * @response: response to encode. + * @error: (allow-none): #GError location to store the error occurring, or + * %NULL. + * + * Encodes a response to a method call. + * + * Returns: a new #FlMethodResponse or %NULL on error. + */ +GBytes* fl_method_codec_encode_response(FlMethodCodec* codec, + FlMethodResponse* response, + GError** error); + /** * fl_method_codec_decode_response: * @codec: an #FlMethodCodec. @@ -92,8 +107,7 @@ GBytes* fl_method_codec_encode_error_envelope(FlMethodCodec* codec, * @error: (allow-none): #GError location to store the error occurring, or * %NULL. * - * Decodes a response to a method call. If the call resulted in an error then - * @error_code is set, otherwise it is %NULL. + * Decodes a response to a method call. * * Returns: a new #FlMethodResponse or %NULL on error. */ diff --git a/engine/src/flutter/shell/platform/linux/fl_platform_handler_test.cc b/engine/src/flutter/shell/platform/linux/fl_platform_handler_test.cc index 98369d227b..4de202e1eb 100644 --- a/engine/src/flutter/shell/platform/linux/fl_platform_handler_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_platform_handler_test.cc @@ -5,90 +5,14 @@ #include #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" -#include "flutter/shell/platform/linux/fl_method_codec_private.h" #include "flutter/shell/platform/linux/fl_platform_handler.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_method_codec.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h" +#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h" #include "flutter/shell/platform/linux/testing/fl_test.h" -#include "flutter/shell/platform/linux/testing/mock_binary_messenger.h" -#include "flutter/testing/testing.h" #include "gmock/gmock.h" #include "gtest/gtest.h" -MATCHER_P(SuccessResponse, result, "") { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(FlMethodResponse) response = - fl_method_codec_decode_response(FL_METHOD_CODEC(codec), arg, nullptr); - if (fl_value_equal(fl_method_response_get_result(response, nullptr), - result)) { - return true; - } - *result_listener << ::testing::PrintToString(response); - return false; -} - -class MethodCallMatcher { - public: - using is_gtest_matcher = void; - - explicit MethodCallMatcher(::testing::Matcher name, - ::testing::Matcher args) - : name_(std::move(name)), args_(std::move(args)) {} - - bool MatchAndExplain(GBytes* method_call, - ::testing::MatchResultListener* result_listener) const { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GError) error = nullptr; - g_autofree gchar* name = nullptr; - g_autoptr(FlValue) args = nullptr; - gboolean result = fl_method_codec_decode_method_call( - FL_METHOD_CODEC(codec), method_call, &name, &args, &error); - if (!result) { - *result_listener << ::testing::PrintToString(error->message); - return false; - } - if (!name_.MatchAndExplain(name, result_listener)) { - *result_listener << " where the name doesn't match: \"" << name << "\""; - return false; - } - if (!args_.MatchAndExplain(args, result_listener)) { - *result_listener << " where the args don't match: " - << ::testing::PrintToString(args); - return false; - } - return true; - } - - void DescribeTo(std::ostream* os) const { - *os << "method name "; - name_.DescribeTo(os); - *os << " and args "; - args_.DescribeTo(os); - } - - void DescribeNegationTo(std::ostream* os) const { - *os << "method name "; - name_.DescribeNegationTo(os); - *os << " or args "; - args_.DescribeNegationTo(os); - } - - private: - ::testing::Matcher name_; - ::testing::Matcher args_; -}; - -static ::testing::Matcher MethodCall( - const std::string& name, - ::testing::Matcher args) { - return MethodCallMatcher(::testing::StrEq(name), std::move(args)); -} - -MATCHER_P(FlValueEq, value, "equal to " + ::testing::PrintToString(value)) { - return fl_value_equal(arg, value); -} - G_DECLARE_FINAL_TYPE(FlTestApplication, fl_test_application, FL, @@ -116,26 +40,35 @@ static void fl_test_application_startup(GApplication* application) { static void fl_test_application_activate(GApplication* application) { G_APPLICATION_CLASS(fl_test_application_parent_class)->activate(application); - ::testing::NiceMock messenger; - g_autoptr(FlPlatformHandler) handler = fl_platform_handler_new(messenger); + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); + g_autoptr(FlPlatformHandler) handler = + fl_platform_handler_new(FL_BINARY_MESSENGER(messenger)); EXPECT_NE(handler, nullptr); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - - g_autoptr(FlValue) exit_result = fl_value_new_map(); - fl_value_set_string_take(exit_result, "response", - fl_value_new_string("exit")); - EXPECT_CALL(messenger, - fl_binary_messenger_send_response( - ::testing::Eq(messenger), ::testing::_, - SuccessResponse(exit_result), ::testing::_)) - .WillOnce(::testing::Return(true)); // Request app exit. + gboolean called = FALSE; g_autoptr(FlValue) args = fl_value_new_map(); fl_value_set_string_take(args, "type", fl_value_new_string("required")); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "System.exitApplication", args, nullptr); - messenger.ReceiveMessage("flutter/platform", message); + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/platform", "System.exitApplication", args, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_map(); + fl_value_set_string_take(expected_result, "response", + fl_value_new_string("exit")); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } static void fl_test_application_dispose(GObject* object) { @@ -171,59 +104,107 @@ FlTestApplication* fl_test_application_new(gboolean* dispose_called) { } TEST(FlPlatformHandlerTest, PlaySound) { - ::testing::NiceMock messenger; - - g_autoptr(FlPlatformHandler) handler = fl_platform_handler_new(messenger); + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); + g_autoptr(FlPlatformHandler) handler = + fl_platform_handler_new(FL_BINARY_MESSENGER(messenger)); EXPECT_NE(handler, nullptr); + gboolean called = FALSE; g_autoptr(FlValue) args = fl_value_new_string("SystemSoundType.alert"); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "SystemSound.play", args, nullptr); + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/platform", "SystemSound.play", args, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - messenger.ReceiveMessage("flutter/platform", message); + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlPlatformHandlerTest, ExitApplication) { - ::testing::NiceMock messenger; + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - g_autoptr(FlPlatformHandler) handler = fl_platform_handler_new(messenger); + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); + g_autoptr(FlPlatformHandler) handler = + fl_platform_handler_new(FL_BINARY_MESSENGER(messenger)); EXPECT_NE(handler, nullptr); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - - g_autoptr(FlValue) null = fl_value_new_null(); - ON_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillByDefault(testing::Return(TRUE)); // Indicate that the binding is initialized. - g_autoptr(GError) error = nullptr; - g_autoptr(GBytes) init_message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "System.initializationComplete", nullptr, &error); - messenger.ReceiveMessage("flutter/platform", init_message); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/platform", "System.initializationComplete", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; - g_autoptr(FlValue) request_args = fl_value_new_map(); - fl_value_set_string_take(request_args, "type", - fl_value_new_string("cancelable")); - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/platform"), - MethodCall("System.requestAppExit", FlValueEq(request_args)), - ::testing::_, ::testing::_, ::testing::_)); + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + gboolean request_exit_called = FALSE; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/platform", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_STREQ(name, "System.requestAppExit"); + + g_autoptr(FlValue) expected_args = fl_value_new_map(); + fl_value_set_string_take(expected_args, "type", + fl_value_new_string("cancelable")); + EXPECT_TRUE(fl_value_equal(args, expected_args)); + + // Cancel so it doesn't try and exit this app (i.e. the current test) + g_autoptr(FlValue) result = fl_value_new_map(); + fl_value_set_string_take(result, "response", + fl_value_new_string("cancel")); + return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); + }, + &request_exit_called); g_autoptr(FlValue) args = fl_value_new_map(); fl_value_set_string_take(args, "type", fl_value_new_string("cancelable")); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "System.exitApplication", args, nullptr); - messenger.ReceiveMessage("flutter/platform", message); + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/platform", "System.exitApplication", args, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_map(); + fl_value_set_string_take(expected_result, "response", + fl_value_new_string("cancel")); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + + g_main_loop_quit(static_cast(user_data)); + }, + loop); + + g_main_loop_run(loop); + + EXPECT_TRUE(request_exit_called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlPlatformHandlerTest, ExitApplicationDispose) { diff --git a/engine/src/flutter/shell/platform/linux/fl_settings_handler_test.cc b/engine/src/flutter/shell/platform/linux/fl_settings_handler_test.cc index 3bffcc2f23..e8ebd34934 100644 --- a/engine/src/flutter/shell/platform/linux/fl_settings_handler_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_settings_handler_test.cc @@ -5,114 +5,187 @@ #include "flutter/shell/platform/linux/fl_settings_handler.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.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/public/flutter_linux/fl_binary_messenger.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" +#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h" #include "flutter/shell/platform/linux/testing/fl_test.h" -#include "flutter/shell/platform/linux/testing/mock_binary_messenger.h" #include "flutter/shell/platform/linux/testing/mock_settings.h" #include "flutter/testing/testing.h" #include "gmock/gmock.h" #include "gtest/gtest.h" -MATCHER_P2(HasSetting, key, value, "") { - g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); - g_autoptr(FlValue) message = - fl_message_codec_decode_message(FL_MESSAGE_CODEC(codec), arg, nullptr); - if (fl_value_equal(fl_value_lookup_string(message, key), value)) { - return true; - } - *result_listener << ::testing::PrintToString(message); - return false; -} - -#define EXPECT_SETTING(messenger, key, value) \ - EXPECT_CALL( \ - messenger, \ - fl_binary_messenger_send_on_channel( \ - ::testing::Eq(messenger), \ - ::testing::StrEq("flutter/settings"), HasSetting(key, value), \ - ::testing::A(), ::testing::A(), \ - ::testing::A())) - TEST(FlSettingsHandlerTest, AlwaysUse24HourFormat) { ::testing::NiceMock settings; - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlEngine) engine = FL_ENGINE(g_object_new(fl_engine_get_type(), "binary-messenger", FL_BINARY_MESSENGER(messenger), nullptr)); g_autoptr(FlSettingsHandler) handler = fl_settings_handler_new(engine); - g_autoptr(FlValue) use_12h = fl_value_new_bool(false); - g_autoptr(FlValue) use_24h = fl_value_new_bool(true); - EXPECT_CALL(settings, fl_settings_get_clock_format( ::testing::Eq(settings))) .WillOnce(::testing::Return(FL_CLOCK_FORMAT_12H)) .WillOnce(::testing::Return(FL_CLOCK_FORMAT_24H)); - EXPECT_SETTING(messenger, "alwaysUse24HourFormat", use_12h); + gboolean called = FALSE; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/settings", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_MAP); + FlValue* value = + fl_value_lookup_string(message, "alwaysUse24HourFormat"); + EXPECT_NE(value, nullptr); + EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_BOOL); + EXPECT_FALSE(fl_value_get_bool(value)); + + return fl_value_new_null(); + }, + &called); fl_settings_handler_start(handler, settings); + EXPECT_TRUE(called); - EXPECT_SETTING(messenger, "alwaysUse24HourFormat", use_24h); + called = FALSE; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/settings", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_MAP); + FlValue* value = + fl_value_lookup_string(message, "alwaysUse24HourFormat"); + EXPECT_NE(value, nullptr); + EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_BOOL); + EXPECT_TRUE(fl_value_get_bool(value)); + + return fl_value_new_null(); + }, + &called); fl_settings_emit_changed(settings); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlSettingsHandlerTest, PlatformBrightness) { ::testing::NiceMock settings; - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlEngine) engine = FL_ENGINE(g_object_new(fl_engine_get_type(), "binary-messenger", FL_BINARY_MESSENGER(messenger), nullptr)); g_autoptr(FlSettingsHandler) handler = fl_settings_handler_new(engine); - g_autoptr(FlValue) light = fl_value_new_string("light"); - g_autoptr(FlValue) dark = fl_value_new_string("dark"); - EXPECT_CALL(settings, fl_settings_get_color_scheme( ::testing::Eq(settings))) .WillOnce(::testing::Return(FL_COLOR_SCHEME_LIGHT)) .WillOnce(::testing::Return(FL_COLOR_SCHEME_DARK)); - EXPECT_SETTING(messenger, "platformBrightness", light); + gboolean called = FALSE; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/settings", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_MAP); + FlValue* value = fl_value_lookup_string(message, "platformBrightness"); + EXPECT_NE(value, nullptr); + EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(value), "light"); + + return fl_value_new_null(); + }, + &called); fl_settings_handler_start(handler, settings); + EXPECT_TRUE(called); - EXPECT_SETTING(messenger, "platformBrightness", dark); + called = FALSE; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/settings", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_MAP); + FlValue* value = fl_value_lookup_string(message, "platformBrightness"); + EXPECT_NE(value, nullptr); + EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(value), "dark"); + + return fl_value_new_null(); + }, + &called); fl_settings_emit_changed(settings); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlSettingsHandlerTest, TextScaleFactor) { ::testing::NiceMock settings; - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); g_autoptr(FlEngine) engine = FL_ENGINE(g_object_new(fl_engine_get_type(), "binary-messenger", FL_BINARY_MESSENGER(messenger), nullptr)); g_autoptr(FlSettingsHandler) handler = fl_settings_handler_new(engine); - g_autoptr(FlValue) one = fl_value_new_float(1.0); - g_autoptr(FlValue) two = fl_value_new_float(2.0); - EXPECT_CALL(settings, fl_settings_get_text_scaling_factor( ::testing::Eq(settings))) .WillOnce(::testing::Return(1.0)) .WillOnce(::testing::Return(2.0)); - EXPECT_SETTING(messenger, "textScaleFactor", one); + gboolean called = FALSE; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/settings", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_MAP); + FlValue* value = fl_value_lookup_string(message, "textScaleFactor"); + EXPECT_NE(value, nullptr); + EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_FLOAT); + EXPECT_EQ(fl_value_get_float(value), 1.0); + + return fl_value_new_null(); + }, + &called); fl_settings_handler_start(handler, settings); + EXPECT_TRUE(called); - EXPECT_SETTING(messenger, "textScaleFactor", two); + called = FALSE; + fl_mock_binary_messenger_set_json_message_channel( + messenger, "flutter/settings", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_MAP); + FlValue* value = fl_value_lookup_string(message, "textScaleFactor"); + EXPECT_NE(value, nullptr); + EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_FLOAT); + EXPECT_EQ(fl_value_get_float(value), 2.0); + + return fl_value_new_null(); + }, + &called); fl_settings_emit_changed(settings); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } // MOCK_ENGINE_PROC is leaky by design diff --git a/engine/src/flutter/shell/platform/linux/fl_text_input_handler_test.cc b/engine/src/flutter/shell/platform/linux/fl_text_input_handler_test.cc index 7787b422c3..a124b236ff 100644 --- a/engine/src/flutter/shell/platform/linux/fl_text_input_handler_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_text_input_handler_test.cc @@ -4,14 +4,11 @@ #include +#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" #include "flutter/shell/platform/linux/fl_method_codec_private.h" #include "flutter/shell/platform/linux/fl_text_input_handler.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_method_codec.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" +#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h" #include "flutter/shell/platform/linux/testing/fl_test.h" -#include "flutter/shell/platform/linux/testing/mock_binary_messenger.h" -#include "flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.h" #include "flutter/shell/platform/linux/testing/mock_im_context.h" #include "flutter/shell/platform/linux/testing/mock_text_input_view_delegate.h" #include "flutter/testing/testing.h" @@ -19,83 +16,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -void printTo(FlMethodResponse* response, ::std::ostream* os) { - *os << ::testing::PrintToString( - fl_method_response_get_result(response, nullptr)); -} - -MATCHER_P(SuccessResponse, result, "") { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(FlMethodResponse) response = - fl_method_codec_decode_response(FL_METHOD_CODEC(codec), arg, nullptr); - if (fl_value_equal(fl_method_response_get_result(response, nullptr), - result)) { - return true; - } - *result_listener << ::testing::PrintToString(response); - return false; -} - -MATCHER_P(FlValueEq, value, "equal to " + ::testing::PrintToString(value)) { - return fl_value_equal(arg, value); -} - -class MethodCallMatcher { - public: - using is_gtest_matcher = void; - - explicit MethodCallMatcher(::testing::Matcher name, - ::testing::Matcher args) - : name_(std::move(name)), args_(std::move(args)) {} - - bool MatchAndExplain(GBytes* method_call, - ::testing::MatchResultListener* result_listener) const { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GError) error = nullptr; - g_autofree gchar* name = nullptr; - g_autoptr(FlValue) args = nullptr; - gboolean result = fl_method_codec_decode_method_call( - FL_METHOD_CODEC(codec), method_call, &name, &args, &error); - if (!result) { - *result_listener << ::testing::PrintToString(error->message); - return false; - } - if (!name_.MatchAndExplain(name, result_listener)) { - *result_listener << " where the name doesn't match: \"" << name << "\""; - return false; - } - if (!args_.MatchAndExplain(args, result_listener)) { - *result_listener << " where the args don't match: " - << ::testing::PrintToString(args); - return false; - } - return true; - } - - void DescribeTo(std::ostream* os) const { - *os << "method name "; - name_.DescribeTo(os); - *os << " and args "; - args_.DescribeTo(os); - } - - void DescribeNegationTo(std::ostream* os) const { - *os << "method name "; - name_.DescribeNegationTo(os); - *os << " or args "; - args_.DescribeNegationTo(os); - } - - private: - ::testing::Matcher name_; - ::testing::Matcher args_; -}; - -::testing::Matcher MethodCall(const std::string& name, - ::testing::Matcher args) { - return MethodCallMatcher(::testing::StrEq(name), std::move(args)); -} - static FlValue* build_map(std::map args) { FlValue* value = fl_value_new_map(); for (auto it = args.begin(); it != args.end(); ++it) { @@ -178,6 +98,49 @@ static FlValue* build_editing_delta(EditingDelta delta) { }); } +static void set_client(FlMockBinaryMessenger* messenger, InputConfig config) { + gboolean called = FALSE; + g_autoptr(FlValue) args = build_input_config(config); + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.setClient", args, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); +} + +static void set_editing_state(FlMockBinaryMessenger* messenger, + EditingState state) { + gboolean called = FALSE; + g_autoptr(FlValue) args = build_editing_state(state); + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.setEditingState", args, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); +} + static void send_key_event(FlTextInputHandler* handler, gint keyval, gint state = 0) { @@ -189,420 +152,391 @@ static void send_key_event(FlTextInputHandler* handler, } TEST(FlTextInputHandlerTest, MessageHandler) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - EXPECT_TRUE(messenger.HasMessageHandler("flutter/textinput")); + EXPECT_TRUE( + fl_mock_binary_messenger_has_handler(messenger, "flutter/textinput")); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, SetClient) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - g_autoptr(FlValue) args = build_input_config({.client_id = 1}); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", args, nullptr); + set_client(messenger, {.client_id = 1}); - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", message); + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, Show) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); EXPECT_CALL(context, gtk_im_context_focus_in(::testing::Eq(context))); - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.show", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.show", nullptr, nullptr); + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - messenger.ReceiveMessage("flutter/textinput", message); + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, Hide) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); EXPECT_CALL(context, gtk_im_context_focus_out(::testing::Eq(context))); - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.hide", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.hide", nullptr, nullptr); + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - messenger.ReceiveMessage("flutter/textinput", message); + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, ClearClient) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.clearClient", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.clearClient", nullptr, nullptr); + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - messenger.ReceiveMessage("flutter/textinput", message); + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, PerformAction) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - // set input config - g_autoptr(FlValue) config = build_input_config({ - .client_id = 1, - .input_type = "TextInputType.multiline", - .input_action = "TextInputAction.newline", - }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", config, nullptr); + set_client(messenger, { + .client_id = 1, + .input_type = "TextInputType.multiline", + .input_action = "TextInputAction.newline", + }); + set_editing_state(messenger, { + .text = "Flutter", + .selection_base = 7, + .selection_extent = 7, + }); - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + // Client will update editing state and perform action + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); - messenger.ReceiveMessage("flutter/textinput", set_client); + if (strcmp(name, "TextInputClient.updateEditingState") == 0) { + g_autoptr(FlValue) expected_args = build_list({ + fl_value_new_int(1), // client_id + build_editing_state({ + .text = "Flutter\n", + .selection_base = 8, + .selection_extent = 8, + }), + }); + EXPECT_TRUE(fl_value_equal(args, expected_args)); + EXPECT_EQ(*call_count, 0); + (*call_count)++; + } else if (strcmp(name, "TextInputClient.performAction") == 0) { + g_autoptr(FlValue) expected_args = build_list({ + fl_value_new_int(1), // client_id + fl_value_new_string("TextInputAction.newline"), + }); + EXPECT_TRUE(fl_value_equal(args, expected_args)); + EXPECT_EQ(*call_count, 1); + (*call_count)++; + } - // set editing state - g_autoptr(FlValue) state = build_editing_state({ - .text = "Flutter", - .selection_base = 7, - .selection_extent = 7, - }); - g_autoptr(GBytes) set_state = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditingState", state, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_state); - - // update editing state - g_autoptr(FlValue) new_state = build_list({ - fl_value_new_int(1), // client_id - build_editing_state({ - .text = "Flutter\n", - .selection_base = 8, - .selection_extent = 8, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(new_state)), - ::testing::_, ::testing::_, ::testing::_)); - - // perform action - g_autoptr(FlValue) action = build_list({ - fl_value_new_int(1), // client_id - fl_value_new_string("TextInputAction.newline"), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.performAction", - FlValueEq(action)), - ::testing::_, ::testing::_, ::testing::_)); + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); send_key_event(handler, GDK_KEY_Return); + EXPECT_EQ(call_count, 2); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } // Regression test for https://github.com/flutter/flutter/issues/125879. TEST(FlTextInputHandlerTest, MultilineWithSendAction) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - // Set input config. - g_autoptr(FlValue) config = build_input_config({ - .client_id = 1, - .input_type = "TextInputType.multiline", - .input_action = "TextInputAction.send", - }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", config, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); - - // Set editing state. - g_autoptr(FlValue) state = build_editing_state({ - .text = "Flutter", - .selection_base = 7, - .selection_extent = 7, - }); - g_autoptr(GBytes) set_state = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditingState", state, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_state); - - // Perform action. - g_autoptr(FlValue) action = build_list({ - fl_value_new_int(1), // client_id - fl_value_new_string("TextInputAction.send"), - }); + set_client(messenger, { + .client_id = 1, + .input_type = "TextInputType.multiline", + .input_action = "TextInputAction.send", + }); + set_editing_state(messenger, { + .text = "Flutter", + .selection_base = 7, + .selection_extent = 7, + }); // Because the input action is not set to TextInputAction.newline, the next // expected call is "TextInputClient.performAction". If the input action was // set to TextInputAction.newline the next call would be // "TextInputClient.updateEditingState" (this case is tested in the test named // 'PerformAction'). - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.performAction", - FlValueEq(action)), - ::testing::_, ::testing::_, ::testing::_)); + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); + + EXPECT_STREQ(name, "TextInputClient.performAction"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + // Perform action. + expected_args = build_list({ + fl_value_new_int(1), // client_id + fl_value_new_string("TextInputAction.send"), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; + + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); send_key_event(handler, GDK_KEY_Return); + EXPECT_EQ(call_count, 1); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, MoveCursor) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - // set input config - g_autoptr(FlValue) config = build_input_config({.client_id = 1}); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", config, nullptr); + set_client(messenger, {.client_id = 1}); + set_editing_state(messenger, { + .text = "Flutter", + .selection_base = 4, + .selection_extent = 4, + }); - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); - messenger.ReceiveMessage("flutter/textinput", set_client); + EXPECT_STREQ(name, "TextInputClient.updateEditingState"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + // move cursor to beginning + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_editing_state({ + .text = "Flutter", + .selection_base = 0, + .selection_extent = 0, + }), + }); + break; + case 1: + // move cursor to end + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_editing_state({ + .text = "Flutter", + .selection_base = 7, + .selection_extent = 7, + }), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; - // set editing state - g_autoptr(FlValue) state = build_editing_state({ - .text = "Flutter", - .selection_base = 4, - .selection_extent = 4, - }); - g_autoptr(GBytes) set_state = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditingState", state, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_state); - - // move cursor to beginning - g_autoptr(FlValue) beginning = build_list({ - fl_value_new_int(1), // client_id - build_editing_state({ - .text = "Flutter", - .selection_base = 0, - .selection_extent = 0, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(beginning)), - ::testing::_, ::testing::_, ::testing::_)); + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); send_key_event(handler, GDK_KEY_Home); - - // move cursor to end - g_autoptr(FlValue) end = build_list({ - fl_value_new_int(1), // client_id - build_editing_state({ - .text = "Flutter", - .selection_base = 7, - .selection_extent = 7, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(end)), - ::testing::_, ::testing::_, ::testing::_)); - send_key_event(handler, GDK_KEY_End); + EXPECT_EQ(call_count, 2); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, Select) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - // set input config - g_autoptr(FlValue) config = build_input_config({.client_id = 1}); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", config, nullptr); + set_client(messenger, {.client_id = 1}); + set_editing_state(messenger, { + .text = "Flutter", + .selection_base = 4, + .selection_extent = 4, + }); - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); - messenger.ReceiveMessage("flutter/textinput", set_client); + EXPECT_STREQ(name, "TextInputClient.updateEditingState"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + // select to end + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_editing_state({ + .text = "Flutter", + .selection_base = 4, + .selection_extent = 7, + }), + }); + break; + case 1: + // select to beginning + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_editing_state({ + .text = "Flutter", + .selection_base = 4, + .selection_extent = 0, + }), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; - // set editing state - g_autoptr(FlValue) state = build_editing_state({ - .text = "Flutter", - .selection_base = 4, - .selection_extent = 4, - }); - g_autoptr(GBytes) set_state = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditingState", state, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_state); - - // select to end - g_autoptr(FlValue) select_to_end = build_list({ - fl_value_new_int(1), // client_id - build_editing_state({ - .text = "Flutter", - .selection_base = 4, - .selection_extent = 7, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(select_to_end)), - ::testing::_, ::testing::_, ::testing::_)); + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); send_key_event(handler, GDK_KEY_End, GDK_SHIFT_MASK); - - // select to beginning - g_autoptr(FlValue) select_to_beginning = build_list({ - fl_value_new_int(1), // client_id - build_editing_state({ - .text = "Flutter", - .selection_base = 4, - .selection_extent = 0, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(select_to_beginning)), - ::testing::_, ::testing::_, ::testing::_)); - send_key_event(handler, GDK_KEY_Home, GDK_SHIFT_MASK); + EXPECT_EQ(call_count, 2); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, Composing) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - g_signal_emit_by_name(context, "preedit-start", nullptr); - // update EXPECT_CALL(context, gtk_im_context_get_preedit_string( @@ -612,94 +546,85 @@ TEST(FlTextInputHandlerTest, Composing) { ::testing::DoAll(::testing::SetArgPointee<1>(g_strdup("Flutter")), ::testing::SetArgPointee<3>(0))); - g_autoptr(FlValue) state = build_list({ - fl_value_new_int(-1), // client_id - build_editing_state({ - .text = "Flutter", - .selection_base = 0, - .selection_extent = 0, - .composing_base = 0, - .composing_extent = 7, - }), - }); + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(state)), - ::testing::_, ::testing::_, ::testing::_)); + EXPECT_STREQ(name, "TextInputClient.updateEditingState"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + expected_args = build_list({ + fl_value_new_int(-1), // client_id + build_editing_state({ + .text = "Flutter", + .selection_base = 0, + .selection_extent = 0, + .composing_base = 0, + .composing_extent = 7, + }), + }); + break; + case 1: + // commit + expected_args = build_list({ + fl_value_new_int(-1), // client_id + build_editing_state({ + .text = "engine", + .selection_base = 6, + .selection_extent = 6, + }), + }); + break; + case 2: + // end + expected_args = build_list({ + fl_value_new_int(-1), // client_id + build_editing_state({ + .text = "engine", + .selection_base = 6, + .selection_extent = 6, + }), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); + + g_signal_emit_by_name(context, "preedit-start", nullptr); g_signal_emit_by_name(context, "preedit-changed", nullptr); - - // commit - g_autoptr(FlValue) commit = build_list({ - fl_value_new_int(-1), // client_id - build_editing_state({ - .text = "engine", - .selection_base = 6, - .selection_extent = 6, - }), - }); - - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(commit)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "engine", nullptr); - - // end - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - ::testing::_), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "preedit-end", nullptr); + EXPECT_EQ(call_count, 3); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, SurroundingText) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - // set input config - g_autoptr(FlValue) config = build_input_config({.client_id = 1}); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", config, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); - - // set editing state - g_autoptr(FlValue) state = build_editing_state({ - .text = "Flutter", - .selection_base = 3, - .selection_extent = 3, - }); - g_autoptr(GBytes) set_state = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditingState", state, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_state); + set_client(messenger, {.client_id = 1}); + set_editing_state(messenger, { + .text = "Flutter", + .selection_base = 3, + .selection_extent = 3, + }); // retrieve EXPECT_CALL(context, gtk_im_context_set_surrounding( @@ -710,35 +635,53 @@ TEST(FlTextInputHandlerTest, SurroundingText) { g_signal_emit_by_name(context, "retrieve-surrounding", &retrieved, nullptr); EXPECT_TRUE(retrieved); - // delete - g_autoptr(FlValue) update = build_list({ - fl_value_new_int(1), // client_id - build_editing_state({ - .text = "Flutr", - .selection_base = 3, - .selection_extent = 3, - }), - }); + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingState", - FlValueEq(update)), - ::testing::_, ::testing::_, ::testing::_)); + EXPECT_STREQ(name, "TextInputClient.updateEditingState"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + // delete + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_editing_state({ + .text = "Flutr", + .selection_base = 3, + .selection_extent = 3, + }), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; + + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); gboolean deleted = false; g_signal_emit_by_name(context, "delete-surrounding", 1, 2, &deleted, nullptr); EXPECT_TRUE(deleted); + EXPECT_EQ(call_count, 1); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, SetMarkedTextRect) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); g_signal_emit_by_name(context, "preedit-start", nullptr); @@ -767,35 +710,24 @@ TEST(FlTextInputHandlerTest, SetMarkedTextRect) { }), }, }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_editable_size_and_transform = - fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditableSizeAndTransform", - size_and_transform, nullptr); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.setEditableSizeAndTransform", + size_and_transform, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - messenger.ReceiveMessage("flutter/textinput", - set_editable_size_and_transform); - - // set marked text rect - g_autoptr(FlValue) rect = build_map({ - {"x", fl_value_new_float(1)}, - {"y", fl_value_new_float(2)}, - {"width", fl_value_new_float(3)}, - {"height", fl_value_new_float(4)}, - }); - g_autoptr(GBytes) set_marked_text_rect = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setMarkedTextRect", rect, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); EXPECT_CALL(delegate, fl_text_input_view_delegate_translate_coordinates( ::testing::Eq(delegate), @@ -812,34 +744,47 @@ TEST(FlTextInputHandlerTest, SetMarkedTextRect) { ::testing::Field(&GdkRectangle::width, 0), ::testing::Field(&GdkRectangle::height, 0))))); - messenger.ReceiveMessage("flutter/textinput", set_marked_text_rect); + // set marked text rect + g_autoptr(FlValue) rect = build_map({ + {"x", fl_value_new_float(1)}, + {"y", fl_value_new_float(2)}, + {"width", fl_value_new_float(3)}, + {"height", fl_value_new_float(4)}, + }); + called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.setMarkedTextRect", rect, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, TextInputTypeNone) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - g_autoptr(FlValue) args = build_input_config({ - .client_id = 1, - .input_type = "TextInputType.none", - }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", args, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::A(), - SuccessResponse(null), ::testing::A())) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); + set_client(messenger, { + .client_id = 1, + .input_type = "TextInputType.none", + }); EXPECT_CALL(context, gtk_im_context_focus_in(::testing::Eq(context))) @@ -847,115 +792,106 @@ TEST(FlTextInputHandlerTest, TextInputTypeNone) { EXPECT_CALL(context, gtk_im_context_focus_out(::testing::Eq(context))); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); + gboolean called = FALSE; + fl_mock_binary_messenger_invoke_json_method( + messenger, "flutter/textinput", "TextInput.show", nullptr, + [](FlMockBinaryMessenger* messenger, FlMethodResponse* response, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; - g_autoptr(GBytes) show = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.show", nullptr, nullptr); + EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - messenger.ReceiveMessage("flutter/textinput", show); + g_autoptr(FlValue) expected_result = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + expected_result)); + }, + &called); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, TextEditingDelta) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); - // set config - g_autoptr(FlValue) args = build_input_config({ - .client_id = 1, - .enable_delta_model = true, - }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", args, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::A(), - SuccessResponse(null), ::testing::A())) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); - - // set editing state - g_autoptr(FlValue) state = build_editing_state({ - .text = "Flutter", - .selection_base = 7, - .selection_extent = 7, - }); - g_autoptr(GBytes) set_state = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setEditingState", state, nullptr); - - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::_, SuccessResponse(null), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_state); + set_client(messenger, { + .client_id = 1, + .enable_delta_model = true, + }); + set_editing_state(messenger, { + .text = "Flutter", + .selection_base = 7, + .selection_extent = 7, + }); // update editing state with deltas - g_autoptr(FlValue) deltas = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flutter", - .delta_text = "Flutter", - .delta_start = 7, - .delta_end = 7, - .selection_base = 0, - .selection_extent = 0, - }), - }), - }}), - }); + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(deltas)), - ::testing::_, ::testing::_, ::testing::_)); + EXPECT_STREQ(name, "TextInputClient.updateEditingStateWithDeltas"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flutter", + .delta_text = "Flutter", + .delta_start = 7, + .delta_end = 7, + .selection_base = 0, + .selection_extent = 0, + }), + }), + }}), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; + + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); send_key_event(handler, GDK_KEY_Home); + EXPECT_EQ(call_count, 1); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, ComposingDelta) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); // set config - g_autoptr(FlValue) args = build_input_config({ - .client_id = 1, - .enable_delta_model = true, - }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", args, nullptr); - - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::A(), - SuccessResponse(null), ::testing::A())) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage("flutter/textinput", set_client); + set_client(messenger, { + .client_id = 1, + .enable_delta_model = true, + }); g_signal_emit_by_name(context, "preedit-start", nullptr); @@ -968,325 +904,283 @@ TEST(FlTextInputHandlerTest, ComposingDelta) { ::testing::DoAll(::testing::SetArgPointee<1>(g_strdup("Flutter ")), ::testing::SetArgPointee<3>(8))); - g_autoptr(FlValue) update = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "", - .delta_text = "Flutter ", - .delta_start = 0, - .delta_end = 0, - .selection_base = 8, - .selection_extent = 8, - .composing_base = 0, - .composing_extent = 8, - }), - }), - }}), - }); + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(update)), - ::testing::_, ::testing::_, ::testing::_)); + EXPECT_STREQ(name, "TextInputClient.updateEditingStateWithDeltas"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "", + .delta_text = "Flutter ", + .delta_start = 0, + .delta_end = 0, + .selection_base = 8, + .selection_extent = 8, + .composing_base = 0, + .composing_extent = 8, + }), + }), + }}), + }); + break; + case 1: + // commit + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flutter ", + .delta_text = "Flutter engine", + .delta_start = 0, + .delta_end = 8, + .selection_base = 14, + .selection_extent = 14, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 2: + // end + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flutter engine", + .selection_base = 14, + .selection_extent = 14, + }), + }), + }}), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; + + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); g_signal_emit_by_name(context, "preedit-changed", nullptr); - - // commit - g_autoptr(FlValue) commit = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flutter ", - .delta_text = "Flutter engine", - .delta_start = 0, - .delta_end = 8, - .selection_base = 14, - .selection_extent = 14, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commit)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "Flutter engine", nullptr); - - // end - g_autoptr(FlValue) end = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flutter engine", - .selection_base = 14, - .selection_extent = 14, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(end)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "preedit-end", nullptr); + EXPECT_EQ(call_count, 3); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlTextInputHandlerTest, NonComposingDelta) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock context; ::testing::NiceMock delegate; - g_autoptr(FlTextInputHandler) handler = - fl_text_input_handler_new(messenger, context, delegate); + g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new( + FL_BINARY_MESSENGER(messenger), context, delegate); EXPECT_NE(handler, nullptr); // set config - g_autoptr(FlValue) args = build_input_config({ - .client_id = 1, - .enable_delta_model = true, - }); - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) set_client = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), "TextInput.setClient", args, nullptr); + set_client(messenger, { + .client_id = 1, + .enable_delta_model = true, + }); - g_autoptr(FlValue) null = fl_value_new_null(); - EXPECT_CALL(messenger, fl_binary_messenger_send_response( - ::testing::Eq(messenger), - ::testing::A(), - SuccessResponse(null), ::testing::A())) - .WillOnce(::testing::Return(true)); + int call_count = 0; + fl_mock_binary_messenger_set_json_method_channel( + messenger, "flutter/textinput", + [](FlMockBinaryMessenger* messenger, const gchar* name, FlValue* args, + gpointer user_data) { + int* call_count = static_cast(user_data); - messenger.ReceiveMessage("flutter/textinput", set_client); + EXPECT_STREQ(name, "TextInputClient.updateEditingStateWithDeltas"); + g_autoptr(FlValue) expected_args = nullptr; + switch (*call_count) { + case 0: + // commit F + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "", + .delta_text = "F", + .delta_start = 0, + .delta_end = 0, + .selection_base = 1, + .selection_extent = 1, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 1: + // commit l + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "F", + .delta_text = "l", + .delta_start = 1, + .delta_end = 1, + .selection_base = 2, + .selection_extent = 2, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 2: + // commit u + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Fl", + .delta_text = "u", + .delta_start = 2, + .delta_end = 2, + .selection_base = 3, + .selection_extent = 3, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 3: + // commit t + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flu", + .delta_text = "t", + .delta_start = 3, + .delta_end = 3, + .selection_base = 4, + .selection_extent = 4, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 4: + // commit t again + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flut", + .delta_text = "t", + .delta_start = 4, + .delta_end = 4, + .selection_base = 5, + .selection_extent = 5, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 5: + // commit e + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flutt", + .delta_text = "e", + .delta_start = 5, + .delta_end = 5, + .selection_base = 6, + .selection_extent = 6, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + case 6: + // commit r + expected_args = build_list({ + fl_value_new_int(1), // client_id + build_map({{ + "deltas", + build_list({ + build_editing_delta({ + .old_text = "Flutte", + .delta_text = "r", + .delta_start = 6, + .delta_end = 6, + .selection_base = 7, + .selection_extent = 7, + .composing_base = -1, + .composing_extent = -1, + }), + }), + }}), + }); + break; + default: + g_assert_not_reached(); + break; + } + EXPECT_TRUE(fl_value_equal(args, expected_args)); + (*call_count)++; - // commit F - g_autoptr(FlValue) commit = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "", - .delta_text = "F", - .delta_start = 0, - .delta_end = 0, - .selection_base = 1, - .selection_extent = 1, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commit)), - ::testing::_, ::testing::_, ::testing::_)); + return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); + }, + &call_count); g_signal_emit_by_name(context, "commit", "F", nullptr); - - // commit l - g_autoptr(FlValue) commitL = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "F", - .delta_text = "l", - .delta_start = 1, - .delta_end = 1, - .selection_base = 2, - .selection_extent = 2, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commitL)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "l", nullptr); - - // commit u - g_autoptr(FlValue) commitU = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Fl", - .delta_text = "u", - .delta_start = 2, - .delta_end = 2, - .selection_base = 3, - .selection_extent = 3, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commitU)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "u", nullptr); - - // commit t - g_autoptr(FlValue) commitTa = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flu", - .delta_text = "t", - .delta_start = 3, - .delta_end = 3, - .selection_base = 4, - .selection_extent = 4, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commitTa)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "t", nullptr); - - // commit t again - g_autoptr(FlValue) commitTb = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flut", - .delta_text = "t", - .delta_start = 4, - .delta_end = 4, - .selection_base = 5, - .selection_extent = 5, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commitTb)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "t", nullptr); - - // commit e - g_autoptr(FlValue) commitE = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flutt", - .delta_text = "e", - .delta_start = 5, - .delta_end = 5, - .selection_base = 6, - .selection_extent = 6, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commitE)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "e", nullptr); - - // commit r - g_autoptr(FlValue) commitR = build_list({ - fl_value_new_int(1), // client_id - build_map({{ - "deltas", - build_list({ - build_editing_delta({ - .old_text = "Flutte", - .delta_text = "r", - .delta_start = 6, - .delta_end = 6, - .selection_base = 7, - .selection_extent = 7, - .composing_base = -1, - .composing_extent = -1, - }), - }), - }}), - }); - - EXPECT_CALL(messenger, - fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/textinput"), - MethodCall("TextInputClient.updateEditingStateWithDeltas", - FlValueEq(commitR)), - ::testing::_, ::testing::_, ::testing::_)); - g_signal_emit_by_name(context, "commit", "r", nullptr); + EXPECT_EQ(call_count, 7); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } diff --git a/engine/src/flutter/shell/platform/linux/fl_window_state_monitor_test.cc b/engine/src/flutter/shell/platform/linux/fl_window_state_monitor_test.cc index f88450741e..8aa6588d44 100644 --- a/engine/src/flutter/shell/platform/linux/fl_window_state_monitor_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_window_state_monitor_test.cc @@ -3,254 +3,287 @@ // found in the LICENSE file. #include "flutter/shell/platform/linux/fl_window_state_monitor.h" +#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_string_codec.h" -#include "flutter/shell/platform/linux/testing/fl_test.h" -#include "flutter/shell/platform/linux/testing/mock_binary_messenger.h" +#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h" #include "flutter/shell/platform/linux/testing/mock_window.h" #include "gtest/gtest.h" -// Matches if a FlValue is a the supplied string. -class FlValueStringMatcher { - public: - using is_gtest_matcher = void; - - explicit FlValueStringMatcher(::testing::Matcher value) - : value_(std::move(value)) {} - - bool MatchAndExplain(GBytes* data, - ::testing::MatchResultListener* result_listener) const { - g_autoptr(FlStringCodec) codec = fl_string_codec_new(); - g_autoptr(GError) error = nullptr; - g_autoptr(FlValue) value = - fl_message_codec_decode_message(FL_MESSAGE_CODEC(codec), data, &error); - if (value == nullptr) { - *result_listener << ::testing::PrintToString(error->message); - return false; - } - if (!value_.MatchAndExplain(fl_value_get_string(value), result_listener)) { - *result_listener << " where the value doesn't match: \"" << value << "\""; - return false; - } - return true; - } - - void DescribeTo(std::ostream* os) const { - *os << "value "; - value_.DescribeTo(os); - } - - void DescribeNegationTo(std::ostream* os) const { - *os << "value "; - value_.DescribeNegationTo(os); - } - - private: - ::testing::Matcher value_; -}; - -::testing::Matcher LifecycleString(const std::string& value) { - return FlValueStringMatcher(::testing::StrEq(value)); -} - TEST(FlWindowStateMonitorTest, GainFocus) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(static_cast(0))); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.resumed"), - ::testing::_, ::testing::_, ::testing::_)); + + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), "AppLifecycleState.resumed"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = GDK_WINDOW_STATE_FOCUSED}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, LoseFocus) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(GDK_WINDOW_STATE_FOCUSED)); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.inactive"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), + "AppLifecycleState.inactive"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = static_cast(0)}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, EnterIconified) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(static_cast(0))); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.hidden"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), "AppLifecycleState.hidden"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = GDK_WINDOW_STATE_ICONIFIED}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, LeaveIconified) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(GDK_WINDOW_STATE_ICONIFIED)); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.inactive"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), + "AppLifecycleState.inactive"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = static_cast(0)}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, LeaveIconifiedFocused) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(GDK_WINDOW_STATE_ICONIFIED)); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.resumed"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), "AppLifecycleState.resumed"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = static_cast( GDK_WINDOW_STATE_FOCUSED)}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, EnterWithdrawn) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(static_cast(0))); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.hidden"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), "AppLifecycleState.hidden"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = GDK_WINDOW_STATE_WITHDRAWN}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, LeaveWithdrawn) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(GDK_WINDOW_STATE_WITHDRAWN)); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.inactive"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), + "AppLifecycleState.inactive"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = static_cast(0)}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } TEST(FlWindowStateMonitorTest, LeaveWithdrawnFocused) { - ::testing::NiceMock messenger; + g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new(); ::testing::NiceMock mock_window; gtk_init(0, nullptr); EXPECT_CALL(mock_window, gdk_window_get_state) .WillOnce(::testing::Return(GDK_WINDOW_STATE_WITHDRAWN)); - EXPECT_CALL(messenger, fl_binary_messenger_send_on_channel( - ::testing::Eq(messenger), - ::testing::StrEq("flutter/lifecycle"), - LifecycleString("AppLifecycleState.resumed"), - ::testing::_, ::testing::_, ::testing::_)); + gboolean called = TRUE; + fl_mock_binary_messenger_set_string_message_channel( + messenger, "flutter/lifecycle", + [](FlMockBinaryMessenger* messenger, FlValue* message, + gpointer user_data) { + gboolean* called = static_cast(user_data); + *called = TRUE; + EXPECT_STREQ(fl_value_get_string(message), "AppLifecycleState.resumed"); + return fl_value_new_string(""); + }, + &called); GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlWindowStateMonitor) monitor = - fl_window_state_monitor_new(messenger, window); + fl_window_state_monitor_new(FL_BINARY_MESSENGER(messenger), window); GdkEvent event = { .window_state = {.new_window_state = static_cast( GDK_WINDOW_STATE_FOCUSED)}}; gboolean handled; g_signal_emit_by_name(window, "window-state-event", &event, &handled); + EXPECT_TRUE(called); + + fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger)); } diff --git a/engine/src/flutter/shell/platform/linux/testing/fl_mock_binary_messenger.cc b/engine/src/flutter/shell/platform/linux/testing/fl_mock_binary_messenger.cc new file mode 100644 index 0000000000..e26f9bcfcb --- /dev/null +++ b/engine/src/flutter/shell/platform/linux/testing/fl_mock_binary_messenger.cc @@ -0,0 +1,609 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h" + +#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" +#include "flutter/shell/platform/linux/fl_method_codec_private.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_method_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_string_codec.h" + +G_DECLARE_FINAL_TYPE(FlMockBinaryMessengerResponseHandle, + fl_mock_binary_messenger_response_handle, + FL, + MOCK_BINARY_MESSENGER_RESPONSE_HANDLE, + FlBinaryMessengerResponseHandle) + +struct _FlMockBinaryMessengerResponseHandle { + FlBinaryMessengerResponseHandle parent_instance; + + FlMockBinaryMessengerCallback callback; + gpointer user_data; +}; + +G_DEFINE_TYPE(FlMockBinaryMessengerResponseHandle, + fl_mock_binary_messenger_response_handle, + fl_binary_messenger_response_handle_get_type()) + +static void fl_mock_binary_messenger_response_handle_class_init( + FlMockBinaryMessengerResponseHandleClass* klass) {} + +static void fl_mock_binary_messenger_response_handle_init( + FlMockBinaryMessengerResponseHandle* self) {} + +FlMockBinaryMessengerResponseHandle* +fl_mock_binary_messenger_response_handle_new( + FlMockBinaryMessengerCallback callback, + gpointer user_data) { + FlMockBinaryMessengerResponseHandle* self = + FL_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE(g_object_new( + fl_mock_binary_messenger_response_handle_get_type(), nullptr)); + self->callback = callback; + self->user_data = user_data; + return self; +} + +struct _FlMockBinaryMessenger { + GObject parent_instance; + + // Handlers the embedder has registered. + GHashTable* handlers; + + // Mocked Dart channels. + GHashTable* mock_channels; + GHashTable* mock_message_channels; + GHashTable* mock_method_channels; +}; + +typedef struct { + FlMockBinaryMessengerChannelHandler callback; + gpointer user_data; +} MockChannel; + +static MockChannel* mock_channel_new( + FlMockBinaryMessengerChannelHandler callback, + gpointer user_data) { + MockChannel* channel = g_new0(MockChannel, 1); + channel->callback = callback; + channel->user_data = user_data; + return channel; +} + +static void mock_channel_free(MockChannel* channel) { + g_free(channel); +} + +typedef struct { + FlMessageCodec* codec; + FlMockBinaryMessengerMessageChannelHandler callback; + gpointer user_data; +} MockMessageChannel; + +static MockMessageChannel* mock_message_channel_new( + FlMockBinaryMessengerMessageChannelHandler callback, + FlMessageCodec* codec, + gpointer user_data) { + MockMessageChannel* channel = g_new0(MockMessageChannel, 1); + channel->codec = FL_MESSAGE_CODEC(g_object_ref(codec)); + channel->callback = callback; + channel->user_data = user_data; + return channel; +} + +static void mock_message_channel_free(MockMessageChannel* channel) { + g_object_unref(channel->codec); + g_free(channel); +} + +typedef struct { + FlMethodCodec* codec; + FlMockBinaryMessengerMethodChannelHandler callback; + gpointer user_data; +} MockMethodChannel; + +static MockMethodChannel* mock_method_channel_new( + FlMockBinaryMessengerMethodChannelHandler callback, + FlMethodCodec* codec, + gpointer user_data) { + MockMethodChannel* channel = g_new0(MockMethodChannel, 1); + channel->codec = FL_METHOD_CODEC(g_object_ref(codec)); + channel->callback = callback; + channel->user_data = user_data; + return channel; +} + +static void mock_method_channel_free(MockMethodChannel* channel) { + g_object_unref(channel->codec); + g_free(channel); +} + +typedef struct { + FlBinaryMessengerMessageHandler callback; + gpointer user_data; + GDestroyNotify destroy_notify; +} Handler; + +static Handler* handler_new(FlBinaryMessengerMessageHandler callback, + gpointer user_data, + GDestroyNotify destroy_notify) { + Handler* handler = g_new0(Handler, 1); + handler->callback = callback; + handler->user_data = user_data; + handler->destroy_notify = destroy_notify; + return handler; +} + +static void handler_free(Handler* handler) { + if (handler->destroy_notify) { + handler->destroy_notify(handler->user_data); + } + g_free(handler); +} + +static void fl_mock_binary_messenger_iface_init( + FlBinaryMessengerInterface* iface); + +G_DEFINE_TYPE_WITH_CODE( + FlMockBinaryMessenger, + fl_mock_binary_messenger, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(fl_binary_messenger_get_type(), + fl_mock_binary_messenger_iface_init)) + +static void fl_mock_binary_messenger_set_message_handler_on_channel( + FlBinaryMessenger* messenger, + const gchar* channel, + FlBinaryMessengerMessageHandler handler, + gpointer user_data, + GDestroyNotify destroy_notify) { + FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); + g_hash_table_insert(self->handlers, g_strdup(channel), + handler_new(handler, user_data, destroy_notify)); +} + +static gboolean fl_mock_binary_messenger_send_response( + FlBinaryMessenger* messenger, + FlBinaryMessengerResponseHandle* response_handle, + GBytes* response, + GError** error) { + FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); + + g_return_val_if_fail( + FL_IS_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle), FALSE); + FlMockBinaryMessengerResponseHandle* handle = + FL_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle); + + handle->callback(self, response, handle->user_data); + + return TRUE; +} + +static void fl_mock_binary_messenger_send_on_channel( + FlBinaryMessenger* messenger, + const gchar* channel, + GBytes* message, + GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); + g_autoptr(GTask) task = g_task_new(self, cancellable, callback, user_data); + + MockChannel* mock_channel = static_cast( + g_hash_table_lookup(self->mock_channels, channel)); + MockMessageChannel* mock_message_channel = static_cast( + g_hash_table_lookup(self->mock_message_channels, channel)); + MockMethodChannel* mock_method_channel = static_cast( + g_hash_table_lookup(self->mock_method_channels, channel)); + g_autoptr(GBytes) response = nullptr; + if (mock_channel != nullptr) { + response = mock_channel->callback(self, message, mock_channel->user_data); + } else if (mock_message_channel != nullptr) { + g_autoptr(GError) error = nullptr; + g_autoptr(FlValue) message_value = fl_message_codec_decode_message( + mock_message_channel->codec, message, &error); + if (message_value == nullptr) { + g_warning("Failed to decode message: %s", error->message); + } else { + g_autoptr(FlValue) response_value = mock_message_channel->callback( + self, message_value, mock_message_channel->user_data); + response = fl_message_codec_encode_message(mock_message_channel->codec, + response_value, &error); + if (response == nullptr) { + g_warning("Failed to encode message: %s", error->message); + } + } + } else if (mock_method_channel != nullptr) { + g_autofree gchar* name = nullptr; + g_autoptr(FlValue) args = nullptr; + g_autoptr(GError) error = nullptr; + if (!fl_method_codec_decode_method_call(mock_method_channel->codec, message, + &name, &args, &error)) { + g_warning("Failed to decode method call: %s", error->message); + } else { + g_autoptr(FlMethodResponse) response_value = + mock_method_channel->callback(self, name, args, + mock_method_channel->user_data); + response = fl_method_codec_encode_response(mock_method_channel->codec, + response_value, &error); + if (response == nullptr) { + g_warning("Failed to encode method response: %s", error->message); + } + } + } + + if (response == nullptr) { + response = g_bytes_new(nullptr, 0); + } + + g_task_return_pointer(task, g_bytes_ref(response), + reinterpret_cast(g_bytes_unref)); +} + +static GBytes* fl_mock_binary_messenger_send_on_channel_finish( + FlBinaryMessenger* messenger, + GAsyncResult* result, + GError** error) { + return static_cast(g_task_propagate_pointer(G_TASK(result), error)); +} + +static void fl_mock_binary_messenger_resize_channel( + FlBinaryMessenger* messenger, + const gchar* channel, + int64_t new_size) {} + +static void fl_mock_binary_messenger_set_warns_on_channel_overflow( + FlBinaryMessenger* messenger, + const gchar* channel, + bool warns) {} + +static void fl_mock_binary_messenger_shutdown(FlBinaryMessenger* messenger) { + FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); + g_hash_table_remove_all(self->handlers); +} + +static void fl_mock_binary_messenger_dispose(GObject* object) { + FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(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_OBJECT_CLASS(fl_mock_binary_messenger_parent_class)->dispose(object); +} + +static void fl_mock_binary_messenger_class_init( + FlMockBinaryMessengerClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_mock_binary_messenger_dispose; +} + +static void fl_mock_binary_messenger_iface_init( + FlBinaryMessengerInterface* iface) { + iface->set_message_handler_on_channel = + fl_mock_binary_messenger_set_message_handler_on_channel; + iface->send_response = fl_mock_binary_messenger_send_response; + iface->send_on_channel = fl_mock_binary_messenger_send_on_channel; + iface->send_on_channel_finish = + fl_mock_binary_messenger_send_on_channel_finish; + iface->resize_channel = fl_mock_binary_messenger_resize_channel; + iface->set_warns_on_channel_overflow = + fl_mock_binary_messenger_set_warns_on_channel_overflow; + iface->shutdown = fl_mock_binary_messenger_shutdown; +} + +static void fl_mock_binary_messenger_init(FlMockBinaryMessenger* self) { + self->handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)handler_free); + + self->mock_channels = g_hash_table_new_full( + g_str_hash, g_str_equal, g_free, (GDestroyNotify)mock_channel_free); + self->mock_message_channels = + g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)mock_message_channel_free); + self->mock_method_channels = + g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)mock_method_channel_free); +} + +FlMockBinaryMessenger* fl_mock_binary_messenger_new() { + FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER( + g_object_new(fl_mock_binary_messenger_get_type(), nullptr)); + return self; +} + +gboolean fl_mock_binary_messenger_has_handler(FlMockBinaryMessenger* self, + const gchar* channel) { + g_return_val_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self), FALSE); + return g_hash_table_lookup(self->handlers, channel) != nullptr; +} + +void fl_mock_binary_messenger_set_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_hash_table_insert(self->mock_channels, g_strdup(channel), + mock_channel_new(handler, user_data)); +} + +void fl_mock_binary_messenger_set_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMessageCodec* codec, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_hash_table_insert(self->mock_message_channels, g_strdup(channel), + mock_message_channel_new(handler, codec, user_data)); +} + +void fl_mock_binary_messenger_set_standard_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new(); + return fl_mock_binary_messenger_set_message_channel( + self, channel, FL_MESSAGE_CODEC(codec), handler, user_data); +} + +void fl_mock_binary_messenger_set_string_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_autoptr(FlStringCodec) codec = fl_string_codec_new(); + return fl_mock_binary_messenger_set_message_channel( + self, channel, FL_MESSAGE_CODEC(codec), handler, user_data); +} + +void fl_mock_binary_messenger_set_json_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); + return fl_mock_binary_messenger_set_message_channel( + self, channel, FL_MESSAGE_CODEC(codec), handler, user_data); +} + +void fl_mock_binary_messenger_set_method_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMethodCodec* codec, + FlMockBinaryMessengerMethodChannelHandler handler, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_hash_table_insert(self->mock_method_channels, g_strdup(channel), + mock_method_channel_new(handler, codec, user_data)); +} + +void fl_mock_binary_messenger_set_standard_method_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMethodChannelHandler 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_method_channel( + self, channel, FL_METHOD_CODEC(codec), handler, user_data); +} + +void fl_mock_binary_messenger_set_json_method_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMethodChannelHandler 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_method_channel( + self, channel, FL_METHOD_CODEC(codec), handler, user_data); +} + +void fl_mock_binary_messenger_send(FlMockBinaryMessenger* self, + const gchar* channel, + GBytes* message, + FlMockBinaryMessengerCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + Handler* handler = + static_cast(g_hash_table_lookup(self->handlers, channel)); + if (handler == nullptr) { + return; + } + + handler->callback( + FL_BINARY_MESSENGER(self), channel, message, + FL_BINARY_MESSENGER_RESPONSE_HANDLE( + fl_mock_binary_messenger_response_handle_new(callback, user_data)), + handler->user_data); +} + +typedef struct { + FlMessageCodec* codec; + FlMockBinaryMessengerMessageCallback callback; + gpointer user_data; +} SendMessageData; + +static SendMessageData* send_message_data_new( + FlMessageCodec* codec, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data) { + SendMessageData* data = g_new0(SendMessageData, 1); + data->codec = FL_MESSAGE_CODEC(g_object_ref(codec)); + data->callback = callback; + data->user_data = user_data; + return data; +} + +static void send_message_data_free(SendMessageData* data) { + g_object_unref(data->codec); + free(data); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(SendMessageData, send_message_data_free) + +static void send_message_cb(FlMockBinaryMessenger* self, + GBytes* response, + gpointer user_data) { + g_autoptr(SendMessageData) data = static_cast(user_data); + + g_autoptr(GError) error = nullptr; + g_autoptr(FlValue) response_value = + fl_message_codec_decode_message(data->codec, response, &error); + if (response_value == nullptr) { + g_warning("Failed to decode message response: %s", error->message); + return; + } + + data->callback(self, response_value, data->user_data); +} + +void fl_mock_binary_messenger_send_message( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMessageCodec* codec, + FlValue* message, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_autoptr(GError) error = nullptr; + g_autoptr(GBytes) encoded_message = + fl_message_codec_encode_message(codec, message, &error); + if (encoded_message == nullptr) { + g_warning("Failed to encode message: %s", error->message); + return; + } + + fl_mock_binary_messenger_send( + self, channel, encoded_message, send_message_cb, + send_message_data_new(codec, callback, user_data)); +} + +void fl_mock_binary_messenger_send_standard_message( + FlMockBinaryMessenger* self, + const gchar* channel, + FlValue* message, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new(); + fl_mock_binary_messenger_send_message(self, channel, FL_MESSAGE_CODEC(codec), + message, callback, user_data); +} + +void fl_mock_binary_messenger_send_json_message( + FlMockBinaryMessenger* self, + const gchar* channel, + FlValue* message, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); + fl_mock_binary_messenger_send_message(self, channel, FL_MESSAGE_CODEC(codec), + message, callback, user_data); +} + +typedef struct { + FlMethodCodec* codec; + FlMockBinaryMessengerMethodCallback callback; + gpointer user_data; +} InvokeMethodData; + +static InvokeMethodData* invoke_method_data_new( + FlMethodCodec* codec, + FlMockBinaryMessengerMethodCallback callback, + gpointer user_data) { + InvokeMethodData* data = g_new0(InvokeMethodData, 1); + data->codec = FL_METHOD_CODEC(g_object_ref(codec)); + data->callback = callback; + data->user_data = user_data; + return data; +} + +static void invoke_method_data_free(InvokeMethodData* data) { + g_object_unref(data->codec); + free(data); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(InvokeMethodData, invoke_method_data_free) + +static void invoke_method_cb(FlMockBinaryMessenger* self, + GBytes* response, + gpointer user_data) { + g_autoptr(InvokeMethodData) data = static_cast(user_data); + + g_autoptr(GError) error = nullptr; + g_autoptr(FlMethodResponse) method_response = + fl_method_codec_decode_response(data->codec, response, &error); + if (method_response == nullptr) { + g_warning("Failed to decode method response: %s", error->message); + return; + } + + data->callback(self, method_response, data->user_data); +} + +void fl_mock_binary_messenger_invoke_method( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMethodCodec* codec, + const char* name, + FlValue* args, + FlMockBinaryMessengerMethodCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(self)); + + g_autoptr(GError) error = nullptr; + g_autoptr(GBytes) message = + fl_method_codec_encode_method_call(codec, name, args, &error); + if (message == nullptr) { + g_warning("Failed to encode method call: %s", error->message); + return; + } + + fl_mock_binary_messenger_send( + self, channel, message, invoke_method_cb, + invoke_method_data_new(codec, callback, user_data)); +} + +void fl_mock_binary_messenger_invoke_standard_method( + FlMockBinaryMessenger* self, + const gchar* channel, + const char* name, + FlValue* args, + FlMockBinaryMessengerMethodCallback callback, + 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_invoke_method(self, channel, FL_METHOD_CODEC(codec), + name, args, callback, user_data); +} + +void fl_mock_binary_messenger_invoke_json_method( + FlMockBinaryMessenger* self, + const gchar* channel, + const char* name, + FlValue* args, + FlMockBinaryMessengerMethodCallback callback, + 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_invoke_method(self, channel, FL_METHOD_CODEC(codec), + name, args, callback, user_data); +} diff --git a/engine/src/flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h b/engine/src/flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h new file mode 100644 index 0000000000..ab6276e291 --- /dev/null +++ b/engine/src/flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h @@ -0,0 +1,160 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_TESTING_FL_MOCK_BINARY_MESSENGER_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_TESTING_FL_MOCK_BINARY_MESSENGER_H_ + +#include "flutter/shell/platform/linux/public/flutter_linux/fl_message_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlMockBinaryMessenger, + fl_mock_binary_messenger, + FL, + MOCK_BINARY_MESSENGER, + GObject) + +typedef GBytes* (*FlMockBinaryMessengerChannelHandler)( + FlMockBinaryMessenger* messenger, + GBytes* message, + gpointer user_data); + +typedef FlValue* (*FlMockBinaryMessengerMessageChannelHandler)( + FlMockBinaryMessenger* messenger, + FlValue* message, + gpointer user_data); + +typedef FlMethodResponse* (*FlMockBinaryMessengerMethodChannelHandler)( + FlMockBinaryMessenger* messenger, + const gchar* name, + FlValue* args, + gpointer user_data); + +typedef void (*FlMockBinaryMessengerCallback)(FlMockBinaryMessenger* messenger, + GBytes* response, + gpointer user_data); + +typedef void (*FlMockBinaryMessengerMessageCallback)( + FlMockBinaryMessenger* messenger, + FlValue* response, + gpointer user_data); + +typedef void (*FlMockBinaryMessengerMethodCallback)( + FlMockBinaryMessenger* messenger, + FlMethodResponse* response, + gpointer user_data); + +FlMockBinaryMessenger* fl_mock_binary_messenger_new(); + +gboolean fl_mock_binary_messenger_has_handler(FlMockBinaryMessenger* self, + const gchar* channel); + +void fl_mock_binary_messenger_set_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMessageCodec* codec, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_standard_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_string_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_json_message_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMessageChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_method_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMethodCodec* codec, + FlMockBinaryMessengerMethodChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_standard_method_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMethodChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_set_json_method_channel( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMockBinaryMessengerMethodChannelHandler handler, + gpointer user_data); + +void fl_mock_binary_messenger_send(FlMockBinaryMessenger* self, + const gchar* channel, + GBytes* message, + FlMockBinaryMessengerCallback callback, + gpointer user_data); + +void fl_mock_binary_messenger_send_message( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMessageCodec* codec, + FlValue* message, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data); + +void fl_mock_binary_messenger_send_standard_message( + FlMockBinaryMessenger* self, + const gchar* channel, + FlValue* message, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data); + +void fl_mock_binary_messenger_send_json_message( + FlMockBinaryMessenger* self, + const gchar* channel, + FlValue* message, + FlMockBinaryMessengerMessageCallback callback, + gpointer user_data); + +void fl_mock_binary_messenger_invoke_method( + FlMockBinaryMessenger* self, + const gchar* channel, + FlMethodCodec* codec, + const char* name, + FlValue* args, + FlMockBinaryMessengerMethodCallback callback, + gpointer user_data); + +void fl_mock_binary_messenger_invoke_standard_method( + FlMockBinaryMessenger* self, + const gchar* channel, + const char* name, + FlValue* args, + FlMockBinaryMessengerMethodCallback callback, + gpointer user_data); + +void fl_mock_binary_messenger_invoke_json_method( + FlMockBinaryMessenger* self, + const gchar* channel, + const char* name, + FlValue* args, + FlMockBinaryMessengerMethodCallback callback, + gpointer user_data); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_TESTING_FL_MOCK_BINARY_MESSENGER_H_ diff --git a/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger.cc b/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger.cc deleted file mode 100644 index 8b22f2291b..0000000000 --- a/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger.cc +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter/shell/platform/linux/testing/mock_binary_messenger.h" -#include "flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.h" - -using namespace flutter::testing; - -G_DECLARE_FINAL_TYPE(FlMockBinaryMessenger, - fl_mock_binary_messenger, - FL, - MOCK_BINARY_MESSENGER, - GObject) - -struct _FlMockBinaryMessenger { - GObject parent_instance; - MockBinaryMessenger* mock; -}; - -static FlBinaryMessenger* fl_mock_binary_messenger_new( - MockBinaryMessenger* mock) { - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER( - g_object_new(fl_mock_binary_messenger_get_type(), nullptr)); - self->mock = mock; - return FL_BINARY_MESSENGER(self); -} - -MockBinaryMessenger::MockBinaryMessenger() - : instance_(fl_mock_binary_messenger_new(this)) {} - -MockBinaryMessenger::~MockBinaryMessenger() { - if (FL_IS_BINARY_MESSENGER(instance_)) { - g_clear_object(&instance_); - } -} - -MockBinaryMessenger::operator FlBinaryMessenger*() { - return instance_; -} - -bool MockBinaryMessenger::HasMessageHandler(const gchar* channel) const { - return message_handlers_.at(channel) != nullptr; -} - -void MockBinaryMessenger::SetMessageHandler( - const gchar* channel, - FlBinaryMessengerMessageHandler handler, - gpointer user_data) { - message_handlers_[channel] = handler; - user_datas_[channel] = user_data; -} - -void MockBinaryMessenger::ReceiveMessage(const gchar* channel, - GBytes* message) { - FlBinaryMessengerMessageHandler handler = message_handlers_[channel]; - if (response_handles_[channel] == nullptr) { - response_handles_[channel] = FL_BINARY_MESSENGER_RESPONSE_HANDLE( - fl_mock_binary_messenger_response_handle_new()); - } - handler(instance_, channel, message, response_handles_[channel], - user_datas_[channel]); -} - -static void fl_mock_binary_messenger_iface_init( - FlBinaryMessengerInterface* iface); - -G_DEFINE_TYPE_WITH_CODE( - FlMockBinaryMessenger, - fl_mock_binary_messenger, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(fl_binary_messenger_get_type(), - fl_mock_binary_messenger_iface_init)) - -static void fl_mock_binary_messenger_class_init( - FlMockBinaryMessengerClass* klass) {} - -static void fl_mock_binary_messenger_set_message_handler_on_channel( - FlBinaryMessenger* messenger, - const gchar* channel, - FlBinaryMessengerMessageHandler handler, - gpointer user_data, - GDestroyNotify destroy_notify) { - g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(messenger)); - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); - self->mock->SetMessageHandler(channel, handler, user_data); - self->mock->fl_binary_messenger_set_message_handler_on_channel( - messenger, channel, handler, user_data, destroy_notify); -} - -static gboolean fl_mock_binary_messenger_send_response( - FlBinaryMessenger* messenger, - FlBinaryMessengerResponseHandle* response_handle, - GBytes* response, - GError** error) { - g_return_val_if_fail(FL_IS_MOCK_BINARY_MESSENGER(messenger), false); - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); - return self->mock->fl_binary_messenger_send_response( - messenger, response_handle, response, error); -} - -static void fl_mock_binary_messenger_send_on_channel( - FlBinaryMessenger* messenger, - const gchar* channel, - GBytes* message, - GCancellable* cancellable, - GAsyncReadyCallback callback, - gpointer user_data) { - g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(messenger)); - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); - self->mock->fl_binary_messenger_send_on_channel( - messenger, channel, message, cancellable, callback, user_data); -} - -static GBytes* fl_mock_binary_messenger_send_on_channel_finish( - FlBinaryMessenger* messenger, - GAsyncResult* result, - GError** error) { - g_return_val_if_fail(FL_IS_MOCK_BINARY_MESSENGER(messenger), nullptr); - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); - return self->mock->fl_binary_messenger_send_on_channel_finish(messenger, - result, error); -} - -static void fl_mock_binary_messenger_resize_channel( - FlBinaryMessenger* messenger, - const gchar* channel, - int64_t new_size) { - g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(messenger)); - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); - self->mock->fl_binary_messenger_resize_channel(messenger, channel, new_size); -} - -static void fl_mock_binary_messenger_set_warns_on_channel_overflow( - FlBinaryMessenger* messenger, - const gchar* channel, - bool warns) { - g_return_if_fail(FL_IS_MOCK_BINARY_MESSENGER(messenger)); - FlMockBinaryMessenger* self = FL_MOCK_BINARY_MESSENGER(messenger); - self->mock->fl_binary_messenger_set_warns_on_channel_overflow(messenger, - channel, warns); -} - -static void fl_mock_binary_messenger_shutdown(FlBinaryMessenger* messenger) {} - -static void fl_mock_binary_messenger_iface_init( - FlBinaryMessengerInterface* iface) { - iface->set_message_handler_on_channel = - fl_mock_binary_messenger_set_message_handler_on_channel; - iface->send_response = fl_mock_binary_messenger_send_response; - iface->send_on_channel = fl_mock_binary_messenger_send_on_channel; - iface->send_on_channel_finish = - fl_mock_binary_messenger_send_on_channel_finish; - iface->resize_channel = fl_mock_binary_messenger_resize_channel; - iface->set_warns_on_channel_overflow = - fl_mock_binary_messenger_set_warns_on_channel_overflow; - iface->shutdown = fl_mock_binary_messenger_shutdown; -} - -static void fl_mock_binary_messenger_init(FlMockBinaryMessenger* self) {} diff --git a/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger.h b/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger.h deleted file mode 100644 index 394e55882e..0000000000 --- a/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_BINARY_MESSENGER_H_ -#define FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_BINARY_MESSENGER_H_ - -#include - -#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" - -#include "gmock/gmock.h" - -namespace flutter { -namespace testing { - -// Mock for FlBinaryMessenger. -class MockBinaryMessenger { - public: - MockBinaryMessenger(); - ~MockBinaryMessenger(); - - // This was an existing use of operator overloading. It's against our style - // guide but enabling clang tidy on header files is a higher priority than - // fixing this. - // NOLINTNEXTLINE(google-explicit-constructor) - operator FlBinaryMessenger*(); - - MOCK_METHOD(void, - fl_binary_messenger_set_message_handler_on_channel, - (FlBinaryMessenger * messenger, - const gchar* channel, - FlBinaryMessengerMessageHandler handler, - gpointer user_data, - GDestroyNotify destroy_notify)); - - MOCK_METHOD(gboolean, - fl_binary_messenger_send_response, - (FlBinaryMessenger * messenger, - FlBinaryMessengerResponseHandle* response_handle, - GBytes* response, - GError** error)); - - MOCK_METHOD(void, - fl_binary_messenger_send_on_channel, - (FlBinaryMessenger * messenger, - const gchar* channel, - GBytes* message, - GCancellable* cancellable, - GAsyncReadyCallback callback, - gpointer user_data)); - - MOCK_METHOD(GBytes*, - fl_binary_messenger_send_on_channel_finish, - (FlBinaryMessenger * messenger, - GAsyncResult* result, - GError** error)); - - MOCK_METHOD(void, - fl_binary_messenger_resize_channel, - (FlBinaryMessenger * messenger, - const gchar* channel, - int64_t new_size)); - - MOCK_METHOD(void, - fl_binary_messenger_set_warns_on_channel_overflow, - (FlBinaryMessenger * messenger, - const gchar* channel, - bool warns)); - - bool HasMessageHandler(const gchar* channel) const; - - void SetMessageHandler(const gchar* channel, - FlBinaryMessengerMessageHandler handler, - gpointer user_data); - - void ReceiveMessage(const gchar* channel, GBytes* message); - - private: - FlBinaryMessenger* instance_ = nullptr; - std::unordered_map - message_handlers_; - std::unordered_map - response_handles_; - std::unordered_map user_datas_; -}; - -} // namespace testing -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_BINARY_MESSENGER_H_ diff --git a/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.cc b/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.cc deleted file mode 100644 index 4bd7e419d2..0000000000 --- a/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.h" - -struct _FlMockBinaryMessengerResponseHandle { - FlBinaryMessengerResponseHandle parent_instance; -}; - -G_DEFINE_TYPE(FlMockBinaryMessengerResponseHandle, - fl_mock_binary_messenger_response_handle, - fl_binary_messenger_response_handle_get_type()); - -static void fl_mock_binary_messenger_response_handle_class_init( - FlMockBinaryMessengerResponseHandleClass* klass) {} - -static void fl_mock_binary_messenger_response_handle_init( - FlMockBinaryMessengerResponseHandle* self) {} - -FlMockBinaryMessengerResponseHandle* -fl_mock_binary_messenger_response_handle_new() { - return FL_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE( - g_object_new(fl_mock_binary_messenger_response_handle_get_type(), NULL)); -} diff --git a/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.h b/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.h deleted file mode 100644 index 42d86cc80f..0000000000 --- a/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE_H_ -#define FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE_H_ - -#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" - -G_BEGIN_DECLS - -G_DECLARE_FINAL_TYPE(FlMockBinaryMessengerResponseHandle, - fl_mock_binary_messenger_response_handle, - FL, - MOCK_BINARY_MESSENGER_RESPONSE_HANDLE, - FlBinaryMessengerResponseHandle) - -FlMockBinaryMessengerResponseHandle* -fl_mock_binary_messenger_response_handle_new(); - -G_END_DECLS - -#endif // FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_BINARY_MESSENGER_RESPONSE_HANDLE_H_