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