2 * Copyright 2012 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"
18 #include "folly/json.h"
19 #include <gtest/gtest.h>
20 #include <gflags/gflags.h>
21 #include <boost/next_prior.hpp>
22 #include "folly/Benchmark.h"
26 TEST(Dynamic, ObjectBasics) {
27 dynamic obj = dynamic::object("a", false);
28 EXPECT_EQ(obj.at("a"), false);
29 EXPECT_EQ(obj.size(), 1);
30 obj.insert("a", true);
31 EXPECT_EQ(obj.size(), 1);
32 EXPECT_EQ(obj.at("a"), true);
33 obj.at("a") = nullptr;
34 EXPECT_EQ(obj.size(), 1);
35 EXPECT_TRUE(obj.at("a") == nullptr);
37 dynamic newObject = dynamic::object;
40 EXPECT_EQ(newObject.size(), 1);
41 newObject["a"] = true;
42 EXPECT_EQ(newObject.size(), 2);
44 EXPECT_EQ(*newObject.keys().begin(), newObject.items().begin()->first);
45 EXPECT_EQ(*newObject.values().begin(), newObject.items().begin()->second);
46 std::vector<std::pair<folly::fbstring, dynamic>> found;
47 found.push_back(std::make_pair(
48 newObject.keys().begin()->asString(),
49 *newObject.values().begin()));
51 EXPECT_EQ(*boost::next(newObject.keys().begin()),
52 boost::next(newObject.items().begin())->first);
53 EXPECT_EQ(*boost::next(newObject.values().begin()),
54 boost::next(newObject.items().begin())->second);
55 found.push_back(std::make_pair(
56 boost::next(newObject.keys().begin())->asString(),
57 *boost::next(newObject.values().begin())));
59 std::sort(found.begin(), found.end());
61 EXPECT_EQ("a", found[0].first);
62 EXPECT_TRUE(found[0].second.asBool());
64 EXPECT_EQ("z", found[1].first);
65 EXPECT_EQ(12, found[1].second.asInt());
67 dynamic obj2 = dynamic::object;
68 EXPECT_TRUE(obj2.isObject());
71 EXPECT_TRUE(d3 == nullptr);
73 EXPECT_TRUE(d3.isObject());
74 d3["foo"] = { 1, 2, 3 };
75 EXPECT_EQ(d3.count("foo"), 1);
78 EXPECT_EQ(d3.at(123), 321);
81 EXPECT_EQ(d3.at("123"), 42);
82 EXPECT_EQ(d3.at(123), 321);
84 // We don't allow objects as keys in objects.
85 EXPECT_ANY_THROW(newObject[d3] = 12);
88 TEST(Dynamic, ObjectErase) {
89 dynamic obj = dynamic::object("key1", "val")
91 EXPECT_EQ(obj.count("key1"), 1);
92 EXPECT_EQ(obj.count("key2"), 1);
93 EXPECT_EQ(obj.erase("key1"), 1);
94 EXPECT_EQ(obj.count("key1"), 0);
95 EXPECT_EQ(obj.count("key2"), 1);
96 EXPECT_EQ(obj.erase("key1"), 0);
98 EXPECT_EQ(obj.count("key1"), 1);
99 EXPECT_EQ(obj.count("key2"), 1);
100 auto it = obj.find("key2");
102 EXPECT_EQ(obj.count("key1"), 1);
103 EXPECT_EQ(obj.count("key2"), 0);
107 EXPECT_EQ(obj.size(), 3);
108 auto ret = obj.erase(boost::next(obj.items().begin()), obj.items().end());
109 EXPECT_TRUE(ret == obj.items().end());
110 EXPECT_EQ(obj.size(), 1);
111 obj.erase(obj.items().begin());
112 EXPECT_TRUE(obj.empty());
115 TEST(Dynamic, ArrayErase) {
116 dynamic arr = { 1, 2, 3, 4, 5, 6 };
118 EXPECT_THROW(arr.erase(1), std::exception);
119 EXPECT_EQ(arr.size(), 6);
120 EXPECT_EQ(arr[0], 1);
121 arr.erase(arr.begin());
122 EXPECT_EQ(arr.size(), 5);
124 arr.erase(boost::next(arr.begin()), boost::prior(arr.end()));
125 EXPECT_EQ(arr.size(), 2);
126 EXPECT_EQ(arr[0], 2);
127 EXPECT_EQ(arr[1], 6);
130 TEST(Dynamic, StringBasics) {
131 dynamic str = "hello world";
132 EXPECT_EQ(11, str.size());
133 EXPECT_FALSE(str.empty());
135 EXPECT_TRUE(str.empty());
138 TEST(Dynamic, ArrayBasics) {
139 dynamic array = { 1, 2, 3 };
140 EXPECT_EQ(array.size(), 3);
141 EXPECT_EQ(array.at(0), 1);
142 EXPECT_EQ(array.at(1), 2);
143 EXPECT_EQ(array.at(2), 3);
145 EXPECT_ANY_THROW(array.at(3));
147 array.push_back("foo");
148 EXPECT_EQ(array.size(), 4);
150 array.resize(12, "something");
151 EXPECT_EQ(array.size(), 12);
152 EXPECT_EQ(array[11], "something");
155 TEST(Dynamic, DeepCopy) {
156 dynamic val = { "foo", "bar", { "foo1", "bar1" } };
157 EXPECT_EQ(val.at(2).at(0), "foo1");
158 EXPECT_EQ(val.at(2).at(1), "bar1");
160 EXPECT_EQ(val2.at(2).at(0), "foo1");
161 EXPECT_EQ(val2.at(2).at(1), "bar1");
162 EXPECT_EQ(val.at(2).at(0), "foo1");
163 EXPECT_EQ(val.at(2).at(1), "bar1");
164 val2.at(2).at(0) = "foo3";
165 val2.at(2).at(1) = "bar3";
166 EXPECT_EQ(val.at(2).at(0), "foo1");
167 EXPECT_EQ(val.at(2).at(1), "bar1");
168 EXPECT_EQ(val2.at(2).at(0), "foo3");
169 EXPECT_EQ(val2.at(2).at(1), "bar3");
171 dynamic obj = dynamic::object("a", "b")
172 ("c", {"d", "e", "f"})
174 EXPECT_EQ(obj.at("a"), "b");
176 obj2.at("a") = {1, 2, 3};
177 EXPECT_EQ(obj.at("a"), "b");
178 dynamic expected = {1, 2, 3};
179 EXPECT_EQ(obj2.at("a"), expected);
182 TEST(Dynamic, Operator) {
185 dynamic d1 = dynamic::object;
186 dynamic d2 = dynamic::object;
188 } catch (std::exception const& e) {
195 dynamic sum = foo + bar;
196 EXPECT_EQ(sum, "asdbar");
200 dynamic math = some / nums;
204 TEST(Dynamic, Conversions) {
205 dynamic str = "12.0";
206 EXPECT_EQ(str.asDouble(), 12.0);
207 EXPECT_ANY_THROW(str.asInt());
208 EXPECT_ANY_THROW(str.asBool());
211 EXPECT_EQ(str.asInt(), 12);
212 EXPECT_EQ(str.asDouble(), 12.0);
214 EXPECT_EQ(str.asBool(), false);
215 EXPECT_EQ(str.asInt(), 0);
216 EXPECT_EQ(str.asDouble(), 0);
217 EXPECT_EQ(str.asString(), "0");
220 TEST(Dynamic, FormattedIO) {
221 std::ostringstream out;
222 dynamic doubl = 123.33;
224 out << "0x" << std::hex << ++dint << ' ' << std::setprecision(1)
226 EXPECT_EQ(out.str(), "0xd 1e+02\n");
229 dynamic arrr = { 1, 2, 3 };
231 EXPECT_EQ(out.str(), "[1,2,3]");
234 dynamic objy = dynamic::object("a", 12);
236 EXPECT_EQ(out.str(), R"({"a":12})");
239 dynamic objy2 = { objy, dynamic::object(12, "str"),
240 dynamic::object(true, false) };
242 EXPECT_EQ(out.str(), R"([{"a":12},{12:"str"},{true:false}])");
245 TEST(Dynamic, GetSetDefaultTest) {
246 dynamic d1 = dynamic::object("foo", "bar");
247 EXPECT_EQ(d1.getDefault("foo", "baz"), "bar");
248 EXPECT_EQ(d1.getDefault("quux", "baz"), "baz");
250 dynamic d2 = dynamic::object("foo", "bar");
251 EXPECT_EQ(d2.setDefault("foo", "quux"), "bar");
252 d2.setDefault("bar", dynamic({})).push_back(42);
253 EXPECT_EQ(d2["bar"][0], 42);
255 dynamic d3 = dynamic::object, empty = dynamic::object;
256 EXPECT_EQ(d3.getDefault("foo"), empty);
257 d3.setDefault("foo")["bar"] = "baz";
258 EXPECT_EQ(d3["foo"]["bar"], "baz");
260 // we do not allow getDefault/setDefault on arrays
261 dynamic d4 = dynamic({});
262 EXPECT_ANY_THROW(d4.getDefault("foo", "bar"));
263 EXPECT_ANY_THROW(d4.setDefault("foo", "bar"));
266 int main(int argc, char** argv) {
267 testing::InitGoogleTest(&argc, argv);
268 google::ParseCommandLineFlags(&argc, &argv, true);
269 if (FLAGS_benchmark) {
270 folly::runBenchmarks();
272 return RUN_ALL_TESTS();