1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <string>
6 #include <utility>
7
8 #include "base/test/gtest_util.h"
9 #include "base/values.h"
10 #include "mojo/public/cpp/base/values_mojom_traits.h"
11 #include "mojo/public/cpp/test_support/test_utils.h"
12 #include "mojo/public/mojom/base/values.mojom.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace mojo_base {
16
TEST(ValuesStructTraitsTest,NullValue)17 TEST(ValuesStructTraitsTest, NullValue) {
18 base::Value in;
19 base::Value out;
20 ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Value>(&in, &out));
21 EXPECT_EQ(in, out);
22 }
23
TEST(ValuesStructTraitsTest,BoolValue)24 TEST(ValuesStructTraitsTest, BoolValue) {
25 static constexpr bool kTestCases[] = {true, false};
26 for (auto& test_case : kTestCases) {
27 base::Value in(test_case);
28 base::Value out;
29 ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Value>(&in, &out));
30 EXPECT_EQ(in, out);
31 }
32 }
33
TEST(ValuesStructTraitsTest,IntValue)34 TEST(ValuesStructTraitsTest, IntValue) {
35 static constexpr int kTestCases[] = {0, -1, 1,
36 std::numeric_limits<int>::min(),
37 std::numeric_limits<int>::max()};
38 for (auto& test_case : kTestCases) {
39 base::Value in(test_case);
40 base::Value out;
41 ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Value>(&in, &out));
42 EXPECT_EQ(in, out);
43 }
44 }
45
TEST(ValuesStructTraitsTest,DoubleValue)46 TEST(ValuesStructTraitsTest, DoubleValue) {
47 static constexpr double kTestCases[] = {-0.0,
48 +0.0,
49 -1.0,
50 +1.0,
51 std::numeric_limits<double>::min(),
52 std::numeric_limits<double>::max()};
53 for (auto& test_case : kTestCases) {
54 base::Value in(test_case);
55 base::Value out;
56 ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Value>(&in, &out));
57 EXPECT_EQ(in, out);
58 }
59 }
60
TEST(ValuesStructTraitsTest,StringValue)61 TEST(ValuesStructTraitsTest, StringValue) {
62 static constexpr const char* kTestCases[] = {
63 "", "ascii",
64 // : Unicode FIREWORKS
65 "\xf0\x9f\x8e\x86",
66 };
67 for (auto* test_case : kTestCases) {
68 base::Value in(test_case);
69 base::Value out;
70 ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Value>(&in, &out));
71 EXPECT_EQ(in, out);
72 }
73 }
74
TEST(ValuesStructTraitsTest,BinaryValue)75 TEST(ValuesStructTraitsTest, BinaryValue) {
76 std::vector<char> kBinaryData = {'\x00', '\x80', '\xff', '\x7f', '\x01'};
77 base::Value in(std::move(kBinaryData));
78 base::Value out;
79 ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Value>(&in, &out));
80 EXPECT_EQ(in, out);
81 }
82
TEST(ValuesStructTraitsTest,DictionaryValue)83 TEST(ValuesStructTraitsTest, DictionaryValue) {
84 // Note: here and below, it would be nice to use an initializer list, but
85 // move-only types and initializer lists don't mix. Initializer lists can't be
86 // modified: thus it's not possible to move.
87 std::vector<base::Value::DictStorage::value_type> storage;
88 storage.emplace_back("null", std::make_unique<base::Value>());
89 storage.emplace_back("bool", std::make_unique<base::Value>(false));
90 storage.emplace_back("int", std::make_unique<base::Value>(0));
91 storage.emplace_back("double", std::make_unique<base::Value>(0.0));
92 storage.emplace_back("string", std::make_unique<base::Value>("0"));
93 storage.emplace_back(
94 "binary", std::make_unique<base::Value>(base::Value::BlobStorage({0})));
95 storage.emplace_back(
96 "dictionary", std::make_unique<base::Value>(base::Value::DictStorage()));
97 storage.emplace_back(
98 "list", std::make_unique<base::Value>(base::Value::ListStorage()));
99
100 base::Value in(
101 base::Value::DictStorage(std::move(storage), base::KEEP_LAST_OF_DUPES));
102 base::Value out;
103 ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Value>(&in, &out));
104 EXPECT_EQ(in, out);
105
106 ASSERT_TRUE(
107 mojo::test::SerializeAndDeserialize<mojom::DictionaryValue>(&in, &out));
108 EXPECT_EQ(in, out);
109 }
110
TEST(ValuesStructTraitsTest,SerializeInvalidDictionaryValue)111 TEST(ValuesStructTraitsTest, SerializeInvalidDictionaryValue) {
112 base::Value in;
113 ASSERT_FALSE(in.is_dict());
114
115 base::Value out;
116 EXPECT_DCHECK_DEATH(
117 mojo::test::SerializeAndDeserialize<mojom::DictionaryValue>(&in, &out));
118 }
119
TEST(ValuesStructTraitsTest,ListValue)120 TEST(ValuesStructTraitsTest, ListValue) {
121 base::Value::ListStorage storage;
122 storage.emplace_back();
123 storage.emplace_back(false);
124 storage.emplace_back(0);
125 storage.emplace_back(0.0);
126 storage.emplace_back("0");
127 storage.emplace_back(base::Value::BlobStorage({0}));
128 storage.emplace_back(base::Value::DictStorage());
129 storage.emplace_back(base::Value::ListStorage());
130 base::Value in(std::move(storage));
131 base::Value out;
132 ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Value>(&in, &out));
133 EXPECT_EQ(in, out);
134
135 ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::ListValue>(&in, &out));
136 EXPECT_EQ(in, out);
137 }
138
TEST(ValuesStructTraitsTest,SerializeInvalidListValue)139 TEST(ValuesStructTraitsTest, SerializeInvalidListValue) {
140 base::Value in;
141 ASSERT_FALSE(in.is_dict());
142
143 base::Value out;
144 EXPECT_DCHECK_DEATH(
145 mojo::test::SerializeAndDeserialize<mojom::ListValue>(&in, &out));
146 }
147
148 // A deeply nested base::Value should trigger a deserialization error.
TEST(ValuesStructTraitsTest,DeeplyNestedValue)149 TEST(ValuesStructTraitsTest, DeeplyNestedValue) {
150 base::Value in;
151 for (int i = 0; i < 100; ++i) {
152 base::Value::ListStorage storage;
153 storage.emplace_back(std::move(in));
154 in = base::Value(std::move(storage));
155 }
156 base::Value out;
157 ASSERT_FALSE(mojo::test::SerializeAndDeserialize<mojom::Value>(&in, &out));
158 }
159
160 } // namespace mojo_base
161