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 // @author Nicholas Ormrod <njormrod@fb.com>
19 #include "folly/DynamicConverter.h"
20 #include <gtest/gtest.h>
21 #include <gflags/gflags.h>
22 #include "folly/Benchmark.h"
24 using namespace folly;
25 using namespace folly::dynamicconverter_detail;
27 TEST(DynamicConverter, template_metaprogramming) {
30 bool c1f = is_container<int>::value;
31 bool c2f = is_container<std::pair<int, int>>::value;
32 bool c3f = is_container<A>::value;
34 bool c1t = is_container<std::vector<int>>::value;
35 bool c2t = is_container<std::set<int>>::value;
36 bool c3t = is_container<std::map<int, int>>::value;
38 EXPECT_EQ(c1f, false);
39 EXPECT_EQ(c2f, false);
40 EXPECT_EQ(c3f, false);
45 bool m1f = is_map_container<int>::value;
46 bool m2f = is_map_container<std::vector<int>>::value;
47 bool m3f = is_map_container<std::set<int>>::value;
49 bool m1t = is_map_container<std::map<int, int>>::value;
50 bool m2t = is_map_container<std::unordered_map<int, int>>::value;
52 EXPECT_EQ(m1f, false);
53 EXPECT_EQ(m2f, false);
54 EXPECT_EQ(m3f, false);
59 TEST(DynamicConverter, arithmetic_types) {
61 auto i1 = convertTo<int>(d1);
64 dynamic d2 = 123456789012345;
65 auto i2 = convertTo<int64_t>(d2);
66 EXPECT_EQ(i2, 123456789012345);
68 dynamic d3 = 123456789012345;
69 auto i3 = convertTo<uint8_t>(d3);
73 auto i4 = convertTo<float>(d4);
74 EXPECT_EQ((int)(i4*100), 314);
77 auto i5 = convertTo<bool>(d5);
81 const auto i6 = convertTo<const int>(d6);
85 auto i7 = convertTo<int>(d7);
89 auto i8 = convertTo<bool>(d8);
93 TEST(DynamicConverter, simple_builtins) {
94 dynamic d1 = "Haskell";
95 auto i1 = convertTo<folly::fbstring>(d1);
96 EXPECT_EQ(i1, "Haskell");
99 auto i2 = convertTo<std::string>(d2);
102 dynamic d3 = { 12, "Scala" };
103 auto i3 = convertTo<std::pair<int, std::string>>(d3);
104 EXPECT_EQ(i3.first, 12);
105 EXPECT_EQ(i3.second, "Scala");
107 dynamic d4 = dynamic::object("C", "C++");
108 auto i4 = convertTo<std::pair<std::string, folly::fbstring>>(d4);
109 EXPECT_EQ(i4.first, "C");
110 EXPECT_EQ(i4.second, "C++");
113 TEST(DynamicConverter, simple_fbvector) {
114 dynamic d1 = { 1, 2, 3 };
115 auto i1 = convertTo<folly::fbvector<int>>(d1);
116 decltype(i1) i1b = { 1, 2, 3 };
120 TEST(DynamicConverter, simple_container) {
121 dynamic d1 = { 1, 2, 3 };
122 auto i1 = convertTo<std::vector<int>>(d1);
123 decltype(i1) i1b = { 1, 2, 3 };
126 dynamic d2 = { 1, 3, 5, 2, 4 };
127 auto i2 = convertTo<std::set<int>>(d2);
128 decltype(i2) i2b = { 1, 2, 3, 5, 4 };
132 TEST(DynamicConverter, simple_map) {
133 dynamic d1 = dynamic::object(1, "one")(2, "two");
134 auto i1 = convertTo<std::map<int, std::string>>(d1);
135 decltype(i1) i1b = { { 1, "one" }, { 2, "two" } };
138 dynamic d2 = { { 3, "three" }, { 4, "four" } };
139 auto i2 = convertTo<std::unordered_map<int, std::string>>(d2);
140 decltype(i2) i2b = { { 3, "three" }, { 4, "four" } };
144 TEST(DynamicConverter, nested_containers) {
145 dynamic d1 = { { 1 }, { }, { 2, 3 } };
146 auto i1 = convertTo<folly::fbvector<std::vector<uint8_t>>>(d1);
147 decltype(i1) i1b = { { 1 }, { }, { 2, 3 } };
150 dynamic h2a = { "3", ".", "1", "4" };
151 dynamic h2b = { "2", ".", "7", "2" };
152 dynamic d2 = dynamic::object(3.14, h2a)(2.72, h2b);
153 auto i2 = convertTo<std::map<double, std::vector<folly::fbstring>>>(d2);
155 { { 3.14, { "3", ".", "1", "4" } },
156 { 2.72, { "2", ".", "7", "2" } } };
162 bool operator==(const A & o) const { return i == o.i; }
165 template <> struct DynamicConverter<A> {
166 static A convert(const dynamic & d) {
167 return { convertTo<int>(d["i"]) };
171 TEST(DynamicConverter, custom_class) {
172 dynamic d1 = dynamic::object("i", 17);
173 auto i1 = convertTo<A>(d1);
176 dynamic d2 = { dynamic::object("i", 18), dynamic::object("i", 19) };
177 auto i2 = convertTo<std::vector<A>>(d2);
178 decltype(i2) i2b = { { 18 }, { 19 } };
182 TEST(DynamicConverter, crazy) {
183 // we are going to create a vector<unordered_map<bool, T>>
184 // we will construct some of the maps from dynamic objects,
185 // some from a vector of KV pairs.
186 // T will be vector<set<string>>
188 std::set<std::string>
189 s1 = { "a", "e", "i", "o", "u" },
190 s2 = { "2", "3", "5", "7" },
191 s3 = { "Hello", "World" };
193 std::vector<std::set<std::string>>
198 std::unordered_map<bool, std::vector<std::set<std::string>>>
199 m1 = { { true, v1 }, { false, v2 } },
200 m2 = { { true, v3 } };
202 std::vector<std::unordered_map<bool, std::vector<std::set<std::string>>>>
207 ds1 = { "a", "e", "i", "o", "u" },
208 ds2 = { "2", "3", "5", "7" },
209 ds3 = { "Hello", "World" };
217 dm1 = dynamic::object(true, dv1)(false, dv2),
218 dm2 = { { true, dv3 } };
224 auto i = convertTo<std::vector<std::unordered_map<bool, std::vector<
225 std::set<std::string>>>>>(df1); // yes, that is 5 close-chevrons
234 explicit Token(int kind, const fbstring& lexeme)
235 : kind_(kind), lexeme_(lexeme) {}
238 template <> struct DynamicConverter<Token> {
239 static Token convert(const dynamic& d) {
240 int k = convertTo<int>(d["KIND"]);
241 fbstring lex = convertTo<fbstring>(d["LEXEME"]);
242 return Token(k, lex);
246 TEST(DynamicConverter, example) {
247 dynamic d1 = dynamic::object("KIND", 2)("LEXEME", "a token");
248 auto i1 = convertTo<Token>(d1);
249 EXPECT_EQ(i1.kind_, 2);
250 EXPECT_EQ(i1.lexeme_, "a token");
253 int main(int argc, char ** argv) {
254 testing::InitGoogleTest(&argc, argv);
255 google::ParseCommandLineFlags(&argc, &argv, true);
256 if (FLAGS_benchmark) {
257 folly::runBenchmarks();
259 return RUN_ALL_TESTS();