| // 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/public/flutter_linux/fl_method_codec.h" |
| |
| #include <cstring> |
| |
| #include "flutter/shell/platform/linux/fl_method_codec_private.h" |
| #include "flutter/shell/platform/linux/public/flutter_linux/fl_message_codec.h" |
| #include "gtest/gtest.h" |
| |
| G_DECLARE_FINAL_TYPE(FlTestMethodCodec, |
| fl_test_method_codec, |
| FL, |
| TEST_METHOD_CODEC, |
| FlMethodCodec) |
| |
| // Implement the FlMethodCodec API for the following tests to check it works as |
| // expected. |
| struct _FlTestMethodCodec { |
| FlMethodCodec parent_instance; |
| }; |
| |
| G_DEFINE_TYPE(FlTestMethodCodec, |
| fl_test_method_codec, |
| fl_method_codec_get_type()) |
| |
| // Helper function to convert binary data to text. |
| static gchar* message_to_text(GBytes* message) { |
| size_t data_length; |
| const gchar* data = |
| static_cast<const gchar*>(g_bytes_get_data(message, &data_length)); |
| return g_strndup(data, data_length); |
| } |
| |
| // Helper function to convert text to binary data. |
| static GBytes* text_to_message(const gchar* text) { |
| return g_bytes_new(text, strlen(text)); |
| } |
| |
| // Implements FlMethodCodec::encode_method_call. |
| static GBytes* fl_test_codec_encode_method_call(FlMethodCodec* codec, |
| const gchar* name, |
| FlValue* args, |
| GError** error) { |
| EXPECT_TRUE(FL_IS_TEST_METHOD_CODEC(codec)); |
| |
| g_autofree gchar* text = nullptr; |
| if (args == nullptr || fl_value_get_type(args) == FL_VALUE_TYPE_NULL) { |
| text = g_strdup_printf("%s()", name); |
| } else if (fl_value_get_type(args) == FL_VALUE_TYPE_INT) { |
| text = g_strdup_printf("%s(%" G_GINT64_FORMAT ")", name, |
| fl_value_get_int(args)); |
| } else { |
| g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED, |
| "ERROR"); |
| return nullptr; |
| } |
| |
| return text_to_message(text); |
| } |
| |
| // Implements FlMethodCodec::decode_method_call. |
| static gboolean fl_test_codec_decode_method_call(FlMethodCodec* codec, |
| GBytes* message, |
| gchar** name, |
| FlValue** args, |
| GError** error) { |
| EXPECT_TRUE(FL_IS_TEST_METHOD_CODEC(codec)); |
| |
| g_autofree gchar* m = message_to_text(message); |
| |
| if (strcmp(m, "error") == 0) { |
| g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED, |
| "ERROR"); |
| return FALSE; |
| } else { |
| *name = g_strdup(m); |
| *args = fl_value_new_null(); |
| return TRUE; |
| } |
| } |
| |
| // Implements FlMethodCodec::encode_success_envelope. |
| static GBytes* fl_test_codec_encode_success_envelope(FlMethodCodec* codec, |
| FlValue* result, |
| GError** error) { |
| EXPECT_TRUE(FL_IS_TEST_METHOD_CODEC(codec)); |
| |
| g_autofree gchar* text = nullptr; |
| if (result == nullptr || fl_value_get_type(result) == FL_VALUE_TYPE_NULL) { |
| text = g_strdup("(null)"); |
| } else if (fl_value_get_type(result) == FL_VALUE_TYPE_INT) { |
| text = g_strdup_printf("%" G_GINT64_FORMAT, fl_value_get_int(result)); |
| } else { |
| g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED, |
| "ERROR"); |
| return nullptr; |
| } |
| |
| return text_to_message(text); |
| } |
| |
| // Implements FlMethodCodec::encode_error_envelope. |
| static GBytes* fl_test_codec_encode_error_envelope(FlMethodCodec* codec, |
| const gchar* code, |
| const gchar* message, |
| FlValue* details, |
| GError** error) { |
| EXPECT_TRUE(FL_IS_TEST_METHOD_CODEC(codec)); |
| |
| if (details != nullptr && fl_value_get_type(details) != FL_VALUE_TYPE_INT) { |
| g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED, |
| "ERROR"); |
| return nullptr; |
| } |
| |
| g_autofree gchar* text = nullptr; |
| if (message == nullptr) { |
| if (details == nullptr || |
| fl_value_get_type(details) == FL_VALUE_TYPE_NULL) { |
| text = g_strdup_printf("Error_%s()", code); |
| } else { |
| text = g_strdup_printf("Error_%s(%" G_GINT64_FORMAT ")", code, |
| fl_value_get_int(details)); |
| } |
| } else { |
| if (details == nullptr || |
| fl_value_get_type(details) == FL_VALUE_TYPE_NULL) { |
| text = g_strdup_printf("Error_%s(%s)", code, message); |
| } else { |
| text = g_strdup_printf("Error_%s(%s,%" G_GINT64_FORMAT ")", code, message, |
| fl_value_get_int(details)); |
| } |
| } |
| |
| return text_to_message(text); |
| } |
| |
| // Implements FlMethodCodec::decode_response. |
| static FlMethodResponse* fl_test_codec_decode_response(FlMethodCodec* codec, |
| GBytes* message, |
| GError** error) { |
| EXPECT_TRUE(FL_IS_TEST_METHOD_CODEC(codec)); |
| |
| g_autofree gchar* m = message_to_text(message); |
| if (strcmp(m, "codec-error") == 0) { |
| g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED, |
| "ERROR"); |
| return nullptr; |
| } else if (strcmp(m, "error") == 0) { |
| g_autoptr(FlValue) details = fl_value_new_int(42); |
| return FL_METHOD_RESPONSE( |
| fl_method_error_response_new("code", "message", details)); |
| } else { |
| g_autoptr(FlValue) result = fl_value_new_string(m); |
| return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); |
| } |
| } |
| |
| static void fl_test_method_codec_class_init(FlTestMethodCodecClass* klass) { |
| FL_METHOD_CODEC_CLASS(klass)->encode_method_call = |
| fl_test_codec_encode_method_call; |
| FL_METHOD_CODEC_CLASS(klass)->decode_method_call = |
| fl_test_codec_decode_method_call; |
| FL_METHOD_CODEC_CLASS(klass)->encode_success_envelope = |
| fl_test_codec_encode_success_envelope; |
| FL_METHOD_CODEC_CLASS(klass)->encode_error_envelope = |
| fl_test_codec_encode_error_envelope; |
| FL_METHOD_CODEC_CLASS(klass)->decode_response = fl_test_codec_decode_response; |
| } |
| |
| static void fl_test_method_codec_init(FlTestMethodCodec* self) {} |
| |
| static FlTestMethodCodec* fl_test_method_codec_new() { |
| return FL_TEST_METHOD_CODEC( |
| g_object_new(fl_test_method_codec_get_type(), nullptr)); |
| } |
| |
| TEST(FlMethodCodecTest, EncodeMethodCall) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(GBytes) message = fl_method_codec_encode_method_call( |
| FL_METHOD_CODEC(codec), "foo", nullptr, &error); |
| EXPECT_EQ(error, nullptr); |
| EXPECT_NE(message, nullptr); |
| |
| g_autofree gchar* message_text = message_to_text(message); |
| EXPECT_STREQ(message_text, "foo()"); |
| } |
| |
| TEST(FlMethodCodecTest, EncodeMethodCallEmptyName) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(GBytes) message = fl_method_codec_encode_method_call( |
| FL_METHOD_CODEC(codec), "", nullptr, &error); |
| EXPECT_EQ(error, nullptr); |
| EXPECT_NE(message, nullptr); |
| |
| g_autofree gchar* message_text = message_to_text(message); |
| EXPECT_STREQ(message_text, "()"); |
| } |
| |
| TEST(FlMethodCodecTest, EncodeMethodCallArgs) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(FlValue) args = fl_value_new_int(42); |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(GBytes) message = fl_method_codec_encode_method_call( |
| FL_METHOD_CODEC(codec), "foo", args, &error); |
| EXPECT_EQ(error, nullptr); |
| EXPECT_NE(message, nullptr); |
| |
| g_autofree gchar* message_text = message_to_text(message); |
| EXPECT_STREQ(message_text, "foo(42)"); |
| } |
| |
| TEST(FlMethodCodecTest, EncodeMethodCallError) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(FlValue) args = fl_value_new_bool(FALSE); |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(GBytes) message = fl_method_codec_encode_method_call( |
| FL_METHOD_CODEC(codec), "foo", args, &error); |
| EXPECT_EQ(message, nullptr); |
| EXPECT_TRUE(g_error_matches(error, FL_MESSAGE_CODEC_ERROR, |
| FL_MESSAGE_CODEC_ERROR_FAILED)); |
| } |
| |
| TEST(FlMethodCodecTest, DecodeMethodCall) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(GBytes) message = text_to_message("foo"); |
| |
| g_autofree gchar* name = nullptr; |
| g_autoptr(FlValue) args = nullptr; |
| g_autoptr(GError) error = nullptr; |
| gboolean result = fl_method_codec_decode_method_call( |
| FL_METHOD_CODEC(codec), message, &name, &args, &error); |
| EXPECT_EQ(error, nullptr); |
| EXPECT_TRUE(result); |
| |
| EXPECT_STREQ(name, "foo"); |
| ASSERT_EQ(fl_value_get_type(args), FL_VALUE_TYPE_NULL); |
| } |
| |
| TEST(FlMethodCodecTest, EncodeSuccessEnvelope) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(FlValue) result = fl_value_new_int(42); |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(GBytes) message = fl_method_codec_encode_success_envelope( |
| FL_METHOD_CODEC(codec), result, &error); |
| EXPECT_EQ(error, nullptr); |
| EXPECT_NE(message, nullptr); |
| |
| g_autofree gchar* message_text = message_to_text(message); |
| EXPECT_STREQ(message_text, "42"); |
| } |
| |
| TEST(FlMethodCodecTest, EncodeSuccessEnvelopeEmpty) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(GBytes) message = fl_method_codec_encode_success_envelope( |
| FL_METHOD_CODEC(codec), nullptr, &error); |
| EXPECT_EQ(error, nullptr); |
| EXPECT_NE(message, nullptr); |
| |
| g_autofree gchar* message_text = message_to_text(message); |
| EXPECT_STREQ(message_text, "(null)"); |
| } |
| |
| TEST(FlMethodCodecTest, EncodeSuccessEnvelopeError) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(FlValue) result = fl_value_new_string("X"); |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(GBytes) message = fl_method_codec_encode_success_envelope( |
| FL_METHOD_CODEC(codec), result, &error); |
| EXPECT_EQ(message, nullptr); |
| EXPECT_TRUE(g_error_matches(error, FL_MESSAGE_CODEC_ERROR, |
| FL_MESSAGE_CODEC_ERROR_FAILED)); |
| } |
| |
| TEST(FlMethodCodecTest, EncodeErrorEnvelopeNoMessageOrDetails) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(GBytes) message = fl_method_codec_encode_error_envelope( |
| FL_METHOD_CODEC(codec), "code", nullptr, nullptr, &error); |
| EXPECT_EQ(error, nullptr); |
| EXPECT_NE(message, nullptr); |
| |
| g_autofree gchar* message_text = message_to_text(message); |
| EXPECT_STREQ(message_text, "Error_code()"); |
| } |
| |
| TEST(FlMethodCodecTest, EncodeErrorEnvelopeMessage) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(GBytes) message = fl_method_codec_encode_error_envelope( |
| FL_METHOD_CODEC(codec), "code", "message", nullptr, &error); |
| EXPECT_EQ(error, nullptr); |
| EXPECT_NE(message, nullptr); |
| |
| g_autofree gchar* message_text = message_to_text(message); |
| EXPECT_STREQ(message_text, "Error_code(message)"); |
| } |
| |
| TEST(FlMethodCodecTest, EncodeErrorEnvelopeDetails) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(FlValue) details = fl_value_new_int(42); |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(GBytes) message = fl_method_codec_encode_error_envelope( |
| FL_METHOD_CODEC(codec), "code", nullptr, details, &error); |
| EXPECT_EQ(error, nullptr); |
| EXPECT_NE(message, nullptr); |
| |
| g_autofree gchar* message_text = message_to_text(message); |
| EXPECT_STREQ(message_text, "Error_code(42)"); |
| } |
| |
| TEST(FlMethodCodecTest, EncodeErrorEnvelopeMessageAndDetails) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(FlValue) details = fl_value_new_int(42); |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(GBytes) message = fl_method_codec_encode_error_envelope( |
| FL_METHOD_CODEC(codec), "code", "message", details, &error); |
| EXPECT_EQ(error, nullptr); |
| EXPECT_NE(message, nullptr); |
| |
| g_autofree gchar* message_text = message_to_text(message); |
| EXPECT_STREQ(message_text, "Error_code(message,42)"); |
| } |
| |
| TEST(FlMethodCodecTest, DecodeResponseSuccess) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(GBytes) message = text_to_message("echo"); |
| |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(FlMethodResponse) response = |
| fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error); |
| EXPECT_EQ(error, nullptr); |
| EXPECT_NE(response, nullptr); |
| ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); |
| FlValue* result = fl_method_success_response_get_result( |
| FL_METHOD_SUCCESS_RESPONSE(response)); |
| ASSERT_NE(result, nullptr); |
| ASSERT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_STRING); |
| EXPECT_STREQ(fl_value_get_string(result), "echo"); |
| } |
| |
| TEST(FlMethodCodecTest, DecodeResponseNotImplemented) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(GBytes) message = g_bytes_new(nullptr, 0); |
| |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(FlMethodResponse) response = |
| fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error); |
| EXPECT_EQ(error, nullptr); |
| EXPECT_NE(response, nullptr); |
| ASSERT_TRUE(FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response)); |
| } |
| |
| TEST(FlMethodCodecTest, DecodeResponseCodecError) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(GBytes) message = text_to_message("codec-error"); |
| |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(FlMethodResponse) response = |
| fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error); |
| EXPECT_TRUE(g_error_matches(error, FL_MESSAGE_CODEC_ERROR, |
| FL_MESSAGE_CODEC_ERROR_FAILED)); |
| EXPECT_EQ(response, nullptr); |
| } |
| |
| TEST(FlMethodCodecTest, DecodeResponseError) { |
| g_autoptr(FlTestMethodCodec) codec = fl_test_method_codec_new(); |
| |
| g_autoptr(GBytes) message = text_to_message("error"); |
| |
| g_autoptr(GError) error = nullptr; |
| g_autoptr(FlMethodResponse) response = |
| fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error); |
| EXPECT_EQ(error, nullptr); |
| EXPECT_NE(response, nullptr); |
| ASSERT_TRUE(FL_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)); |
| ASSERT_NE(details, nullptr); |
| ASSERT_EQ(fl_value_get_type(details), FL_VALUE_TYPE_INT); |
| EXPECT_EQ(fl_value_get_int(details), 42); |
| } |