1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/boostorg/json
9 //
10
11 // Test that header file is self-contained.
12 #include <boost/json/value_from.hpp>
13
14 #include <boost/json/value.hpp> // prevent intellisense bugs
15 #include <boost/json/serialize.hpp>
16
17 #include "test_suite.hpp"
18
19 #include <string>
20 #include <vector>
21 #include <tuple>
22 #include <map>
23 #include <unordered_map>
24
25 //----------------------------------------------------------
26
27 namespace value_from_test_ns {
28
29 //----------------------------------------------------------
30
31 struct T1
32 {
33 int i = 42;
34 };
35
36 void
tag_invoke(::boost::json::value_from_tag,::boost::json::value & jv,T1 const & t)37 tag_invoke(
38 ::boost::json::value_from_tag,
39 ::boost::json::value& jv,
40 T1 const& t)
41 {
42 jv = t.i;
43 }
44
45 //----------------------------------------------------------
46
47 // member function
48 // uses generic algorithms
49 struct T2
50 {
51 std::vector<int> v;
52 std::string s;
53
T2value_from_test_ns::T254 T2()
55 : v({1,2,3, 4})
56 , s("test")
57 {
58 }
59 };
60
61 void
tag_invoke(::boost::json::value_from_tag,::boost::json::value & jv,T2 const & t)62 tag_invoke(
63 ::boost::json::value_from_tag,
64 ::boost::json::value& jv,
65 T2 const& t)
66 {
67 jv = { t.v, t.s };
68 };
69
70 struct T3
71 {
72 };
73
74 BOOST_STATIC_ASSERT(! ::boost::json::has_value_from<T3>::value);
75
76 struct T4
77 {
operator ::boost::json::valuevalue_from_test_ns::T478 operator ::boost::json::value()
79 {
80 return nullptr;
81 }
82 };
83
84 BOOST_STATIC_ASSERT(! ::boost::json::has_value_from<T4>::value);
85
86 //----------------------------------------------------------
87
88 } // value_from_test_ns
89
90 template<class T>
91 static
92 void
check(::boost::json::string_view s,T const & t)93 check(
94 ::boost::json::string_view s,
95 T const& t)
96 {
97 {
98 auto const jv = value_from(t,
99 ::boost::json::storage_ptr{});
100 auto const js =
101 ::boost::json::serialize(jv);
102 BOOST_TEST(js == s);
103 }
104 {
105 auto const jv =
106 ::boost::json::value_from(t);
107 auto const js =
108 ::boost::json::serialize(jv);
109 BOOST_TEST(js == s);
110 }
111 }
112
113 template<class T>
114 static
115 void
testValueCtor()116 testValueCtor()
117 {
118 BOOST_TEST(
119 ::boost::json::serialize(
120 ::boost::json::value_from(T{})) ==
121 ::boost::json::serialize(
122 ::boost::json::value(T{})));
123 }
124
125 BOOST_JSON_NS_BEGIN
126
127 // integral
128 BOOST_STATIC_ASSERT(has_value_from<int>::value);
129 BOOST_STATIC_ASSERT(has_value_from<int&>::value);
130 BOOST_STATIC_ASSERT(has_value_from<int&&>::value);
131 // array
132 BOOST_STATIC_ASSERT(has_value_from<int[4]>::value);
133 BOOST_STATIC_ASSERT(has_value_from<int(&)[4]>::value);
134 BOOST_STATIC_ASSERT(has_value_from<int(&&)[4]>::value);
135 // forward range
136 BOOST_STATIC_ASSERT(has_value_from<std::vector<int>>::value);
137 BOOST_STATIC_ASSERT(has_value_from<std::vector<int>&>::value);
138 BOOST_STATIC_ASSERT(has_value_from<std::vector<int>&&>::value);
139 // tuple-like
140 BOOST_STATIC_ASSERT(has_value_from<std::tuple<int, int>>::value);
141 BOOST_STATIC_ASSERT(has_value_from<std::tuple<int, int>&>::value);
142 BOOST_STATIC_ASSERT(has_value_from<std::tuple<int, int>&&>::value);
143 BOOST_STATIC_ASSERT(has_value_from<key_value_pair>::value);
144 BOOST_STATIC_ASSERT(has_value_from<key_value_pair&>::value);
145 BOOST_STATIC_ASSERT(has_value_from<key_value_pair&&>::value);
146
147 // object-like
148 BOOST_STATIC_ASSERT(has_value_from<std::map<string_view, int>>::value);
149
150 class value_from_test
151 {
152 public:
153 static
154 void
testValueCtors()155 testValueCtors()
156 {
157 // value_from supports every value constructor
158
159 testValueCtor<value const&>();
160 }
161
162 static
163 void
testGeneral()164 testGeneral()
165 {
166 {
167 int a[4] = {1, 2, 3, 4};
168 value b{1, 2, 3, 4};
169 value c = value_from(a);
170 BOOST_TEST(c.is_array());
171 BOOST_TEST(serialize(c) == serialize(b));
172 }
173 {
174 std::tuple<int, string, int, bool> a{1, "2", 42, true};
175 value b{1, "2", 42, true};
176 value c = value_from(a);
177 BOOST_TEST(c.is_array());
178 BOOST_TEST(serialize(c) == serialize(b));
179 }
180 {
181 std::pair<int, string> a{1, string("2")};
182 value b{1, "2"};
183 value c = value_from(a);
184 BOOST_TEST(c.is_array());
185 BOOST_TEST(serialize(c) == serialize(b));
186 }
187 {
188 // ensures that this isn't parsed as a key value pair
189 std::pair<string_view, int> a{"2", 1};
190 value b{"2", 1};
191 value c = value_from(a);
192 BOOST_TEST(c.is_array());
193 BOOST_TEST(serialize(c) == serialize(b));
194 }
195 {
196 key_value_pair a{"2", 1};
197 value b{"2", 1};
198 value c = value_from(a);
199 BOOST_TEST(c.is_array());
200 BOOST_TEST(serialize(c) == serialize(b));
201 }
202 }
203
204 static
205 void
testAssociative()206 testAssociative()
207 {
208 {
209 std::map<string_view, int> a =
210 {{"a", 1}, {"b", 2}, {"c", 3}};
211 value b = {{"a", 1}, {"b", 2}, {"c", 3}};
212 value c = value_from(a);
213 BOOST_TEST(c.is_object());
214 BOOST_TEST(a.size() == c.as_object().size());
215 BOOST_TEST(b.as_object().size() == c.as_object().size());
216 }
217 {
218 std::unordered_map<std::string, int> a =
219 {{"a", 1}, {"b", 2}, {"c", 3}};
220 value b = {{"a", 1}, {"b", 2}, {"c", 3}};
221 value c = value_from(a);
222 BOOST_TEST(c.is_object());
223 BOOST_TEST(a.size() == c.as_object().size());
224 BOOST_TEST(b.as_object().size() == c.as_object().size());
225 }
226 {
227 std::map<int, int> a =
228 {{1, 1}, {2, 2}, {3, 3}};
229 value b = {{1, 1}, {2, 2}, {3, 3}};
230 value c = value_from(a);
231 BOOST_TEST(!c.is_object());
232 BOOST_TEST(a.size() == c.as_array().size());
233 BOOST_TEST(b.as_array().size() == c.as_array().size());
234 }
235 {
236 std::unordered_map<int, int> a =
237 {{1, 1}, {2, 2}, {3, 3}};
238 value b = {{1, 1}, {2, 2}, {3, 3}};
239 value c = value_from(a);
240 BOOST_TEST(!c.is_object());
241 BOOST_TEST(a.size() == c.as_array().size());
242 BOOST_TEST(b.as_array().size() == c.as_array().size());
243 }
244 }
245
246 void
run()247 run()
248 {
249 check("42", ::value_from_test_ns::T1{});
250 check("[[1,2,3,4],\"test\"]", ::value_from_test_ns::T2{});
251
252 testValueCtors();
253 testGeneral();
254 testAssociative();
255 }
256 };
257
258 TEST_SUITE(value_from_test, "boost.json.value_from");
259
260 BOOST_JSON_NS_END
261