Refactor tests to verify that a single folly target can be used successfully
[folly.git] / folly / test / DynamicTest.cpp
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <folly/dynamic.h>
18
19 #include <boost/next_prior.hpp>
20 #include <gflags/gflags.h>
21 #include <gtest/gtest.h>
22
23 using folly::dynamic;
24
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_ << ">";
32 }
33
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);
44
45   dynamic newObject = dynamic::object;
46
47   newObject["z"] = 12;
48   EXPECT_EQ(newObject.size(), 1);
49   newObject["a"] = true;
50   EXPECT_EQ(newObject.size(), 2);
51
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()));
58
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())));
66
67   std::sort(found.begin(), found.end());
68
69   EXPECT_EQ("a", found[0].first);
70   EXPECT_TRUE(found[0].second.asBool());
71
72   EXPECT_EQ("z", found[1].first);
73   EXPECT_EQ(12, found[1].second.asInt());
74
75   dynamic obj2 = dynamic::object;
76   EXPECT_TRUE(obj2.isObject());
77
78   dynamic d3 = nullptr;
79   EXPECT_TRUE(d3 == nullptr);
80   d3 = dynamic::object;
81   EXPECT_TRUE(d3.isObject());
82   d3["foo"] = { 1, 2, 3 };
83   EXPECT_EQ(d3.count("foo"), 1);
84
85   d3[123] = 321;
86   EXPECT_EQ(d3.at(123), 321);
87
88   d3["123"] = 42;
89   EXPECT_EQ(d3.at("123"), 42);
90   EXPECT_EQ(d3.at(123), 321);
91
92   dynamic objInsert = folly::dynamic::object();
93   dynamic objA = folly::dynamic::object("1", "2");
94   dynamic objB = folly::dynamic::object("1", "2");
95
96   objInsert.insert("1", std::move(objA));
97   objInsert.insert("1", std::move(objB));
98
99   EXPECT_EQ(objInsert.find("1")->second.size(), 1);
100
101   // We don't allow objects as keys in objects.
102   EXPECT_ANY_THROW(newObject[d3] = 12);
103 }
104
105 TEST(Dynamic, ObjectErase) {
106   dynamic obj = dynamic::object("key1", "val")
107                                ("key2", "val2");
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);
114   obj["key1"] = 12;
115   EXPECT_EQ(obj.count("key1"), 1);
116   EXPECT_EQ(obj.count("key2"), 1);
117   auto it = obj.find("key2");
118   obj.erase(it);
119   EXPECT_EQ(obj.count("key1"), 1);
120   EXPECT_EQ(obj.count("key2"), 0);
121
122   obj["asd"] = 42.0;
123   obj["foo"] = 42.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());
130 }
131
132 TEST(Dynamic, ArrayErase) {
133   dynamic arr = { 1, 2, 3, 4, 5, 6 };
134
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);
140
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);
145 }
146
147 TEST(Dynamic, StringBasics) {
148   dynamic str = "hello world";
149   EXPECT_EQ(11, str.size());
150   EXPECT_FALSE(str.empty());
151   str = "";
152   EXPECT_TRUE(str.empty());
153 }
154
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);
161
162   EXPECT_ANY_THROW(array.at(3));
163
164   array.push_back("foo");
165   EXPECT_EQ(array.size(), 4);
166
167   array.resize(12, "something");
168   EXPECT_EQ(array.size(), 12);
169   EXPECT_EQ(array[11], "something");
170 }
171
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");
176   dynamic val2 = val;
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");
187
188   dynamic obj = dynamic::object("a", "b")
189                                ("c", {"d", "e", "f"})
190                                ;
191   EXPECT_EQ(obj.at("a"), "b");
192   dynamic obj2 = obj;
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);
197 }
198
199 TEST(Dynamic, Operator) {
200   bool caught = false;
201   try {
202     dynamic d1 = dynamic::object;
203     dynamic d2 = dynamic::object;
204     auto foo = d1 < d2;
205   } catch (std::exception const& e) {
206     caught = true;
207   }
208   EXPECT_TRUE(caught);
209
210   dynamic foo = "asd";
211   dynamic bar = "bar";
212   dynamic sum = foo + bar;
213   EXPECT_EQ(sum, "asdbar");
214
215   dynamic some = 12;
216   dynamic nums = 4;
217   dynamic math = some / nums;
218   EXPECT_EQ(math, 3);
219 }
220
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());
226
227   str = "12";
228   EXPECT_EQ(str.asInt(), 12);
229   EXPECT_EQ(str.asDouble(), 12.0);
230   str = "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");
235
236   dynamic num = 12;
237   EXPECT_EQ("12", num.asString());
238   EXPECT_EQ(12.0, num.asDouble());
239 }
240
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");
245
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);
250
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");
255
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"));
260 }
261
262 TEST(Dynamic, ObjectForwarding) {
263   // Make sure dynamic::object can be constructed the same way as any
264   // dynamic.
265   dynamic d = dynamic::object("asd", {"foo", "bar"});
266   dynamic d2 = dynamic::object("key2", {"value", "words"})
267                               ("key", "value1");
268 }
269
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));
277
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"));
286 }
287
288 int main(int argc, char** argv) {
289   testing::InitGoogleTest(&argc, argv);
290   gflags::ParseCommandLineFlags(&argc, &argv, true);
291   return RUN_ALL_TESTS();
292 }