From 14ae687eacef2f89aa3af30293fede17f7752f1a Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Tue, 3 Dec 2024 13:41:33 +1300 Subject: [PATCH] Make a mock messenger that can easily mock channels (flutter/engine#56867) The previous mock required knowing the specific functions used in the binary messenger, this method instead allows test code to provide complete platform channel implementation for testing and make simulated platform channel calls into embedder code. --- .../src/flutter/shell/platform/linux/BUILD.gn | 3 +- .../linux/fl_binary_messenger_test.cc | 31 +- .../linux/fl_key_channel_responder.cc | 17 +- .../platform/linux/fl_key_channel_responder.h | 25 +- .../linux/fl_key_channel_responder_test.cc | 196 +- .../linux/fl_keyboard_handler_test.cc | 52 +- .../shell/platform/linux/fl_method_channel.cc | 31 +- .../shell/platform/linux/fl_method_codec.cc | 26 + .../platform/linux/fl_method_codec_private.h | 18 +- .../linux/fl_platform_handler_test.cc | 239 ++- .../linux/fl_settings_handler_test.cc | 157 +- .../linux/fl_text_input_handler_test.cc | 1696 ++++++++--------- .../linux/fl_window_state_monitor_test.cc | 235 ++- .../linux/testing/fl_mock_binary_messenger.cc | 609 ++++++ .../linux/testing/fl_mock_binary_messenger.h | 160 ++ .../linux/testing/mock_binary_messenger.cc | 160 -- .../linux/testing/mock_binary_messenger.h | 91 - .../mock_binary_messenger_response_handle.cc | 25 - .../mock_binary_messenger_response_handle.h | 23 - 19 files changed, 2134 insertions(+), 1660 deletions(-) create mode 100644 engine/src/flutter/shell/platform/linux/testing/fl_mock_binary_messenger.cc create mode 100644 engine/src/flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h delete mode 100644 engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger.cc delete mode 100644 engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger.h delete mode 100644 engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.cc delete mode 100644 engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.h 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_