blob: 5c1616f0dff54cfa6804cacd4a27024bab7e96cf [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/encodable_value.h"
#include <limits>
#include "gtest/gtest.h"
namespace flutter {
TEST(EncodableValueTest, Null) {
EncodableValue value;
value.IsNull();
}
TEST(EncodableValueTest, Bool) {
EncodableValue value(false);
EXPECT_FALSE(std::get<bool>(value));
value = true;
EXPECT_TRUE(std::get<bool>(value));
}
TEST(EncodableValueTest, Int) {
EncodableValue value(42);
EXPECT_EQ(std::get<int32_t>(value), 42);
value = std::numeric_limits<int32_t>::max();
EXPECT_EQ(std::get<int32_t>(value), std::numeric_limits<int32_t>::max());
}
// Test the int/long convenience wrapper.
TEST(EncodableValueTest, LongValue) {
const EncodableValue int_value(std::numeric_limits<int32_t>::max());
EXPECT_EQ(int_value.LongValue(), std::numeric_limits<int32_t>::max());
const EncodableValue long_value(std::numeric_limits<int64_t>::max());
EXPECT_EQ(long_value.LongValue(), std::numeric_limits<int64_t>::max());
}
TEST(EncodableValueTest, Long) {
EncodableValue value(INT64_C(42));
EXPECT_EQ(std::get<int64_t>(value), 42);
value = std::numeric_limits<int64_t>::max();
EXPECT_EQ(std::get<int64_t>(value), std::numeric_limits<int64_t>::max());
}
TEST(EncodableValueTest, Double) {
EncodableValue value(3.14);
EXPECT_EQ(std::get<double>(value), 3.14);
value = std::numeric_limits<double>::max();
EXPECT_EQ(std::get<double>(value), std::numeric_limits<double>::max());
}
TEST(EncodableValueTest, String) {
std::string hello("Hello, world!");
EncodableValue value(hello);
EXPECT_EQ(std::get<std::string>(value), hello);
value = std::string("Goodbye");
EXPECT_EQ(std::get<std::string>(value), "Goodbye");
}
// Explicitly verify that the overrides to prevent char*->bool conversions work.
TEST(EncodableValueTest, CString) {
const char* hello = "Hello, world!";
EncodableValue value(hello);
EXPECT_EQ(std::get<std::string>(value), hello);
value = "Goodbye";
EXPECT_EQ(std::get<std::string>(value), "Goodbye");
}
TEST(EncodableValueTest, UInt8List) {
std::vector<uint8_t> data = {0, 2};
EncodableValue value(data);
auto& list_value = std::get<std::vector<uint8_t>>(value);
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);
auto& list_value = std::get<std::vector<int32_t>>(value);
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);
auto& list_value = std::get<std::vector<int64_t>>(value);
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);
auto& list_value = std::get<std::vector<double>>(value);
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);
auto& list_value = std::get<EncodableList>(value);
EXPECT_EQ(std::get<int32_t>(list_value[0]), 1);
EXPECT_EQ(std::get<double>(list_value[1]), 2.0);
EXPECT_EQ(std::get<std::string>(list_value[2]), "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(std::get<bool>(std::get<EncodableList>(value)[3]), 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);
auto& map_value = std::get<EncodableMap>(value);
EXPECT_EQ(
std::holds_alternative<std::vector<int32_t>>(map_value[EncodableValue()]),
true);
EXPECT_EQ(std::get<int64_t>(map_value[EncodableValue(1)]), INT64_C(10000));
EXPECT_EQ(std::get<int32_t>(map_value[EncodableValue("two")]), 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(std::get<bool>(map_value[EncodableValue(true)]), false);
}
// 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<double>{0, INT64_C(1)}),
EncodableValue(std::vector<double>{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")}}),
// FloatList
EncodableValue(std::vector<float>{0, 1}),
EncodableValue(std::vector<float>{0, 100}),
};
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) << "Indexes: " << i << ", " << j;
}
}
// Copies should always be equal.
EncodableValue copy(a);
EXPECT_FALSE(a < copy || copy < a);
}
}
// Tests that structures are deep-copied.
TEST(EncodableValueTest, DeepCopy) {
EncodableList original = {
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 copy(original);
ASSERT_TRUE(std::holds_alternative<EncodableList>(copy));
// Spot-check innermost collection values.
auto& root_list = std::get<EncodableList>(copy);
auto& first_child = std::get<EncodableMap>(root_list[0]);
EXPECT_EQ(std::get<int32_t>(first_child[EncodableValue("two")]), 7);
auto& second_child = std::get<EncodableList>(root_list[1]);
auto& innermost_map = std::get<EncodableMap>(second_child[2]);
EXPECT_EQ(std::get<std::string>(innermost_map[EncodableValue("a")]), "b");
// Modify those values in the original structure.
first_child[EncodableValue("two")] = EncodableValue();
innermost_map[EncodableValue("a")] = 99;
// Re-check innermost collection values of the original to ensure that they
// haven't changed.
first_child = std::get<EncodableMap>(original[0]);
EXPECT_EQ(std::get<int32_t>(first_child[EncodableValue("two")]), 7);
second_child = std::get<EncodableList>(original[1]);
innermost_map = std::get<EncodableMap>(second_child[2]);
EXPECT_EQ(std::get<std::string>(innermost_map[EncodableValue("a")]), "b");
}
// Simple class for testing custom encodable values
class TestCustomValue {
public:
TestCustomValue() : x_(0), y_(0) {}
TestCustomValue(int x, int y) : x_(x), y_(y) {}
~TestCustomValue() = default;
int x() const { return x_; }
int y() const { return y_; }
private:
int x_;
int y_;
};
TEST(EncodableValueTest, TypeIndexesCorrect) {
// Null
EXPECT_EQ(EncodableValue().index(), 0u);
// Bool
EXPECT_EQ(EncodableValue(true).index(), 1u);
// Int32
EXPECT_EQ(EncodableValue(100).index(), 2u);
// Int64
EXPECT_EQ(EncodableValue(INT64_C(100)).index(), 3u);
// Double
EXPECT_EQ(EncodableValue(7.0).index(), 4u);
// String
EXPECT_EQ(EncodableValue("one").index(), 5u);
// ByteList
EXPECT_EQ(EncodableValue(std::vector<uint8_t>()).index(), 6u);
// IntList
EXPECT_EQ(EncodableValue(std::vector<int32_t>()).index(), 7u);
// LongList
EXPECT_EQ(EncodableValue(std::vector<int64_t>()).index(), 8u);
// DoubleList
EXPECT_EQ(EncodableValue(std::vector<double>()).index(), 9u);
// List
EXPECT_EQ(EncodableValue(EncodableList()).index(), 10u);
// Map
EXPECT_EQ(EncodableValue(EncodableMap()).index(), 11u);
// Custom type
TestCustomValue customValue;
EXPECT_EQ(((EncodableValue)CustomEncodableValue(customValue)).index(), 12u);
// FloatList
EXPECT_EQ(EncodableValue(std::vector<float>()).index(), 13u);
} // namespace flutter
} // namespace flutter