2 * Copyright 2015 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <folly/dynamic.h>
19 #include <boost/next_prior.hpp>
20 #include <gflags/gflags.h>
21 #include <gtest/gtest.h>
25 // This test runs without any external dependencies, including json.
26 // This means that if there's a test failure, there's no way to print
27 // a useful runtime representation of the folly::dynamic. We will
28 // live with this in order to test dependencies. This method is
29 // normally provided by json.cpp.
30 void dynamic::print_as_pseudo_json(std::ostream& out) const {
31 out << "<folly::dynamic object of type " << type_ << ">";
34 TEST(Dynamic, ObjectBasics) {
35 dynamic obj = dynamic::object("a", false);
36 EXPECT_EQ(obj.at("a"), false);
37 EXPECT_EQ(obj.size(), 1);
38 obj.insert("a", true);
39 EXPECT_EQ(obj.size(), 1);
40 EXPECT_EQ(obj.at("a"), true);
41 obj.at("a") = nullptr;
42 EXPECT_EQ(obj.size(), 1);
43 EXPECT_TRUE(obj.at("a") == nullptr);
45 dynamic newObject = dynamic::object;
48 EXPECT_EQ(newObject.size(), 1);
49 newObject["a"] = true;
50 EXPECT_EQ(newObject.size(), 2);
52 EXPECT_EQ(*newObject.keys().begin(), newObject.items().begin()->first);
53 EXPECT_EQ(*newObject.values().begin(), newObject.items().begin()->second);
54 std::vector<std::pair<folly::fbstring, dynamic>> found;
55 found.push_back(std::make_pair(
56 newObject.keys().begin()->asString(),
57 *newObject.values().begin()));
59 EXPECT_EQ(*boost::next(newObject.keys().begin()),
60 boost::next(newObject.items().begin())->first);
61 EXPECT_EQ(*boost::next(newObject.values().begin()),
62 boost::next(newObject.items().begin())->second);
63 found.push_back(std::make_pair(
64 boost::next(newObject.keys().begin())->asString(),
65 *boost::next(newObject.values().begin())));
67 std::sort(found.begin(), found.end());
69 EXPECT_EQ("a", found[0].first);
70 EXPECT_TRUE(found[0].second.asBool());
72 EXPECT_EQ("z", found[1].first);
73 EXPECT_EQ(12, found[1].second.asInt());
75 dynamic obj2 = dynamic::object;
76 EXPECT_TRUE(obj2.isObject());
79 EXPECT_TRUE(d3 == nullptr);
81 EXPECT_TRUE(d3.isObject());
82 d3["foo"] = { 1, 2, 3 };
83 EXPECT_EQ(d3.count("foo"), 1);
86 EXPECT_EQ(d3.at(123), 321);
89 EXPECT_EQ(d3.at("123"), 42);
90 EXPECT_EQ(d3.at(123), 321);
92 dynamic objInsert = folly::dynamic::object();
93 dynamic objA = folly::dynamic::object("1", "2");
94 dynamic objB = folly::dynamic::object("1", "2");
96 objInsert.insert("1", std::move(objA));
97 objInsert.insert("1", std::move(objB));
99 EXPECT_EQ(objInsert.find("1")->second.size(), 1);
101 // We don't allow objects as keys in objects.
102 EXPECT_ANY_THROW(newObject[d3] = 12);
105 TEST(Dynamic, ObjectErase) {
106 dynamic obj = dynamic::object("key1", "val")
108 EXPECT_EQ(obj.count("key1"), 1);
109 EXPECT_EQ(obj.count("key2"), 1);
110 EXPECT_EQ(obj.erase("key1"), 1);
111 EXPECT_EQ(obj.count("key1"), 0);
112 EXPECT_EQ(obj.count("key2"), 1);
113 EXPECT_EQ(obj.erase("key1"), 0);
115 EXPECT_EQ(obj.count("key1"), 1);
116 EXPECT_EQ(obj.count("key2"), 1);
117 auto it = obj.find("key2");
119 EXPECT_EQ(obj.count("key1"), 1);
120 EXPECT_EQ(obj.count("key2"), 0);
124 EXPECT_EQ(obj.size(), 3);
125 auto ret = obj.erase(boost::next(obj.items().begin()), obj.items().end());
126 EXPECT_TRUE(ret == obj.items().end());
127 EXPECT_EQ(obj.size(), 1);
128 obj.erase(obj.items().begin());
129 EXPECT_TRUE(obj.empty());
132 TEST(Dynamic, ArrayErase) {
133 dynamic arr = { 1, 2, 3, 4, 5, 6 };
135 EXPECT_THROW(arr.erase(1), std::exception);
136 EXPECT_EQ(arr.size(), 6);
137 EXPECT_EQ(arr[0], 1);
138 arr.erase(arr.begin());
139 EXPECT_EQ(arr.size(), 5);
141 arr.erase(boost::next(arr.begin()), boost::prior(arr.end()));
142 EXPECT_EQ(arr.size(), 2);
143 EXPECT_EQ(arr[0], 2);
144 EXPECT_EQ(arr[1], 6);
147 TEST(Dynamic, StringBasics) {
148 dynamic str = "hello world";
149 EXPECT_EQ(11, str.size());
150 EXPECT_FALSE(str.empty());
152 EXPECT_TRUE(str.empty());
155 TEST(Dynamic, ArrayBasics) {
156 dynamic array = { 1, 2, 3 };
157 EXPECT_EQ(array.size(), 3);
158 EXPECT_EQ(array.at(0), 1);
159 EXPECT_EQ(array.at(1), 2);
160 EXPECT_EQ(array.at(2), 3);
162 EXPECT_ANY_THROW(array.at(3));
164 array.push_back("foo");
165 EXPECT_EQ(array.size(), 4);
167 array.resize(12, "something");
168 EXPECT_EQ(array.size(), 12);
169 EXPECT_EQ(array[11], "something");
172 TEST(Dynamic, DeepCopy) {
173 dynamic val = { "foo", "bar", { "foo1", "bar1" } };
174 EXPECT_EQ(val.at(2).at(0), "foo1");
175 EXPECT_EQ(val.at(2).at(1), "bar1");
177 EXPECT_EQ(val2.at(2).at(0), "foo1");
178 EXPECT_EQ(val2.at(2).at(1), "bar1");
179 EXPECT_EQ(val.at(2).at(0), "foo1");
180 EXPECT_EQ(val.at(2).at(1), "bar1");
181 val2.at(2).at(0) = "foo3";
182 val2.at(2).at(1) = "bar3";
183 EXPECT_EQ(val.at(2).at(0), "foo1");
184 EXPECT_EQ(val.at(2).at(1), "bar1");
185 EXPECT_EQ(val2.at(2).at(0), "foo3");
186 EXPECT_EQ(val2.at(2).at(1), "bar3");
188 dynamic obj = dynamic::object("a", "b")
189 ("c", {"d", "e", "f"})
191 EXPECT_EQ(obj.at("a"), "b");
193 obj2.at("a") = {1, 2, 3};
194 EXPECT_EQ(obj.at("a"), "b");
195 dynamic expected = {1, 2, 3};
196 EXPECT_EQ(obj2.at("a"), expected);
199 TEST(Dynamic, Operator) {
202 dynamic d1 = dynamic::object;
203 dynamic d2 = dynamic::object;
205 } catch (std::exception const& e) {
212 dynamic sum = foo + bar;
213 EXPECT_EQ(sum, "asdbar");
217 dynamic math = some / nums;
221 TEST(Dynamic, Conversions) {
222 dynamic str = "12.0";
223 EXPECT_EQ(str.asDouble(), 12.0);
224 EXPECT_ANY_THROW(str.asInt());
225 EXPECT_ANY_THROW(str.asBool());
228 EXPECT_EQ(str.asInt(), 12);
229 EXPECT_EQ(str.asDouble(), 12.0);
231 EXPECT_EQ(str.asBool(), false);
232 EXPECT_EQ(str.asInt(), 0);
233 EXPECT_EQ(str.asDouble(), 0);
234 EXPECT_EQ(str.asString(), "0");
237 EXPECT_EQ("12", num.asString());
238 EXPECT_EQ(12.0, num.asDouble());
241 TEST(Dynamic, GetSetDefaultTest) {
242 dynamic d1 = dynamic::object("foo", "bar");
243 EXPECT_EQ(d1.getDefault("foo", "baz"), "bar");
244 EXPECT_EQ(d1.getDefault("quux", "baz"), "baz");
246 dynamic d2 = dynamic::object("foo", "bar");
247 EXPECT_EQ(d2.setDefault("foo", "quux"), "bar");
248 d2.setDefault("bar", dynamic({})).push_back(42);
249 EXPECT_EQ(d2["bar"][0], 42);
251 dynamic d3 = dynamic::object, empty = dynamic::object;
252 EXPECT_EQ(d3.getDefault("foo"), empty);
253 d3.setDefault("foo")["bar"] = "baz";
254 EXPECT_EQ(d3["foo"]["bar"], "baz");
256 // we do not allow getDefault/setDefault on arrays
257 dynamic d4 = dynamic({});
258 EXPECT_ANY_THROW(d4.getDefault("foo", "bar"));
259 EXPECT_ANY_THROW(d4.setDefault("foo", "bar"));
262 TEST(Dynamic, ObjectForwarding) {
263 // Make sure dynamic::object can be constructed the same way as any
265 dynamic d = dynamic::object("asd", {"foo", "bar"});
266 dynamic d2 = dynamic::object("key2", {"value", "words"})
270 TEST(Dynamic, GetPtr) {
271 dynamic array = { 1, 2, "three" };
272 EXPECT_TRUE(array.get_ptr(0));
273 EXPECT_FALSE(array.get_ptr(3));
274 EXPECT_EQ(dynamic("three"), *array.get_ptr(2));
275 const dynamic& carray = array;
276 EXPECT_EQ(dynamic("three"), *carray.get_ptr(2));
278 dynamic object = dynamic::object("one", 1)("two", 2);
279 EXPECT_TRUE(object.get_ptr("one"));
280 EXPECT_FALSE(object.get_ptr("three"));
281 EXPECT_EQ(dynamic(2), *object.get_ptr("two"));
282 *object.get_ptr("one") = 11;
283 EXPECT_EQ(dynamic(11), *object.get_ptr("one"));
284 const dynamic& cobject = object;
285 EXPECT_EQ(dynamic(2), *cobject.get_ptr("two"));
288 TEST(Dynamic, Assignment) {
289 const dynamic ds[] = { { 1, 2, 3 },
290 dynamic::object("a", true),
295 const dynamic dd[] = { { 5, 6 },
296 dynamic::object("t", "T")(1, 7),
301 for (const auto& source : ds) {
302 for (const auto& dest : dd) {
304 EXPECT_EQ(tmp, dest);
306 EXPECT_EQ(tmp, source);
311 int main(int argc, char** argv) {
312 testing::InitGoogleTest(&argc, argv);
313 gflags::ParseCommandLineFlags(&argc, &argv, true);
314 return RUN_ALL_TESTS();