| // 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/json_method_codec.h" |
| |
| #include "flutter/shell/platform/common/client_wrapper/include/flutter/method_result_functions.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<rapidjson::Document>& a, |
| const MethodCall<rapidjson::Document>& 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; |
| } |
| return *a.arguments() == *b.arguments(); |
| } |
| |
| } // namespace |
| |
| TEST(JsonMethodCodec, HandlesMethodCallsWithNullArguments) { |
| const JsonMethodCodec& codec = JsonMethodCodec::GetInstance(); |
| MethodCall<rapidjson::Document> call("hello", nullptr); |
| auto encoded = codec.EncodeMethodCall(call); |
| ASSERT_TRUE(encoded); |
| std::unique_ptr<MethodCall<rapidjson::Document>> decoded = |
| codec.DecodeMethodCall(*encoded); |
| ASSERT_TRUE(decoded); |
| EXPECT_TRUE(MethodCallsAreEqual(call, *decoded)); |
| } |
| |
| TEST(JsonMethodCodec, HandlesMethodCallsWithArgument) { |
| const JsonMethodCodec& codec = JsonMethodCodec::GetInstance(); |
| |
| auto arguments = std::make_unique<rapidjson::Document>(rapidjson::kArrayType); |
| auto& allocator = arguments->GetAllocator(); |
| arguments->PushBack(42, allocator); |
| arguments->PushBack("world", allocator); |
| MethodCall<rapidjson::Document> call("hello", std::move(arguments)); |
| auto encoded = codec.EncodeMethodCall(call); |
| ASSERT_TRUE(encoded); |
| std::unique_ptr<MethodCall<rapidjson::Document>> decoded = |
| codec.DecodeMethodCall(*encoded); |
| ASSERT_TRUE(decoded); |
| EXPECT_TRUE(MethodCallsAreEqual(call, *decoded)); |
| } |
| |
| TEST(JsonMethodCodec, HandlesSuccessEnvelopesWithNullResult) { |
| const JsonMethodCodec& codec = JsonMethodCodec::GetInstance(); |
| auto encoded = codec.EncodeSuccessEnvelope(); |
| ASSERT_TRUE(encoded); |
| std::vector<uint8_t> bytes = {'[', 'n', 'u', 'l', 'l', ']'}; |
| EXPECT_EQ(*encoded, bytes); |
| |
| bool decoded_successfully = false; |
| MethodResultFunctions<rapidjson::Document> result_handler( |
| [&decoded_successfully](const rapidjson::Document* result) { |
| decoded_successfully = true; |
| EXPECT_EQ(result, nullptr); |
| }, |
| nullptr, nullptr); |
| codec.DecodeAndProcessResponseEnvelope(encoded->data(), encoded->size(), |
| &result_handler); |
| EXPECT_TRUE(decoded_successfully); |
| } |
| |
| TEST(JsonMethodCodec, HandlesSuccessEnvelopesWithResult) { |
| const JsonMethodCodec& codec = JsonMethodCodec::GetInstance(); |
| rapidjson::Document result; |
| result.SetInt(42); |
| auto encoded = codec.EncodeSuccessEnvelope(&result); |
| ASSERT_TRUE(encoded); |
| std::vector<uint8_t> bytes = {'[', '4', '2', ']'}; |
| EXPECT_EQ(*encoded, bytes); |
| |
| bool decoded_successfully = false; |
| MethodResultFunctions<rapidjson::Document> result_handler( |
| [&decoded_successfully](const rapidjson::Document* result) { |
| decoded_successfully = true; |
| EXPECT_EQ(result->GetInt(), 42); |
| }, |
| nullptr, nullptr); |
| codec.DecodeAndProcessResponseEnvelope(encoded->data(), encoded->size(), |
| &result_handler); |
| EXPECT_TRUE(decoded_successfully); |
| } |
| |
| TEST(JsonMethodCodec, HandlesErrorEnvelopesWithNulls) { |
| const JsonMethodCodec& codec = JsonMethodCodec::GetInstance(); |
| auto encoded = codec.EncodeErrorEnvelope("errorCode"); |
| ASSERT_TRUE(encoded); |
| std::vector<uint8_t> bytes = { |
| '[', '"', 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e', |
| '"', ',', '"', '"', ',', 'n', 'u', 'l', 'l', ']', |
| }; |
| EXPECT_EQ(*encoded, bytes); |
| |
| bool decoded_successfully = false; |
| MethodResultFunctions<rapidjson::Document> result_handler( |
| nullptr, |
| [&decoded_successfully](const std::string& code, |
| const std::string& message, |
| const rapidjson::Document* 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(JsonMethodCodec, HandlesErrorEnvelopesWithDetails) { |
| const JsonMethodCodec& codec = JsonMethodCodec::GetInstance(); |
| // NOLINTNEXTLINE(clang-analyzer-core.NullDereference) |
| rapidjson::Document details(rapidjson::kArrayType); |
| auto& allocator = details.GetAllocator(); |
| details.PushBack("a", allocator); |
| details.PushBack(42, allocator); |
| auto encoded = |
| codec.EncodeErrorEnvelope("errorCode", "something failed", &details); |
| ASSERT_NE(encoded.get(), nullptr); |
| std::vector<uint8_t> bytes = { |
| '[', '"', 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e', '"', ',', '"', |
| 's', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', ' ', 'f', 'a', 'i', 'l', |
| 'e', 'd', '"', ',', '[', '"', 'a', '"', ',', '4', '2', ']', ']', |
| }; |
| EXPECT_EQ(*encoded, bytes); |
| |
| bool decoded_successfully = false; |
| MethodResultFunctions<rapidjson::Document> result_handler( |
| nullptr, |
| [&decoded_successfully](const std::string& code, |
| const std::string& message, |
| const rapidjson::Document* details) { |
| decoded_successfully = true; |
| EXPECT_EQ(code, "errorCode"); |
| EXPECT_EQ(message, "something failed"); |
| EXPECT_TRUE(details->IsArray()); |
| EXPECT_EQ(std::string((*details)[0].GetString()), "a"); |
| EXPECT_EQ((*details)[1].GetInt(), 42); |
| }, |
| nullptr); |
| codec.DecodeAndProcessResponseEnvelope(encoded->data(), encoded->size(), |
| &result_handler); |
| EXPECT_TRUE(decoded_successfully); |
| } |
| |
| } // namespace flutter |