mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add tests for FlBinaryMessenger, FlBasicMessageChannel, FlMethodChannel (#18597)
* Add mock implementations of the Flutter embedding API and EGL * Add tests for FlBinaryMessenger, FlBasicMessageChannel, FlMethodChannel
This commit is contained in:
parent
2bd95d9a4c
commit
a095cc23d8
@ -1191,10 +1191,12 @@ FILE: ../../../flutter/shell/platform/glfw/public/flutter_glfw.h
|
||||
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.cc
|
||||
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.h
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_basic_message_channel.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_basic_message_channel_test.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_binary_codec.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_binary_codec_test.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_binary_messenger.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_binary_messenger_private.h
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_binary_messenger_test.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_dart_project.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_engine.cc
|
||||
@ -1211,6 +1213,7 @@ FILE: ../../../flutter/shell/platform/linux/fl_method_call.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_method_call_private.h
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_method_channel.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_method_channel_private.h
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_method_channel_test.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_method_codec.cc
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_method_codec_private.h
|
||||
FILE: ../../../flutter/shell/platform/linux/fl_method_codec_test.cc
|
||||
|
||||
@ -24,7 +24,6 @@ template("embedder_source_set") {
|
||||
source_set(target_name) {
|
||||
sources = [
|
||||
"embedder.cc",
|
||||
"embedder.h",
|
||||
"embedder_engine.cc",
|
||||
"embedder_engine.h",
|
||||
"embedder_external_texture_gl.cc",
|
||||
@ -75,6 +74,10 @@ template("embedder_source_set") {
|
||||
"//third_party/skia",
|
||||
]
|
||||
|
||||
public_deps = [
|
||||
":embedder_headers",
|
||||
]
|
||||
|
||||
public_configs += [ "//flutter:config" ]
|
||||
}
|
||||
}
|
||||
@ -87,6 +90,14 @@ embedder_source_set("embedder_with_symbol_prefix") {
|
||||
public_configs = [ ":embedder_prefix_config" ]
|
||||
}
|
||||
|
||||
source_set("embedder_headers") {
|
||||
public = [
|
||||
"embedder.h",
|
||||
]
|
||||
|
||||
public_configs = [ "//flutter:config" ]
|
||||
}
|
||||
|
||||
config("embedder_prefix_config") {
|
||||
defines = [ "FLUTTER_API_SYMBOL_PREFIX=Embedder" ]
|
||||
}
|
||||
|
||||
@ -70,9 +70,11 @@ config("relative_flutter_linux_headers") {
|
||||
include_dirs = [ "public" ]
|
||||
}
|
||||
|
||||
source_set("flutter_linux") {
|
||||
source_set("flutter_linux_sources") {
|
||||
public = _public_headers
|
||||
|
||||
configs += [ "//flutter/shell/platform/linux/config:gtk" ]
|
||||
|
||||
sources = [
|
||||
"fl_basic_message_channel.cc",
|
||||
"fl_binary_codec.cc",
|
||||
@ -99,19 +101,29 @@ source_set("flutter_linux") {
|
||||
"fl_view.cc",
|
||||
]
|
||||
|
||||
# Set flag to stop headers being directly included (library users should not do this)
|
||||
defines = [ "FLUTTER_LINUX_COMPILATION" ]
|
||||
|
||||
deps = [
|
||||
"//flutter/shell/platform/embedder:embedder_headers",
|
||||
"//third_party/rapidjson",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("flutter_linux") {
|
||||
configs += [
|
||||
"//flutter/shell/platform/linux/config:gtk",
|
||||
"//flutter/shell/platform/linux/config:egl",
|
||||
"//third_party/khronos:khronos_headers",
|
||||
]
|
||||
|
||||
# Set flag to stop headers being directly included (library users should not do this)
|
||||
defines = [ "FLUTTER_LINUX_COMPILATION" ]
|
||||
public_deps = [
|
||||
":flutter_linux_sources",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//flutter/shell/platform/common/cpp:common_cpp_input",
|
||||
"//flutter/shell/platform/embedder:embedder_with_symbol_prefix",
|
||||
"//third_party/rapidjson",
|
||||
]
|
||||
}
|
||||
|
||||
@ -123,11 +135,14 @@ executable("flutter_linux_unittests") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"fl_basic_message_channel_test.cc",
|
||||
"fl_binary_codec_test.cc",
|
||||
"fl_binary_messenger_test.cc",
|
||||
"fl_dart_project_test.cc",
|
||||
"fl_json_message_codec_test.cc",
|
||||
"fl_json_method_codec_test.cc",
|
||||
"fl_message_codec_test.cc",
|
||||
"fl_method_channel_test.cc",
|
||||
"fl_method_codec_test.cc",
|
||||
"fl_method_response_test.cc",
|
||||
"fl_standard_message_codec_test.cc",
|
||||
@ -135,6 +150,9 @@ executable("flutter_linux_unittests") {
|
||||
"fl_string_codec_test.cc",
|
||||
"fl_value_test.cc",
|
||||
"testing/fl_test.cc",
|
||||
"testing/mock_egl.cc",
|
||||
"testing/mock_engine.cc",
|
||||
"testing/mock_renderer.cc",
|
||||
]
|
||||
|
||||
public_configs = [ "//flutter:config" ]
|
||||
@ -145,8 +163,10 @@ executable("flutter_linux_unittests") {
|
||||
defines = [ "FLUTTER_LINUX_COMPILATION" ]
|
||||
|
||||
deps = [
|
||||
":flutter_linux",
|
||||
":flutter_linux_fixtures",
|
||||
":flutter_linux_sources",
|
||||
"//flutter/runtime:libdart",
|
||||
"//flutter/shell/platform/embedder:embedder_headers",
|
||||
"//flutter/testing",
|
||||
]
|
||||
}
|
||||
|
||||
152
shell/platform/linux/fl_basic_message_channel_test.cc
Normal file
152
shell/platform/linux/fl_basic_message_channel_test.cc
Normal file
@ -0,0 +1,152 @@
|
||||
// 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.
|
||||
|
||||
// Included first as it collides with the X11 headers.
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "flutter/shell/platform/linux/fl_binary_messenger_private.h"
|
||||
#include "flutter/shell/platform/linux/fl_engine_private.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.h"
|
||||
#include "flutter/shell/platform/linux/testing/mock_renderer.h"
|
||||
|
||||
// Creates a mock engine that responds to platform messages.
|
||||
static FlEngine* make_mock_engine() {
|
||||
g_autoptr(FlDartProject) project = fl_dart_project_new("data");
|
||||
g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
|
||||
g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer));
|
||||
g_autoptr(GError) error = nullptr;
|
||||
EXPECT_TRUE(fl_engine_start(engine, &error));
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
return static_cast<FlEngine*>(g_object_ref(engine));
|
||||
}
|
||||
|
||||
// Called when the message response is received in the SendMessage test.
|
||||
static void echo_response_cb(GObject* object,
|
||||
GAsyncResult* result,
|
||||
gpointer user_data) {
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(FlValue) message = fl_basic_message_channel_send_finish(
|
||||
FL_BASIC_MESSAGE_CHANNEL(object), result, &error);
|
||||
EXPECT_NE(message, nullptr);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_STRING);
|
||||
EXPECT_STREQ(fl_value_get_string(message), "Hello World!");
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks sending a message works.
|
||||
TEST(FlBasicMessageChannelTest, SendMessage) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new();
|
||||
g_autoptr(FlBasicMessageChannel) channel = fl_basic_message_channel_new(
|
||||
messenger, "test/echo", FL_MESSAGE_CODEC(codec));
|
||||
g_autoptr(FlValue) message = fl_value_new_string("Hello World!");
|
||||
fl_basic_message_channel_send(channel, message, nullptr, echo_response_cb,
|
||||
loop);
|
||||
|
||||
// Blocks here until echo_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
|
||||
// Called when the message response is received in the SendFailure test.
|
||||
static void failure_response_cb(GObject* object,
|
||||
GAsyncResult* result,
|
||||
gpointer user_data) {
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(FlValue) message = fl_basic_message_channel_send_finish(
|
||||
FL_BASIC_MESSAGE_CHANNEL(object), result, &error);
|
||||
EXPECT_EQ(message, nullptr);
|
||||
EXPECT_NE(error, nullptr);
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks the engine reporting a send failure is handled.
|
||||
TEST(FlBasicMessageChannelTest, SendFailure) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new();
|
||||
g_autoptr(FlBasicMessageChannel) channel = fl_basic_message_channel_new(
|
||||
messenger, "test/failure", FL_MESSAGE_CODEC(codec));
|
||||
g_autoptr(FlValue) message = fl_value_new_string("Hello World!");
|
||||
fl_basic_message_channel_send(channel, message, nullptr, failure_response_cb,
|
||||
loop);
|
||||
|
||||
// Blocks here until failure_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
|
||||
// Called when a message is received from the engine in the ReceiveMessage test.
|
||||
static void message_cb(FlBasicMessageChannel* channel,
|
||||
FlValue* message,
|
||||
FlBasicMessageChannelResponseHandle* response_handle,
|
||||
gpointer user_data) {
|
||||
EXPECT_NE(message, nullptr);
|
||||
EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_STRING);
|
||||
EXPECT_STREQ(fl_value_get_string(message), "Marco!");
|
||||
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(FlValue) response = fl_value_new_string("Polo!");
|
||||
EXPECT_TRUE(fl_basic_message_channel_respond(channel, response_handle,
|
||||
response, &error));
|
||||
EXPECT_EQ(error, nullptr);
|
||||
}
|
||||
|
||||
// Called when a the test engine notifies us what response we sent in the
|
||||
// ReceiveMessage test.
|
||||
static void response_cb(FlBasicMessageChannel* channel,
|
||||
FlValue* message,
|
||||
FlBasicMessageChannelResponseHandle* response_handle,
|
||||
gpointer user_data) {
|
||||
EXPECT_NE(message, nullptr);
|
||||
EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_STRING);
|
||||
EXPECT_STREQ(fl_value_get_string(message), "Polo!");
|
||||
|
||||
fl_basic_message_channel_respond(channel, response_handle, nullptr, nullptr);
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks the shell able to receive and respond to messages from the engine.
|
||||
TEST(FlBasicMessageChannelTest, ReceiveMessage) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
|
||||
// Listen for messages from the engine.
|
||||
g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new();
|
||||
g_autoptr(FlBasicMessageChannel) messages_channel =
|
||||
fl_basic_message_channel_new(messenger, "test/messages",
|
||||
FL_MESSAGE_CODEC(codec));
|
||||
fl_basic_message_channel_set_message_handler(messages_channel, message_cb,
|
||||
nullptr, nullptr);
|
||||
|
||||
// Listen for response from the engine.
|
||||
g_autoptr(FlBasicMessageChannel) responses_channel =
|
||||
fl_basic_message_channel_new(messenger, "test/responses",
|
||||
FL_MESSAGE_CODEC(codec));
|
||||
fl_basic_message_channel_set_message_handler(responses_channel, response_cb,
|
||||
loop, nullptr);
|
||||
|
||||
// Triggger the engine to send a message.
|
||||
g_autoptr(FlBasicMessageChannel) control_channel =
|
||||
fl_basic_message_channel_new(messenger, "test/send-message",
|
||||
FL_MESSAGE_CODEC(codec));
|
||||
g_autoptr(FlValue) message = fl_value_new_string("Marco!");
|
||||
fl_basic_message_channel_send(control_channel, message, nullptr, nullptr,
|
||||
nullptr);
|
||||
|
||||
// Blocks here until response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
195
shell/platform/linux/fl_binary_messenger_test.cc
Normal file
195
shell/platform/linux/fl_binary_messenger_test.cc
Normal file
@ -0,0 +1,195 @@
|
||||
// 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.
|
||||
|
||||
// Included first as it collides with the X11 headers.
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "flutter/shell/platform/linux/fl_binary_messenger_private.h"
|
||||
#include "flutter/shell/platform/linux/fl_engine_private.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h"
|
||||
#include "flutter/shell/platform/linux/testing/mock_renderer.h"
|
||||
|
||||
// Creates a mock engine that responds to platform messages.
|
||||
static FlEngine* make_mock_engine() {
|
||||
g_autoptr(FlDartProject) project = fl_dart_project_new("data");
|
||||
g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
|
||||
g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer));
|
||||
g_autoptr(GError) error = nullptr;
|
||||
EXPECT_TRUE(fl_engine_start(engine, &error));
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
return static_cast<FlEngine*>(g_object_ref(engine));
|
||||
}
|
||||
|
||||
// Checks sending nullptr for a message works.
|
||||
TEST(FlBinaryMessengerTest, SendNullptrMessage) {
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
fl_binary_messenger_send_on_channel(messenger, "test/echo", nullptr, nullptr,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
// Checks sending a zero length message works.
|
||||
TEST(FlBinaryMessengerTest, SendEmptyMessage) {
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
g_autoptr(GBytes) message = g_bytes_new(nullptr, 0);
|
||||
fl_binary_messenger_send_on_channel(messenger, "test/echo", message, nullptr,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
// Called when the message response is received in the SendMessage test.
|
||||
static void echo_response_cb(GObject* object,
|
||||
GAsyncResult* result,
|
||||
gpointer user_data) {
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(GBytes) message = fl_binary_messenger_send_on_channel_finish(
|
||||
FL_BINARY_MESSENGER(object), result, &error);
|
||||
EXPECT_NE(message, nullptr);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
g_autofree gchar* text =
|
||||
g_strndup(static_cast<const gchar*>(g_bytes_get_data(message, nullptr)),
|
||||
g_bytes_get_size(message));
|
||||
EXPECT_STREQ(text, "Hello World!");
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks sending a message works.
|
||||
TEST(FlBinaryMessengerTest, SendMessage) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
const char* text = "Hello World!";
|
||||
g_autoptr(GBytes) message = g_bytes_new(text, strlen(text));
|
||||
fl_binary_messenger_send_on_channel(messenger, "test/echo", message, nullptr,
|
||||
echo_response_cb, loop);
|
||||
|
||||
// Blocks here until echo_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
|
||||
// Called when the message response is received in the NullptrResponse test.
|
||||
static void nullptr_response_cb(GObject* object,
|
||||
GAsyncResult* result,
|
||||
gpointer user_data) {
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(GBytes) message = fl_binary_messenger_send_on_channel_finish(
|
||||
FL_BINARY_MESSENGER(object), result, &error);
|
||||
EXPECT_NE(message, nullptr);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
EXPECT_EQ(g_bytes_get_size(message), static_cast<gsize>(0));
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks the engine returning a nullptr message work.
|
||||
TEST(FlBinaryMessengerTest, NullptrResponse) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
const char* text = "Hello World!";
|
||||
g_autoptr(GBytes) message = g_bytes_new(text, strlen(text));
|
||||
fl_binary_messenger_send_on_channel(messenger, "test/nullptr-response",
|
||||
message, nullptr, nullptr_response_cb,
|
||||
loop);
|
||||
|
||||
// Blocks here until nullptr_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
|
||||
// Called when the message response is received in the SendFailure test.
|
||||
static void failure_response_cb(GObject* object,
|
||||
GAsyncResult* result,
|
||||
gpointer user_data) {
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(GBytes) message = fl_binary_messenger_send_on_channel_finish(
|
||||
FL_BINARY_MESSENGER(object), result, &error);
|
||||
EXPECT_EQ(message, nullptr);
|
||||
EXPECT_NE(error, nullptr);
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks the engine reporting a send failure is handled.
|
||||
TEST(FlBinaryMessengerTest, SendFailure) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
fl_binary_messenger_send_on_channel(messenger, "test/failure", nullptr,
|
||||
nullptr, failure_response_cb, loop);
|
||||
|
||||
// Blocks here until failure_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
|
||||
// Called when a message is received from the engine in the ReceiveMessage test.
|
||||
static void message_cb(FlBinaryMessenger* messenger,
|
||||
const gchar* channel,
|
||||
GBytes* message,
|
||||
FlBinaryMessengerResponseHandle* response_handle,
|
||||
gpointer user_data) {
|
||||
EXPECT_NE(message, nullptr);
|
||||
g_autofree gchar* text =
|
||||
g_strndup(static_cast<const gchar*>(g_bytes_get_data(message, nullptr)),
|
||||
g_bytes_get_size(message));
|
||||
EXPECT_STREQ(text, "Marco!");
|
||||
|
||||
const char* response_text = "Polo!";
|
||||
g_autoptr(GBytes) response =
|
||||
g_bytes_new(response_text, strlen(response_text));
|
||||
g_autoptr(GError) error = nullptr;
|
||||
EXPECT_TRUE(fl_binary_messenger_send_response(messenger, response_handle,
|
||||
response, &error));
|
||||
EXPECT_EQ(error, nullptr);
|
||||
}
|
||||
|
||||
// Called when a the test engine notifies us what response we sent in the
|
||||
// ReceiveMessage test.
|
||||
static void response_cb(FlBinaryMessenger* messenger,
|
||||
const gchar* channel,
|
||||
GBytes* message,
|
||||
FlBinaryMessengerResponseHandle* response_handle,
|
||||
gpointer user_data) {
|
||||
EXPECT_NE(message, nullptr);
|
||||
g_autofree gchar* text =
|
||||
g_strndup(static_cast<const gchar*>(g_bytes_get_data(message, nullptr)),
|
||||
g_bytes_get_size(message));
|
||||
EXPECT_STREQ(text, "Polo!");
|
||||
|
||||
fl_binary_messenger_send_response(messenger, response_handle, nullptr,
|
||||
nullptr);
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks the shell able to receive and respond to messages from the engine.
|
||||
TEST(FlBinaryMessengerTest, ReceiveMessage) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
|
||||
// Listen for messages from the engine.
|
||||
fl_binary_messenger_set_message_handler_on_channel(
|
||||
messenger, "test/messages", message_cb, nullptr, nullptr);
|
||||
|
||||
// Listen for response from the engine.
|
||||
fl_binary_messenger_set_message_handler_on_channel(
|
||||
messenger, "test/responses", response_cb, loop, nullptr);
|
||||
|
||||
// Triggger the engine to send a message.
|
||||
const char* text = "Marco!";
|
||||
g_autoptr(GBytes) message = g_bytes_new(text, strlen(text));
|
||||
fl_binary_messenger_send_on_channel(messenger, "test/send-message", message,
|
||||
nullptr, nullptr, nullptr);
|
||||
|
||||
// Blocks here until response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
434
shell/platform/linux/fl_method_channel_test.cc
Normal file
434
shell/platform/linux/fl_method_channel_test.cc
Normal file
@ -0,0 +1,434 @@
|
||||
// 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.
|
||||
|
||||
// Included first as it collides with the X11 headers.
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "flutter/shell/platform/linux/fl_binary_messenger_private.h"
|
||||
#include "flutter/shell/platform/linux/fl_engine_private.h"
|
||||
#include "flutter/shell/platform/linux/fl_method_codec_private.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h"
|
||||
#include "flutter/shell/platform/linux/testing/mock_renderer.h"
|
||||
|
||||
// Creates a mock engine that responds to platform messages.
|
||||
static FlEngine* make_mock_engine() {
|
||||
g_autoptr(FlDartProject) project = fl_dart_project_new("data");
|
||||
g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
|
||||
g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer));
|
||||
g_autoptr(GError) error = nullptr;
|
||||
EXPECT_TRUE(fl_engine_start(engine, &error));
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
return static_cast<FlEngine*>(g_object_ref(engine));
|
||||
}
|
||||
|
||||
// Called when when the method call response is received in the InvokeMethod
|
||||
// test.
|
||||
static void method_response_cb(GObject* object,
|
||||
GAsyncResult* result,
|
||||
gpointer user_data) {
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(
|
||||
FL_METHOD_CHANNEL(object), result, &error);
|
||||
EXPECT_NE(response, nullptr);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
FlValue* r = fl_method_response_get_result(response, &error);
|
||||
EXPECT_NE(r, nullptr);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
EXPECT_EQ(fl_value_get_type(r), FL_VALUE_TYPE_STRING);
|
||||
EXPECT_STREQ(fl_value_get_string(r), "Hello World!");
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks if invoking a method returns a value.
|
||||
TEST(FlMethodChannelTest, InvokeMethod) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
|
||||
messenger, "test/standard-method", FL_METHOD_CODEC(codec));
|
||||
|
||||
g_autoptr(FlValue) args = fl_value_new_string("Hello World!");
|
||||
fl_method_channel_invoke_method(channel, "Echo", args, nullptr,
|
||||
method_response_cb, loop);
|
||||
|
||||
// Blocks here until method_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
|
||||
// Called when when the method call response is received in the
|
||||
// InvokeMethodNullptrArgsMessage test.
|
||||
static void nullptr_args_response_cb(GObject* object,
|
||||
GAsyncResult* result,
|
||||
gpointer user_data) {
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(
|
||||
FL_METHOD_CHANNEL(object), result, &error);
|
||||
EXPECT_NE(response, nullptr);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
FlValue* r = fl_method_response_get_result(response, &error);
|
||||
EXPECT_NE(r, nullptr);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
EXPECT_EQ(fl_value_get_type(r), FL_VALUE_TYPE_NULL);
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks if a method can be invoked with nullptr for arguments.
|
||||
TEST(FlMethodChannelTest, InvokeMethodNullptrArgsMessage) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
|
||||
messenger, "test/standard-method", FL_METHOD_CODEC(codec));
|
||||
|
||||
fl_method_channel_invoke_method(channel, "Echo", nullptr, nullptr,
|
||||
nullptr_args_response_cb, loop);
|
||||
|
||||
// Blocks here until nullptr_args_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
|
||||
// Called when when the method call response is received in the
|
||||
// InvokeMethodError test.
|
||||
static void error_response_cb(GObject* object,
|
||||
GAsyncResult* result,
|
||||
gpointer user_data) {
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(
|
||||
FL_METHOD_CHANNEL(object), result, &error);
|
||||
EXPECT_NE(response, nullptr);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
EXPECT_TRUE(FL_IS_METHOD_ERROR_RESPONSE(response));
|
||||
EXPECT_STREQ(
|
||||
fl_method_error_response_get_code(FL_METHOD_ERROR_RESPONSE(response)),
|
||||
"CODE");
|
||||
EXPECT_STREQ(
|
||||
fl_method_error_response_get_message(FL_METHOD_ERROR_RESPONSE(response)),
|
||||
"MESSAGE");
|
||||
FlValue* details =
|
||||
fl_method_error_response_get_details(FL_METHOD_ERROR_RESPONSE(response));
|
||||
EXPECT_NE(details, nullptr);
|
||||
EXPECT_EQ(fl_value_get_type(details), FL_VALUE_TYPE_STRING);
|
||||
EXPECT_STREQ(fl_value_get_string(details), "DETAILS");
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks if an error response from a method call is handled.
|
||||
TEST(FlMethodChannelTest, InvokeMethodError) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
|
||||
messenger, "test/standard-method", FL_METHOD_CODEC(codec));
|
||||
|
||||
g_autoptr(FlValue) args = fl_value_new_list();
|
||||
fl_value_append_take(args, fl_value_new_string("CODE"));
|
||||
fl_value_append_take(args, fl_value_new_string("MESSAGE"));
|
||||
fl_value_append_take(args, fl_value_new_string("DETAILS"));
|
||||
fl_method_channel_invoke_method(channel, "Error", args, nullptr,
|
||||
error_response_cb, loop);
|
||||
|
||||
// Blocks here until error_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
|
||||
// Called when when the method call response is received in the
|
||||
// InvokeMethodNotImplemented test.
|
||||
static void not_implemented_response_cb(GObject* object,
|
||||
GAsyncResult* result,
|
||||
gpointer user_data) {
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(
|
||||
FL_METHOD_CHANNEL(object), result, &error);
|
||||
EXPECT_NE(response, nullptr);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
EXPECT_TRUE(FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response));
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks if a not implemeneted response from a method call is handled.
|
||||
TEST(FlMethodChannelTest, InvokeMethodNotImplemented) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
|
||||
messenger, "test/standard-method", FL_METHOD_CODEC(codec));
|
||||
|
||||
fl_method_channel_invoke_method(channel, "NotImplemented", nullptr, nullptr,
|
||||
not_implemented_response_cb, loop);
|
||||
|
||||
// Blocks here until not_implemented_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
|
||||
// Called when when the method call response is received in the
|
||||
// InvokeMethodFailure test.
|
||||
static void failure_response_cb(GObject* object,
|
||||
GAsyncResult* result,
|
||||
gpointer user_data) {
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(
|
||||
FL_METHOD_CHANNEL(object), result, &error);
|
||||
EXPECT_EQ(response, nullptr);
|
||||
EXPECT_NE(error, nullptr);
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks if an engine failure calling a method call is handled.
|
||||
TEST(FlMethodChannelTest, InvokeMethodFailure) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(FlMethodChannel) channel =
|
||||
fl_method_channel_new(messenger, "test/failure", FL_METHOD_CODEC(codec));
|
||||
|
||||
fl_method_channel_invoke_method(channel, "Echo", nullptr, nullptr,
|
||||
failure_response_cb, loop);
|
||||
|
||||
// Blocks here until failure_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
|
||||
// Called when a method call is received from the engine in the
|
||||
// ReceiveMethodCallRespondSuccess test.
|
||||
static void method_call_success_cb(FlMethodChannel* channel,
|
||||
FlMethodCall* method_call,
|
||||
gpointer user_data) {
|
||||
EXPECT_STREQ(fl_method_call_get_name(method_call), "Foo");
|
||||
EXPECT_EQ(fl_value_get_type(fl_method_call_get_args(method_call)),
|
||||
FL_VALUE_TYPE_STRING);
|
||||
EXPECT_STREQ(fl_value_get_string(fl_method_call_get_args(method_call)),
|
||||
"Marco!");
|
||||
|
||||
g_autoptr(FlValue) result = fl_value_new_string("Polo!");
|
||||
g_autoptr(GError) error = nullptr;
|
||||
EXPECT_TRUE(fl_method_call_respond_success(method_call, result, &error));
|
||||
EXPECT_EQ(error, nullptr);
|
||||
}
|
||||
|
||||
// Called when a the test engine notifies us what response we sent in the
|
||||
// ReceiveMethodCallRespondSuccess test.
|
||||
static void method_call_success_response_cb(
|
||||
FlBinaryMessenger* messenger,
|
||||
const gchar* channel,
|
||||
GBytes* message,
|
||||
FlBinaryMessengerResponseHandle* response_handle,
|
||||
gpointer user_data) {
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(FlMethodResponse) response =
|
||||
fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error);
|
||||
EXPECT_NE(response, nullptr);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
|
||||
FlValue* result = fl_method_success_response_get_result(
|
||||
FL_METHOD_SUCCESS_RESPONSE(response));
|
||||
EXPECT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_STRING);
|
||||
EXPECT_STREQ(fl_value_get_string(result), "Polo!");
|
||||
|
||||
fl_binary_messenger_send_response(messenger, response_handle, nullptr,
|
||||
nullptr);
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks the shell able to receive and respond to method calls from the engine.
|
||||
TEST(FlMethodChannelTest, ReceiveMethodCallRespondSuccess) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
|
||||
messenger, "test/standard-method", FL_METHOD_CODEC(codec));
|
||||
fl_method_channel_set_method_call_handler(channel, method_call_success_cb,
|
||||
nullptr, nullptr);
|
||||
|
||||
// Listen for response from the engine.
|
||||
fl_binary_messenger_set_message_handler_on_channel(
|
||||
messenger, "test/responses", method_call_success_response_cb, loop,
|
||||
nullptr);
|
||||
|
||||
// Trigger the engine to make a method call.
|
||||
g_autoptr(FlValue) args = fl_value_new_list();
|
||||
fl_value_append_take(args, fl_value_new_string("test/standard-method"));
|
||||
fl_value_append_take(args, fl_value_new_string("Foo"));
|
||||
fl_value_append_take(args, fl_value_new_string("Marco!"));
|
||||
fl_method_channel_invoke_method(channel, "InvokeMethod", args, nullptr,
|
||||
nullptr, loop);
|
||||
|
||||
// Blocks here until method_call_success_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
|
||||
// Called when a method call is received from the engine in the
|
||||
// ReceiveMethodCallRespondError test.
|
||||
static void method_call_error_cb(FlMethodChannel* channel,
|
||||
FlMethodCall* method_call,
|
||||
gpointer user_data) {
|
||||
EXPECT_STREQ(fl_method_call_get_name(method_call), "Foo");
|
||||
EXPECT_EQ(fl_value_get_type(fl_method_call_get_args(method_call)),
|
||||
FL_VALUE_TYPE_STRING);
|
||||
EXPECT_STREQ(fl_value_get_string(fl_method_call_get_args(method_call)),
|
||||
"Marco!");
|
||||
|
||||
g_autoptr(FlValue) details = fl_value_new_string("DETAILS");
|
||||
g_autoptr(GError) error = nullptr;
|
||||
EXPECT_TRUE(fl_method_call_respond_error(method_call, "CODE", "MESSAGE",
|
||||
details, &error));
|
||||
EXPECT_EQ(error, nullptr);
|
||||
}
|
||||
|
||||
// Called when a the test engine notifies us what response we sent in the
|
||||
// ReceiveMethodCallRespondError test.
|
||||
static void method_call_error_response_cb(
|
||||
FlBinaryMessenger* messenger,
|
||||
const gchar* channel,
|
||||
GBytes* message,
|
||||
FlBinaryMessengerResponseHandle* response_handle,
|
||||
gpointer user_data) {
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(FlMethodResponse) response =
|
||||
fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error);
|
||||
EXPECT_NE(response, nullptr);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
EXPECT_TRUE(FL_IS_METHOD_ERROR_RESPONSE(response));
|
||||
EXPECT_STREQ(
|
||||
fl_method_error_response_get_code(FL_METHOD_ERROR_RESPONSE(response)),
|
||||
"CODE");
|
||||
EXPECT_STREQ(
|
||||
fl_method_error_response_get_message(FL_METHOD_ERROR_RESPONSE(response)),
|
||||
"MESSAGE");
|
||||
FlValue* details =
|
||||
fl_method_error_response_get_details(FL_METHOD_ERROR_RESPONSE(response));
|
||||
EXPECT_EQ(fl_value_get_type(details), FL_VALUE_TYPE_STRING);
|
||||
EXPECT_STREQ(fl_value_get_string(details), "DETAILS");
|
||||
|
||||
fl_binary_messenger_send_response(messenger, response_handle, nullptr,
|
||||
nullptr);
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks the shell able to receive and respond to method calls from the engine.
|
||||
TEST(FlMethodChannelTest, ReceiveMethodCallRespondError) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
|
||||
messenger, "test/standard-method", FL_METHOD_CODEC(codec));
|
||||
fl_method_channel_set_method_call_handler(channel, method_call_error_cb,
|
||||
nullptr, nullptr);
|
||||
|
||||
// Listen for response from the engine.
|
||||
fl_binary_messenger_set_message_handler_on_channel(
|
||||
messenger, "test/responses", method_call_error_response_cb, loop,
|
||||
nullptr);
|
||||
|
||||
// Trigger the engine to make a method call.
|
||||
g_autoptr(FlValue) args = fl_value_new_list();
|
||||
fl_value_append_take(args, fl_value_new_string("test/standard-method"));
|
||||
fl_value_append_take(args, fl_value_new_string("Foo"));
|
||||
fl_value_append_take(args, fl_value_new_string("Marco!"));
|
||||
fl_method_channel_invoke_method(channel, "InvokeMethod", args, nullptr,
|
||||
nullptr, loop);
|
||||
|
||||
// Blocks here until method_call_error_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
|
||||
// Called when a method call is received from the engine in the
|
||||
// ReceiveMethodCallRespondNotImplemented test.
|
||||
static void method_call_not_implemented_cb(FlMethodChannel* channel,
|
||||
FlMethodCall* method_call,
|
||||
gpointer user_data) {
|
||||
EXPECT_STREQ(fl_method_call_get_name(method_call), "Foo");
|
||||
EXPECT_EQ(fl_value_get_type(fl_method_call_get_args(method_call)),
|
||||
FL_VALUE_TYPE_STRING);
|
||||
EXPECT_STREQ(fl_value_get_string(fl_method_call_get_args(method_call)),
|
||||
"Marco!");
|
||||
|
||||
g_autoptr(GError) error = nullptr;
|
||||
EXPECT_TRUE(fl_method_call_respond_not_implemented(method_call, &error));
|
||||
EXPECT_EQ(error, nullptr);
|
||||
}
|
||||
|
||||
// Called when a the test engine notifies us what response we sent in the
|
||||
// ReceiveMethodCallRespondNotImplemented test.
|
||||
static void method_call_not_implemented_response_cb(
|
||||
FlBinaryMessenger* messenger,
|
||||
const gchar* channel,
|
||||
GBytes* message,
|
||||
FlBinaryMessengerResponseHandle* response_handle,
|
||||
gpointer user_data) {
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(FlMethodResponse) response =
|
||||
fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error);
|
||||
EXPECT_NE(response, nullptr);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
EXPECT_TRUE(FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response));
|
||||
|
||||
fl_binary_messenger_send_response(messenger, response_handle, nullptr,
|
||||
nullptr);
|
||||
|
||||
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
|
||||
}
|
||||
|
||||
// Checks the shell able to receive and respond to method calls from the engine.
|
||||
TEST(FlMethodChannelTest, ReceiveMethodCallRespondNotImplemented) {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
|
||||
|
||||
g_autoptr(FlEngine) engine = make_mock_engine();
|
||||
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
|
||||
messenger, "test/standard-method", FL_METHOD_CODEC(codec));
|
||||
fl_method_channel_set_method_call_handler(
|
||||
channel, method_call_not_implemented_cb, nullptr, nullptr);
|
||||
|
||||
// Listen for response from the engine.
|
||||
fl_binary_messenger_set_message_handler_on_channel(
|
||||
messenger, "test/responses", method_call_not_implemented_response_cb,
|
||||
loop, nullptr);
|
||||
|
||||
// Trigger the engine to make a method call.
|
||||
g_autoptr(FlValue) args = fl_value_new_list();
|
||||
fl_value_append_take(args, fl_value_new_string("test/standard-method"));
|
||||
fl_value_append_take(args, fl_value_new_string("Foo"));
|
||||
fl_value_append_take(args, fl_value_new_string("Marco!"));
|
||||
fl_method_channel_invoke_method(channel, "InvokeMethod", args, nullptr,
|
||||
nullptr, loop);
|
||||
|
||||
// Blocks here until method_call_not_implemented_response_cb is called.
|
||||
g_main_loop_run(loop);
|
||||
}
|
||||
65
shell/platform/linux/testing/mock_egl.cc
Normal file
65
shell/platform/linux/testing/mock_egl.cc
Normal file
@ -0,0 +1,65 @@
|
||||
// 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 <EGL/egl.h>
|
||||
|
||||
EGLBoolean eglBindAPI(EGLenum api) {
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLBoolean eglChooseConfig(EGLDisplay dpy,
|
||||
const EGLint* attrib_list,
|
||||
EGLConfig* configs,
|
||||
EGLint config_size,
|
||||
EGLint* num_config) {
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLContext eglCreateContext(EGLDisplay dpy,
|
||||
EGLConfig config,
|
||||
EGLContext share_context,
|
||||
const EGLint* attrib_list) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EGLSurface eglCreateWindowSurface(EGLDisplay dpy,
|
||||
EGLConfig config,
|
||||
EGLNativeWindowType win,
|
||||
const EGLint* attrib_list) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void (*eglGetProcAddress(const char* procname))(void) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) {
|
||||
if (major != nullptr)
|
||||
*major = 1;
|
||||
if (minor != nullptr)
|
||||
*major = 5;
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLBoolean eglMakeCurrent(EGLDisplay dpy,
|
||||
EGLSurface draw,
|
||||
EGLSurface read,
|
||||
EGLContext ctx) {
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLBoolean eglQueryContext(EGLDisplay dpy,
|
||||
EGLContext ctx,
|
||||
EGLint attribute,
|
||||
EGLint* value) {
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
|
||||
return EGL_TRUE;
|
||||
}
|
||||
369
shell/platform/linux/testing/mock_engine.cc
Normal file
369
shell/platform/linux/testing/mock_engine.cc
Normal file
@ -0,0 +1,369 @@
|
||||
// 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/embedder/embedder.h"
|
||||
#include "flutter/shell/platform/linux/fl_method_codec_private.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_response.h"
|
||||
#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
struct _FlutterEngine {
|
||||
bool running;
|
||||
FlutterPlatformMessageCallback platform_message_callback;
|
||||
FlutterTaskRunnerPostTaskCallback platform_post_task_callback;
|
||||
void* user_data;
|
||||
|
||||
_FlutterEngine(FlutterPlatformMessageCallback platform_message_callback,
|
||||
FlutterTaskRunnerPostTaskCallback platform_post_task_callback,
|
||||
void* user_data)
|
||||
: running(false),
|
||||
platform_message_callback(platform_message_callback),
|
||||
platform_post_task_callback(platform_post_task_callback),
|
||||
user_data(user_data) {}
|
||||
};
|
||||
|
||||
struct _FlutterPlatformMessageResponseHandle {
|
||||
FlutterDataCallback data_callback;
|
||||
void* user_data;
|
||||
std::string channel;
|
||||
bool released;
|
||||
|
||||
// Constructor for a response handle generated by the engine.
|
||||
_FlutterPlatformMessageResponseHandle(std::string channel)
|
||||
: data_callback(nullptr),
|
||||
user_data(nullptr),
|
||||
channel(channel),
|
||||
released(false) {}
|
||||
|
||||
// Constructor for a response handle generated by the shell.
|
||||
_FlutterPlatformMessageResponseHandle(FlutterDataCallback data_callback,
|
||||
void* user_data)
|
||||
: data_callback(data_callback), user_data(user_data), released(false) {}
|
||||
};
|
||||
|
||||
struct _FlutterTaskRunner {
|
||||
uint64_t task;
|
||||
std::string channel;
|
||||
const FlutterPlatformMessageResponseHandle* response_handle;
|
||||
uint8_t* message;
|
||||
size_t message_size;
|
||||
|
||||
_FlutterTaskRunner(
|
||||
uint64_t task,
|
||||
const std::string& channel,
|
||||
const FlutterPlatformMessageResponseHandle* response_handle,
|
||||
const uint8_t* message,
|
||||
size_t message_size)
|
||||
: task(task),
|
||||
channel(channel),
|
||||
response_handle(response_handle),
|
||||
message_size(message_size) {
|
||||
this->message = static_cast<uint8_t*>(malloc(message_size));
|
||||
memcpy(this->message, message, message_size);
|
||||
}
|
||||
~_FlutterTaskRunner() {
|
||||
if (response_handle != nullptr) {
|
||||
EXPECT_TRUE(response_handle->released);
|
||||
delete response_handle;
|
||||
}
|
||||
free(message);
|
||||
}
|
||||
};
|
||||
|
||||
// Send a response from the engine.
|
||||
static void send_response(
|
||||
FLUTTER_API_SYMBOL(FlutterEngine) engine,
|
||||
const std::string& channel,
|
||||
const FlutterPlatformMessageResponseHandle* response_handle,
|
||||
const uint8_t* message,
|
||||
size_t message_size) {
|
||||
if (response_handle == nullptr)
|
||||
return;
|
||||
|
||||
FlutterTask task;
|
||||
task.runner = new _FlutterTaskRunner(1234, channel, response_handle, message,
|
||||
message_size);
|
||||
task.task = task.runner->task;
|
||||
engine->platform_post_task_callback(task, 0, engine->user_data);
|
||||
}
|
||||
|
||||
// Send a message from the engine.
|
||||
static void send_message(FLUTTER_API_SYMBOL(FlutterEngine) engine,
|
||||
const std::string& channel,
|
||||
const uint8_t* message,
|
||||
size_t message_size) {
|
||||
FlutterTask task;
|
||||
task.runner =
|
||||
new _FlutterTaskRunner(1234, channel, nullptr, message, message_size);
|
||||
task.task = task.runner->task;
|
||||
engine->platform_post_task_callback(task, 0, engine->user_data);
|
||||
}
|
||||
|
||||
static void invoke_method(FLUTTER_API_SYMBOL(FlutterEngine) engine,
|
||||
const std::string& channel,
|
||||
const gchar* name,
|
||||
FlValue* args) {
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(GError) error = nullptr;
|
||||
g_autoptr(GBytes) message = fl_method_codec_encode_method_call(
|
||||
FL_METHOD_CODEC(codec), name, args, &error);
|
||||
EXPECT_NE(message, nullptr);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
FlutterTask task;
|
||||
task.runner = new _FlutterTaskRunner(
|
||||
1234, channel, nullptr,
|
||||
static_cast<const uint8_t*>(g_bytes_get_data(message, nullptr)),
|
||||
g_bytes_get_size(message));
|
||||
task.task = task.runner->task;
|
||||
engine->platform_post_task_callback(task, 0, engine->user_data);
|
||||
}
|
||||
|
||||
FlutterEngineResult FlutterEngineRun(size_t version,
|
||||
const FlutterRendererConfig* config,
|
||||
const FlutterProjectArgs* args,
|
||||
void* user_data,
|
||||
FLUTTER_API_SYMBOL(FlutterEngine) *
|
||||
engine_out) {
|
||||
EXPECT_NE(config, nullptr);
|
||||
EXPECT_NE(args, nullptr);
|
||||
EXPECT_NE(user_data, nullptr);
|
||||
EXPECT_NE(engine_out, nullptr);
|
||||
|
||||
FlutterEngineResult result =
|
||||
FlutterEngineInitialize(version, config, args, user_data, engine_out);
|
||||
if (result != kSuccess)
|
||||
return result;
|
||||
return FlutterEngineRunInitialized(*engine_out);
|
||||
}
|
||||
|
||||
FlutterEngineResult FlutterEngineShutdown(FLUTTER_API_SYMBOL(FlutterEngine)
|
||||
engine) {
|
||||
delete engine;
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
FlutterEngineResult FlutterEngineInitialize(size_t version,
|
||||
const FlutterRendererConfig* config,
|
||||
const FlutterProjectArgs* args,
|
||||
void* user_data,
|
||||
FLUTTER_API_SYMBOL(FlutterEngine) *
|
||||
engine_out) {
|
||||
EXPECT_NE(config, nullptr);
|
||||
|
||||
EXPECT_NE(args, nullptr);
|
||||
EXPECT_NE(args->platform_message_callback, nullptr);
|
||||
EXPECT_NE(args->custom_task_runners, nullptr);
|
||||
EXPECT_NE(args->custom_task_runners->platform_task_runner, nullptr);
|
||||
EXPECT_NE(args->custom_task_runners->platform_task_runner->post_task_callback,
|
||||
nullptr);
|
||||
|
||||
EXPECT_NE(user_data, nullptr);
|
||||
|
||||
EXPECT_EQ(config->type, kOpenGL);
|
||||
|
||||
*engine_out = new _FlutterEngine(
|
||||
args->platform_message_callback,
|
||||
args->custom_task_runners->platform_task_runner->post_task_callback,
|
||||
user_data);
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
FlutterEngineResult FlutterEngineDeinitialize(FLUTTER_API_SYMBOL(FlutterEngine)
|
||||
engine) {
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
FlutterEngineResult FlutterEngineRunInitialized(
|
||||
FLUTTER_API_SYMBOL(FlutterEngine) engine) {
|
||||
engine->running = true;
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
FlutterEngineResult FlutterEngineSendWindowMetricsEvent(
|
||||
FLUTTER_API_SYMBOL(FlutterEngine) engine,
|
||||
const FlutterWindowMetricsEvent* event) {
|
||||
EXPECT_TRUE(engine->running);
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
FlutterEngineResult FlutterEngineSendPointerEvent(
|
||||
FLUTTER_API_SYMBOL(FlutterEngine) engine,
|
||||
const FlutterPointerEvent* events,
|
||||
size_t events_count) {
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
FLUTTER_EXPORT
|
||||
FlutterEngineResult FlutterEngineSendPlatformMessage(
|
||||
FLUTTER_API_SYMBOL(FlutterEngine) engine,
|
||||
const FlutterPlatformMessage* message) {
|
||||
EXPECT_TRUE(engine->running);
|
||||
|
||||
if (strcmp(message->channel, "test/echo") == 0) {
|
||||
// Responds with the same message received.
|
||||
send_response(engine, message->channel, message->response_handle,
|
||||
message->message, message->message_size);
|
||||
} else if (strcmp(message->channel, "test/send-message") == 0) {
|
||||
// Triggers the engine to send a message.
|
||||
send_response(engine, message->channel, message->response_handle, nullptr,
|
||||
0);
|
||||
send_message(engine, "test/messages", message->message,
|
||||
message->message_size);
|
||||
} else if (strcmp(message->channel, "test/standard-method") == 0) {
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(GBytes) m = g_bytes_new(message->message, message->message_size);
|
||||
g_autofree gchar* name = nullptr;
|
||||
g_autoptr(FlValue) args = nullptr;
|
||||
g_autoptr(GError) error = nullptr;
|
||||
EXPECT_TRUE(fl_method_codec_decode_method_call(FL_METHOD_CODEC(codec), m,
|
||||
&name, &args, &error));
|
||||
EXPECT_EQ(error, nullptr);
|
||||
|
||||
g_autoptr(GBytes) response = nullptr;
|
||||
if (strcmp(name, "Echo") == 0) {
|
||||
// Returns args as a success result.
|
||||
response = fl_method_codec_encode_success_envelope(FL_METHOD_CODEC(codec),
|
||||
args, &error);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
} else if (strcmp(name, "Error") == 0) {
|
||||
// Returns an error result.
|
||||
const gchar* code = nullptr;
|
||||
const gchar* message = nullptr;
|
||||
FlValue* details = nullptr;
|
||||
if (fl_value_get_length(args) >= 2) {
|
||||
FlValue* code_value = fl_value_get_list_value(args, 0);
|
||||
EXPECT_EQ(fl_value_get_type(code_value), FL_VALUE_TYPE_STRING);
|
||||
code = fl_value_get_string(code_value);
|
||||
FlValue* message_value = fl_value_get_list_value(args, 1);
|
||||
message = fl_value_get_type(message_value) == FL_VALUE_TYPE_STRING
|
||||
? fl_value_get_string(message_value)
|
||||
: nullptr;
|
||||
}
|
||||
if (fl_value_get_length(args) >= 3)
|
||||
details = fl_value_get_list_value(args, 2);
|
||||
response = fl_method_codec_encode_error_envelope(
|
||||
FL_METHOD_CODEC(codec), code, message, details, &error);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
} else if (strcmp(name, "InvokeMethod") == 0) {
|
||||
// Gets the engine to call the shell.
|
||||
if (fl_value_get_length(args) == 3) {
|
||||
FlValue* channel_value = fl_value_get_list_value(args, 0);
|
||||
EXPECT_EQ(fl_value_get_type(channel_value), FL_VALUE_TYPE_STRING);
|
||||
const gchar* channel = fl_value_get_string(channel_value);
|
||||
FlValue* name_value = fl_value_get_list_value(args, 1);
|
||||
EXPECT_EQ(fl_value_get_type(name_value), FL_VALUE_TYPE_STRING);
|
||||
const gchar* name = fl_value_get_string(name_value);
|
||||
FlValue* method_args = fl_value_get_list_value(args, 2);
|
||||
invoke_method(engine, channel, name, method_args);
|
||||
}
|
||||
response = fl_method_codec_encode_success_envelope(FL_METHOD_CODEC(codec),
|
||||
nullptr, &error);
|
||||
EXPECT_EQ(error, nullptr);
|
||||
} else {
|
||||
// Returns "not implemented".
|
||||
response = g_bytes_new(nullptr, 0);
|
||||
}
|
||||
|
||||
send_response(
|
||||
engine, message->channel, message->response_handle,
|
||||
static_cast<const uint8_t*>(g_bytes_get_data(response, nullptr)),
|
||||
g_bytes_get_size(response));
|
||||
} else if (strcmp(message->channel, "test/nullptr-response") == 0) {
|
||||
// Sends a null response.
|
||||
send_response(engine, message->channel, message->response_handle, nullptr,
|
||||
0);
|
||||
} else if (strcmp(message->channel, "test/failure") == 0) {
|
||||
// Generates an internal error.
|
||||
return kInternalInconsistency;
|
||||
}
|
||||
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
FlutterEngineResult FlutterPlatformMessageCreateResponseHandle(
|
||||
FLUTTER_API_SYMBOL(FlutterEngine) engine,
|
||||
FlutterDataCallback data_callback,
|
||||
void* user_data,
|
||||
FlutterPlatformMessageResponseHandle** response_out) {
|
||||
EXPECT_TRUE(engine->running);
|
||||
EXPECT_NE(data_callback, nullptr);
|
||||
EXPECT_NE(user_data, nullptr);
|
||||
|
||||
_FlutterPlatformMessageResponseHandle* handle =
|
||||
new _FlutterPlatformMessageResponseHandle(data_callback, user_data);
|
||||
|
||||
*response_out = handle;
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
FlutterEngineResult FlutterPlatformMessageReleaseResponseHandle(
|
||||
FLUTTER_API_SYMBOL(FlutterEngine) engine,
|
||||
FlutterPlatformMessageResponseHandle* response) {
|
||||
EXPECT_NE(engine, nullptr);
|
||||
EXPECT_NE(response, nullptr);
|
||||
|
||||
EXPECT_TRUE(engine->running);
|
||||
|
||||
EXPECT_FALSE(response->released);
|
||||
response->released = true;
|
||||
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
FlutterEngineResult FlutterEngineSendPlatformMessageResponse(
|
||||
FLUTTER_API_SYMBOL(FlutterEngine) engine,
|
||||
const FlutterPlatformMessageResponseHandle* handle,
|
||||
const uint8_t* data,
|
||||
size_t data_length) {
|
||||
EXPECT_NE(engine, nullptr);
|
||||
EXPECT_NE(handle, nullptr);
|
||||
|
||||
EXPECT_TRUE(engine->running);
|
||||
|
||||
// Send a message so the shell can check the responses received.
|
||||
if (handle->channel != "test/responses")
|
||||
send_message(engine, "test/responses", data, data_length);
|
||||
|
||||
EXPECT_FALSE(handle->released);
|
||||
|
||||
delete handle;
|
||||
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
FlutterEngineResult FlutterEngineRunTask(FLUTTER_API_SYMBOL(FlutterEngine)
|
||||
engine,
|
||||
const FlutterTask* task) {
|
||||
EXPECT_NE(engine, nullptr);
|
||||
EXPECT_NE(task, nullptr);
|
||||
EXPECT_NE(task->runner, nullptr);
|
||||
|
||||
FlutterTaskRunner runner = task->runner;
|
||||
EXPECT_NE(runner, nullptr);
|
||||
const FlutterPlatformMessageResponseHandle* response_handle =
|
||||
runner->response_handle;
|
||||
if (response_handle != nullptr) {
|
||||
EXPECT_NE(response_handle->data_callback, nullptr);
|
||||
response_handle->data_callback(runner->message, runner->message_size,
|
||||
response_handle->user_data);
|
||||
} else {
|
||||
_FlutterPlatformMessageResponseHandle* handle =
|
||||
new _FlutterPlatformMessageResponseHandle(runner->channel);
|
||||
|
||||
FlutterPlatformMessage message;
|
||||
message.struct_size = sizeof(FlutterPlatformMessage);
|
||||
message.channel = runner->channel.c_str();
|
||||
message.message = runner->message;
|
||||
message.message_size = runner->message_size;
|
||||
message.response_handle = handle;
|
||||
engine->platform_message_callback(&message, engine->user_data);
|
||||
}
|
||||
|
||||
delete runner;
|
||||
|
||||
return kSuccess;
|
||||
}
|
||||
27
shell/platform/linux/testing/mock_renderer.cc
Normal file
27
shell/platform/linux/testing/mock_renderer.cc
Normal file
@ -0,0 +1,27 @@
|
||||
// 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_renderer.h"
|
||||
|
||||
struct _FlMockRenderer {
|
||||
FlRenderer parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FlMockRenderer, fl_mock_renderer, fl_renderer_get_type())
|
||||
|
||||
// Implements FlRenderer::start
|
||||
static gboolean fl_mock_renderer_start(FlRenderer* renderer, GError** error) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void fl_mock_renderer_class_init(FlMockRendererClass* klass) {
|
||||
FL_RENDERER_CLASS(klass)->start = fl_mock_renderer_start;
|
||||
}
|
||||
|
||||
static void fl_mock_renderer_init(FlMockRenderer* self) {}
|
||||
|
||||
// Creates a stub renderer
|
||||
FlMockRenderer* fl_mock_renderer_new() {
|
||||
return FL_MOCK_RENDERER(g_object_new(fl_mock_renderer_get_type(), nullptr));
|
||||
}
|
||||
17
shell/platform/linux/testing/mock_renderer.h
Normal file
17
shell/platform/linux/testing/mock_renderer.h
Normal file
@ -0,0 +1,17 @@
|
||||
// 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/fl_renderer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_DECLARE_FINAL_TYPE(FlMockRenderer,
|
||||
fl_mock_renderer,
|
||||
FL,
|
||||
MOCK_RENDERER,
|
||||
FlRenderer)
|
||||
|
||||
FlMockRenderer* fl_mock_renderer_new();
|
||||
|
||||
G_END_DECLS
|
||||
Loading…
x
Reference in New Issue
Block a user