text: // 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/cpp/client_wrapper/include/flutter/encodable_value.h"
  
  #include <limits>
  
  #include "gtest/gtest.h"
  
  namespace flutter {
  
  // Verifies that value.type() is |type|, and that of all the Is* methods, only
  // the one that matches the type is true.
  void VerifyType(EncodableValue& value,
                  EncodableValue::EncodableValue::Type type) {
    EXPECT_EQ(value.type(), type);
  
    EXPECT_EQ(value.IsNull(), type == EncodableValue::Type::kNull);
    EXPECT_EQ(value.IsBool(), type == EncodableValue::Type::kBool);
    EXPECT_EQ(value.IsInt(), type == EncodableValue::Type::kInt);
    EXPECT_EQ(value.IsLong(), type == EncodableValue::Type::kLong);
    EXPECT_EQ(value.IsDouble(), type == EncodableValue::Type::kDouble);
    EXPECT_EQ(value.IsString(), type == EncodableValue::Type::kString);
    EXPECT_EQ(value.IsByteList(), type == EncodableValue::Type::kByteList);
    EXPECT_EQ(value.IsIntList(), type == EncodableValue::Type::kIntList);
    EXPECT_EQ(value.IsLongList(), type == EncodableValue::Type::kLongList);
    EXPECT_EQ(value.IsDoubleList(), type == EncodableValue::Type::kDoubleList);
    EXPECT_EQ(value.IsList(), type == EncodableValue::Type::kList);
    EXPECT_EQ(value.IsMap(), type == EncodableValue::Type::kMap);
  }
  
  TEST(EncodableValueTest, Null) {
    EncodableValue value;
    VerifyType(value, EncodableValue::Type::kNull);
  }
  
  TEST(EncodableValueTest, Bool) {
    EncodableValue value(false);
    VerifyType(value, EncodableValue::Type::kBool);
  
    EXPECT_FALSE(value.BoolValue());
    value = true;
    EXPECT_TRUE(value.BoolValue());
  }
  
  TEST(EncodableValueTest, Int) {
    EncodableValue value(42);
    VerifyType(value, EncodableValue::Type::kInt);
  
    EXPECT_EQ(value.IntValue(), 42);
    value = std::numeric_limits<int32_t>::max();
    EXPECT_EQ(value.IntValue(), std::numeric_limits<int32_t>::max());
  }
  
  TEST(EncodableValueTest, LongValueFromInt) {
    EncodableValue value(std::numeric_limits<int32_t>::max());
    EXPECT_EQ(value.LongValue(), std::numeric_limits<int32_t>::max());
  }
  
  TEST(EncodableValueTest, Long) {
    EncodableValue value(INT64_C(42));
    VerifyType(value, EncodableValue::Type::kLong);
  
    EXPECT_EQ(value.LongValue(), 42);
    value = std::numeric_limits<int64_t>::max();
    EXPECT_EQ(value.LongValue(), std::numeric_limits<int64_t>::max());
  }
  
  TEST(EncodableValueTest, Double) {
    EncodableValue value(3.14);
    VerifyType(value, EncodableValue::Type::kDouble);
  
    EXPECT_EQ(value.DoubleValue(), 3.14);
    value = std::numeric_limits<double>::max();
    EXPECT_EQ(value.DoubleValue(), std::numeric_limits<double>::max());
  }
  
  TEST(EncodableValueTest, String) {
    std::string hello("Hello, world!");
    EncodableValue value(hello);
    VerifyType(value, EncodableValue::Type::kString);
  
    EXPECT_EQ(value.StringValue(), hello);
    value = "Goodbye";
    EXPECT_EQ(value.StringValue(), "Goodbye");
  }
  
  TEST(EncodableValueTest, UInt8List) {
    std::vector<uint8_t> data = {0, 2};
    EncodableValue value(data);
    VerifyType(value, EncodableValue::Type::kByteList);
  
    std::vector<uint8_t>& list_value = value.ByteListValue();
    list_value.push_back(std::numeric_limits<uint8_t>::max());
    EXPECT_EQ(list_value[0], 0);
    EXPECT_EQ(list_value[1], 2);
  
    ASSERT_EQ(list_value.size(), 3u);
    EXPECT_EQ(data.size(), 2u);
    EXPECT_EQ(list_value[2], std::numeric_limits<uint8_t>::max());
  }
  
  TEST(EncodableValueTest, Int32List) {
    std::vector<int32_t> data = {-10, 2};
    EncodableValue value(data);
    VerifyType(value, EncodableValue::Type::kIntList);
  
    std::vector<int32_t>& list_value = value.IntListValue();
    list_value.push_back(std::numeric_limits<int32_t>::max());
    EXPECT_EQ(list_value[0], -10);
    EXPECT_EQ(list_value[1], 2);
  
    ASSERT_EQ(list_value.size(), 3u);
    EXPECT_EQ(data.size(), 2u);
    EXPECT_EQ(list_value[2], std::numeric_limits<int32_t>::max());
  }
  
  TEST(EncodableValueTest, Int64List) {
    std::vector<int64_t> data = {-10, 2};
    EncodableValue value(data);
    VerifyType(value, EncodableValue::Type::kLongList);
  
    std::vector<int64_t>& list_value = value.LongListValue();
    list_value.push_back(std::numeric_limits<int64_t>::max());
    EXPECT_EQ(list_value[0], -10);
    EXPECT_EQ(list_value[1], 2);
  
    ASSERT_EQ(list_value.size(), 3u);
    EXPECT_EQ(data.size(), 2u);
    EXPECT_EQ(list_value[2], std::numeric_limits<int64_t>::max());
  }
  
  TEST(EncodableValueTest, DoubleList) {
    std::vector<double> data = {-10.0, 2.0};
    EncodableValue value(data);
    VerifyType(value, EncodableValue::Type::kDoubleList);
  
    std::vector<double>& list_value = value.DoubleListValue();
    list_value.push_back(std::numeric_limits<double>::max());
    EXPECT_EQ(list_value[0], -10.0);
    EXPECT_EQ(list_value[1], 2.0);
  
    ASSERT_EQ(list_value.size(), 3u);
    EXPECT_EQ(data.size(), 2u);
    EXPECT_EQ(list_value[2], std::numeric_limits<double>::max());
  }
  
  TEST(EncodableValueTest, List) {
    EncodableList encodables = {
        EncodableValue(1),
        EncodableValue(2.0),
        EncodableValue("Three"),
    };
    EncodableValue value(encodables);
    VerifyType(value, EncodableValue::Type::kList);
  
    EncodableList& list_value = value.ListValue();
    EXPECT_EQ(list_value[0].IntValue(), 1);
    EXPECT_EQ(list_value[1].DoubleValue(), 2.0);
    EXPECT_EQ(list_value[2].StringValue(), "Three");
  
    // Ensure that it's a modifiable copy of the original array.
    list_value.push_back(EncodableValue(true));
    ASSERT_EQ(list_value.size(), 4u);
    EXPECT_EQ(encodables.size(), 3u);
    EXPECT_EQ(value.ListValue()[3].BoolValue(), true);
  }
  
  TEST(EncodableValueTest, Map) {
    EncodableMap encodables = {
        {EncodableValue(), EncodableValue(std::vector<int32_t>{1, 2, 3})},
        {EncodableValue(1), EncodableValue(INT64_C(10000))},
        {EncodableValue("two"), EncodableValue(7)},
    };
    EncodableValue value(encodables);
    VerifyType(value, EncodableValue::Type::kMap);
  
    EncodableMap& map_value = value.MapValue();
    EXPECT_EQ(map_value[EncodableValue()].IsIntList(), true);
    EXPECT_EQ(map_value[EncodableValue(1)].LongValue(), INT64_C(10000));
    EXPECT_EQ(map_value[EncodableValue("two")].IntValue(), 7);
  
    // Ensure that it's a modifiable copy of the original map.
    map_value[EncodableValue(true)] = EncodableValue(false);
    ASSERT_EQ(map_value.size(), 4u);
    EXPECT_EQ(encodables.size(), 3u);
    EXPECT_EQ(map_value[EncodableValue(true)].BoolValue(), false);
  }
  
  TEST(EncodableValueTest, EmptyTypeConstructor) {
    EXPECT_TRUE(EncodableValue(EncodableValue::Type::kNull).IsNull());
    EXPECT_EQ(EncodableValue(EncodableValue::Type::kBool).BoolValue(), false);
    EXPECT_EQ(EncodableValue(EncodableValue::Type::kInt).IntValue(), 0);
    EXPECT_EQ(EncodableValue(EncodableValue::Type::kLong).LongValue(),
              INT64_C(0));
    EXPECT_EQ(EncodableValue(EncodableValue::Type::kDouble).DoubleValue(), 0.0);
    EXPECT_EQ(EncodableValue(EncodableValue::Type::kString).StringValue().size(),
              0u);
    EXPECT_EQ(
        EncodableValue(EncodableValue::Type::kByteList).ByteListValue().size(),
        0u);
    EXPECT_EQ(
        EncodableValue(EncodableValue::Type::kIntList).IntListValue().size(), 0u);
    EXPECT_EQ(
        EncodableValue(EncodableValue::Type::kLongList).LongListValue().size(),
        0u);
    EXPECT_EQ(EncodableValue(EncodableValue::Type::kDoubleList)
                  .DoubleListValue()
                  .size(),
              0u);
    EXPECT_EQ(EncodableValue(EncodableValue::Type::kList).ListValue().size(), 0u);
    EXPECT_EQ(EncodableValue(EncodableValue::Type::kMap).MapValue().size(), 0u);
  }
  
  // Tests that the < operator meets the requirements of using EncodableValue as
  // a map key.
  TEST(EncodableValueTest, Comparison) {
    EncodableList values = {
        // Null
        EncodableValue(),
        // Bool
        EncodableValue(true),
        EncodableValue(false),
        // Int
        EncodableValue(-7),
        EncodableValue(0),
        EncodableValue(100),
        // Long
        EncodableValue(INT64_C(-7)),
        EncodableValue(INT64_C(0)),
        EncodableValue(INT64_C(100)),
        // Double
        EncodableValue(-7.0),
        EncodableValue(0.0),
        EncodableValue(100.0),
        // String
        EncodableValue("one"),
        EncodableValue("two"),
        // ByteList
        EncodableValue(std::vector<uint8_t>{0, 1}),
        EncodableValue(std::vector<uint8_t>{0, 10}),
        // IntList
        EncodableValue(std::vector<int32_t>{0, 1}),
        EncodableValue(std::vector<int32_t>{0, 100}),
        // LongList
        EncodableValue(std::vector<int64_t>{0, INT64_C(1)}),
        EncodableValue(std::vector<int64_t>{0, INT64_C(100)}),
        // DoubleList
        EncodableValue(std::vector<int64_t>{0, INT64_C(1)}),
        EncodableValue(std::vector<int64_t>{0, INT64_C(100)}),
        // List
        EncodableValue(EncodableList{EncodableValue(), EncodableValue(true)}),
        EncodableValue(EncodableList{EncodableValue(), EncodableValue(1.0)}),
        // Map
        EncodableValue(EncodableMap{{EncodableValue(), EncodableValue(true)},
                                    {EncodableValue(7), EncodableValue(7.0)}}),
        EncodableValue(
            EncodableMap{{EncodableValue(), EncodableValue(1.0)},
                         {EncodableValue("key"), EncodableValue("value")}}),
    };
  
    for (size_t i = 0; i < values.size(); ++i) {
      const auto& a = values[i];
      for (size_t j = 0; j < values.size(); ++j) {
        const auto& b = values[j];
        if (i == j) {
          // Identical objects should always be equal.
          EXPECT_FALSE(a < b);
          EXPECT_FALSE(b < a);
        } else {
          // All other comparisons should be consistent, but the direction doesn't
          // matter.
          EXPECT_NE(a < b, b < a);
        }
      }
  
      // Different non-collection objects with the same value should be equal;
      // different collections should always be unequal regardless of contents.
      bool is_collection = a.IsByteList() || a.IsIntList() || a.IsLongList() ||
                           a.IsDoubleList() || a.IsList() || a.IsMap();
      EncodableValue copy(a);
      bool is_equal = !(a < copy || copy < a);
      EXPECT_EQ(is_equal, !is_collection);
    }
  }
  
  // Tests that structures are deep-copied.
  TEST(EncodableValueTest, DeepCopy) {
    EncodableList encodables = {
        EncodableValue(EncodableMap{
            {EncodableValue(), EncodableValue(std::vector<int32_t>{1, 2, 3})},
            {EncodableValue(1), EncodableValue(INT64_C(0000))},
            {EncodableValue("two"), EncodableValue(7)},
        }),
        EncodableValue(EncodableList{
            EncodableValue(),
            EncodableValue(),
            EncodableValue(
                EncodableMap{{EncodableValue("a"), EncodableValue("b")}}),
        }),
    };
  
    EncodableValue value(encodables);
    ASSERT_TRUE(value.IsList());
  
    // Spot-check innermost collection values.
    EXPECT_EQ(value.ListValue()[0].MapValue()[EncodableValue("two")].IntValue(),
              7);
    EXPECT_EQ(value.ListValue()[1]
                  .ListValue()[2]
                  .MapValue()[EncodableValue("a")]
                  .StringValue(),
              "b");
  
    // Modify those values in the original structure.
    encodables[0].MapValue()[EncodableValue("two")] = EncodableValue();
    encodables[1].ListValue()[2].MapValue()[EncodableValue("a")] = 99;
  
    // Re-check innermost collection values to ensure that they haven't changed.
    EXPECT_EQ(value.ListValue()[0].MapValue()[EncodableValue("two")].IntValue(),
              7);
    EXPECT_EQ(value.ListValue()[1]
                  .ListValue()[2]
                  .MapValue()[EncodableValue("a")]
                  .StringValue(),
              "b");
  }
  
  }  // namespace flutter
  