blob: 82ec96d0f8852bc41b922f863c57f21197d945d9 [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/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