blob: a3c2fb43141ec4f078519d7c76a3d929267385c9 [file] [log] [blame]
// 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/common/client_wrapper/include/flutter/standard_method_codec.h"
#include "flutter/shell/platform/common/client_wrapper/include/flutter/method_result_functions.h"
#include "flutter/shell/platform/common/client_wrapper/testing/test_codec_extensions.h"
#include "gtest/gtest.h"
namespace flutter {
namespace {
// Returns true if the given method calls have the same method name, and their
// arguments have equivalent values.
bool MethodCallsAreEqual(const MethodCall<>& a, const MethodCall<>& b) {
if (a.method_name() != b.method_name()) {
return false;
}
// Treat nullptr and Null as equivalent.
if ((!a.arguments() || a.arguments()->IsNull()) &&
(!b.arguments() || b.arguments()->IsNull())) {
return true;
}
// If only one is nullptr, fail early rather than throw below.
if (!a.arguments() || !b.arguments()) {
return false;
}
return *a.arguments() == *b.arguments();
}
} // namespace
TEST(StandardMethodCodec, GetInstanceCachesInstance) {
const StandardMethodCodec& codec_a =
StandardMethodCodec::GetInstance(nullptr);
const StandardMethodCodec& codec_b =
StandardMethodCodec::GetInstance(nullptr);
EXPECT_EQ(&codec_a, &codec_b);
}
TEST(StandardMethodCodec, HandlesMethodCallsWithNullArguments) {
const StandardMethodCodec& codec = StandardMethodCodec::GetInstance();
MethodCall<> call("hello", nullptr);
auto encoded = codec.EncodeMethodCall(call);
ASSERT_NE(encoded.get(), nullptr);
std::unique_ptr<MethodCall<>> decoded = codec.DecodeMethodCall(*encoded);
ASSERT_NE(decoded.get(), nullptr);
EXPECT_TRUE(MethodCallsAreEqual(call, *decoded));
}
TEST(StandardMethodCodec, HandlesMethodCallsWithArgument) {
const StandardMethodCodec& codec = StandardMethodCodec::GetInstance();
MethodCall<> call("hello", std::make_unique<EncodableValue>(EncodableList{
EncodableValue(42),
EncodableValue("world"),
}));
auto encoded = codec.EncodeMethodCall(call);
ASSERT_NE(encoded.get(), nullptr);
std::unique_ptr<MethodCall<>> decoded = codec.DecodeMethodCall(*encoded);
ASSERT_NE(decoded.get(), nullptr);
EXPECT_TRUE(MethodCallsAreEqual(call, *decoded));
}
TEST(StandardMethodCodec, HandlesSuccessEnvelopesWithNullResult) {
const StandardMethodCodec& codec = StandardMethodCodec::GetInstance();
auto encoded = codec.EncodeSuccessEnvelope();
ASSERT_NE(encoded.get(), nullptr);
std::vector<uint8_t> bytes = {0x00, 0x00};
EXPECT_EQ(*encoded, bytes);
bool decoded_successfully = false;
MethodResultFunctions<> result_handler(
[&decoded_successfully](const EncodableValue* result) {
decoded_successfully = true;
EXPECT_EQ(result, nullptr);
},
nullptr, nullptr);
codec.DecodeAndProcessResponseEnvelope(encoded->data(), encoded->size(),
&result_handler);
EXPECT_TRUE(decoded_successfully);
}
TEST(StandardMethodCodec, HandlesSuccessEnvelopesWithResult) {
const StandardMethodCodec& codec = StandardMethodCodec::GetInstance();
EncodableValue result(42);
auto encoded = codec.EncodeSuccessEnvelope(&result);
ASSERT_NE(encoded.get(), nullptr);
std::vector<uint8_t> bytes = {0x00, 0x03, 0x2a, 0x00, 0x00, 0x00};
EXPECT_EQ(*encoded, bytes);
bool decoded_successfully = false;
MethodResultFunctions<> result_handler(
[&decoded_successfully](const EncodableValue* result) {
decoded_successfully = true;
EXPECT_EQ(std::get<int32_t>(*result), 42);
},
nullptr, nullptr);
codec.DecodeAndProcessResponseEnvelope(encoded->data(), encoded->size(),
&result_handler);
EXPECT_TRUE(decoded_successfully);
}
TEST(StandardMethodCodec, HandlesErrorEnvelopesWithNulls) {
const StandardMethodCodec& codec = StandardMethodCodec::GetInstance();
auto encoded = codec.EncodeErrorEnvelope("errorCode");
ASSERT_NE(encoded.get(), nullptr);
std::vector<uint8_t> bytes = {0x01, 0x07, 0x09, 0x65, 0x72, 0x72, 0x6f,
0x72, 0x43, 0x6f, 0x64, 0x65, 0x00, 0x00};
EXPECT_EQ(*encoded, bytes);
bool decoded_successfully = false;
MethodResultFunctions<> result_handler(
nullptr,
[&decoded_successfully](const std::string& code,
const std::string& message,
const EncodableValue* details) {
decoded_successfully = true;
EXPECT_EQ(code, "errorCode");
EXPECT_EQ(message, "");
EXPECT_EQ(details, nullptr);
},
nullptr);
codec.DecodeAndProcessResponseEnvelope(encoded->data(), encoded->size(),
&result_handler);
EXPECT_TRUE(decoded_successfully);
}
TEST(StandardMethodCodec, HandlesErrorEnvelopesWithDetails) {
const StandardMethodCodec& codec = StandardMethodCodec::GetInstance();
EncodableValue details(EncodableList{
EncodableValue("a"),
EncodableValue(42),
});
auto encoded =
codec.EncodeErrorEnvelope("errorCode", "something failed", &details);
ASSERT_NE(encoded.get(), nullptr);
std::vector<uint8_t> bytes = {
0x01, 0x07, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f,
0x64, 0x65, 0x07, 0x10, 0x73, 0x6f, 0x6d, 0x65, 0x74, 0x68,
0x69, 0x6e, 0x67, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64,
0x0c, 0x02, 0x07, 0x01, 0x61, 0x03, 0x2a, 0x00, 0x00, 0x00,
};
EXPECT_EQ(*encoded, bytes);
bool decoded_successfully = false;
MethodResultFunctions<> result_handler(
nullptr,
[&decoded_successfully](const std::string& code,
const std::string& message,
const EncodableValue* details) {
decoded_successfully = true;
EXPECT_EQ(code, "errorCode");
EXPECT_EQ(message, "something failed");
const auto* details_list = std::get_if<EncodableList>(details);
ASSERT_NE(details_list, nullptr);
EXPECT_EQ(std::get<std::string>((*details_list)[0]), "a");
EXPECT_EQ(std::get<int32_t>((*details_list)[1]), 42);
},
nullptr);
codec.DecodeAndProcessResponseEnvelope(encoded->data(), encoded->size(),
&result_handler);
EXPECT_TRUE(decoded_successfully);
}
TEST(StandardMethodCodec, HandlesCustomTypeArguments) {
const StandardMethodCodec& codec = StandardMethodCodec::GetInstance(
&PointExtensionSerializer::GetInstance());
Point point(7, 9);
MethodCall<> call(
"hello", std::make_unique<EncodableValue>(CustomEncodableValue(point)));
auto encoded = codec.EncodeMethodCall(call);
ASSERT_NE(encoded.get(), nullptr);
std::unique_ptr<MethodCall<>> decoded = codec.DecodeMethodCall(*encoded);
ASSERT_NE(decoded.get(), nullptr);
const Point& decoded_point = std::any_cast<Point>(
std::get<CustomEncodableValue>(*decoded->arguments()));
EXPECT_EQ(point, decoded_point);
};
} // namespace flutter