1 /*
2 __ _____ _____ _____
3 __| | __| | | | JSON for Modern C++ (test suite)
4 | | |__ | | | | | | version 3.9.1
5 |_____|_____|_____|_|___| https://github.com/nlohmann/json
6
7 Licensed under the MIT License <http://opensource.org/licenses/MIT>.
8 SPDX-License-Identifier: MIT
9 Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
10
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be included in all
19 copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 SOFTWARE.
28 */
29
30 #include "doctest_compatibility.h"
31 DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-equal")
32
33 #include <nlohmann/json.hpp>
34 using nlohmann::json;
35
36 #include <deque>
37 #include <forward_list>
38 #include <list>
39 #include <set>
40 #include <unordered_map>
41 #include <unordered_set>
42 #include <iostream>
43 #include <sstream>
44 #include <iomanip>
45
46 #if defined(_MSC_VER)
47 #pragma warning (push)
48 #pragma warning (disable : 4189) // local variable is initialized but not referenced
49 #endif
50
skip()51 TEST_CASE("README" * doctest::skip())
52 {
53 {
54 // redirect std::cout for the README file
55 auto old_cout_buffer = std::cout.rdbuf();
56 std::ostringstream new_stream;
57 std::cout.rdbuf(new_stream.rdbuf());
58 {
59 // create an empty structure (null)
60 json j;
61
62 // add a number that is stored as double (note the implicit conversion of j to an object)
63 j["pi"] = 3.141;
64
65 // add a Boolean that is stored as bool
66 j["happy"] = true;
67
68 // add a string that is stored as std::string
69 j["name"] = "Niels";
70
71 // add another null object by passing nullptr
72 j["nothing"] = nullptr;
73
74 // add an object inside the object
75 j["answer"]["everything"] = 42;
76
77 // add an array that is stored as std::vector (using an initializer list)
78 j["list"] = { 1, 0, 2 };
79
80 // add another object (using an initializer list of pairs)
81 j["object"] = { {"currency", "USD"}, {"value", 42.99} };
82
83 // instead, you could also write (which looks very similar to the JSON above)
84 json j2 =
85 {
86 {"pi", 3.141},
87 {"happy", true},
88 {"name", "Niels"},
89 {"nothing", nullptr},
90 {
91 "answer", {
92 {"everything", 42}
93 }
94 },
95 {"list", {1, 0, 2}},
96 {
97 "object", {
98 {"currency", "USD"},
99 {"value", 42.99}
100 }
101 }
102 };
103 }
104
105 {
106 // ways to express the empty array []
107 json empty_array_implicit = {{}};
108 CHECK(empty_array_implicit.is_array());
109 json empty_array_explicit = json::array();
110 CHECK(empty_array_explicit.is_array());
111
112 // a way to express the empty object {}
113 json empty_object_explicit = json::object();
114 CHECK(empty_object_explicit.is_object());
115
116 // a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]]
117 json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} });
118 CHECK(array_not_object.is_array());
119 CHECK(array_not_object.size() == 2);
120 CHECK(array_not_object[0].is_array());
121 CHECK(array_not_object[1].is_array());
122 }
123
124 {
125 // create object from string literal
126 json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;
127
128 // or even nicer with a raw string literal
129 auto j2 = R"(
130 {
131 "happy": true,
132 "pi": 3.141
133 }
134 )"_json;
135
136 // or explicitly
137 auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }");
138
139 // explicit conversion to string
140 std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141}
141
142 // serialization with pretty printing
143 // pass in the amount of spaces to indent
144 std::cout << j.dump(4) << std::endl;
145 // {
146 // "happy": true,
147 // "pi": 3.141
148 // }
149
150 std::cout << std::setw(2) << j << std::endl;
151 }
152
153 {
154 // create an array using push_back
155 json j;
156 j.push_back("foo");
157 j.push_back(1);
158 j.push_back(true);
159
160 // comparison
161 bool x = (j == "[\"foo\", 1, true]"_json); // true
162 CHECK(x == true);
163
164 // iterate the array
165 for (json::iterator it = j.begin(); it != j.end(); ++it)
166 {
167 std::cout << *it << '\n';
168 }
169
170 // range-based for
171 for (auto element : j)
172 {
173 std::cout << element << '\n';
174 }
175
176 // getter/setter
177 const auto tmp = j[0].get<std::string>();
178 j[1] = 42;
179 bool foo{j.at(2)};
180 CHECK(foo == true);
181
182 // other stuff
183 j.size(); // 3 entries
184 j.empty(); // false
185 j.type(); // json::value_t::array
186 j.clear(); // the array is empty again
187
188 // create an object
189 json o;
190 o["foo"] = 23;
191 o["bar"] = false;
192 o["baz"] = 3.141;
193
194 // find an entry
195 if (o.find("foo") != o.end())
196 {
197 // there is an entry with key "foo"
198 }
199 }
200
201 {
202 std::vector<int> c_vector {1, 2, 3, 4};
203 json j_vec(c_vector);
204 // [1, 2, 3, 4]
205
206 std::deque<float> c_deque {1.2f, 2.3f, 3.4f, 5.6f};
207 json j_deque(c_deque);
208 // [1.2, 2.3, 3.4, 5.6]
209
210 std::list<bool> c_list {true, true, false, true};
211 json j_list(c_list);
212 // [true, true, false, true]
213
214 std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
215 json j_flist(c_flist);
216 // [12345678909876, 23456789098765, 34567890987654, 45678909876543]
217
218 std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
219 json j_array(c_array);
220 // [1, 2, 3, 4]
221
222 std::set<std::string> c_set {"one", "two", "three", "four", "one"};
223 json j_set(c_set); // only one entry for "one" is used
224 // ["four", "one", "three", "two"]
225
226 std::unordered_set<std::string> c_uset {"one", "two", "three", "four", "one"};
227 json j_uset(c_uset); // only one entry for "one" is used
228 // maybe ["two", "three", "four", "one"]
229
230 std::multiset<std::string> c_mset {"one", "two", "one", "four"};
231 json j_mset(c_mset); // both entries for "one" are used
232 // maybe ["one", "two", "one", "four"]
233
234 std::unordered_multiset<std::string> c_umset {"one", "two", "one", "four"};
235 json j_umset(c_umset); // both entries for "one" are used
236 // maybe ["one", "two", "one", "four"]
237 }
238
239 {
240 std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
241 json j_map(c_map);
242 // {"one": 1, "two": 2, "three": 3}
243
244 std::unordered_map<const char*, float> c_umap { {"one", 1.2f}, {"two", 2.3f}, {"three", 3.4f} };
245 json j_umap(c_umap);
246 // {"one": 1.2, "two": 2.3, "three": 3.4}
247
248 std::multimap<std::string, bool> c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
249 json j_mmap(c_mmap); // only one entry for key "three" is used
250 // maybe {"one": true, "two": true, "three": true}
251
252 std::unordered_multimap<std::string, bool> c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
253 json j_ummap(c_ummap); // only one entry for key "three" is used
254 // maybe {"one": true, "two": true, "three": true}
255 }
256
257 {
258 // strings
259 std::string s1 = "Hello, world!";
260 json js = s1;
261 auto s2 = js.get<std::string>();
262
263 // Booleans
264 bool b1 = true;
265 json jb = b1;
266 bool b2{jb};
267 CHECK(b2 == true);
268
269 // numbers
270 int i = 42;
271 json jn = i;
272 double f{jn};
273 CHECK(f == 42);
274
275 // etc.
276
277 std::string vs = js.get<std::string>();
278 bool vb = jb.get<bool>();
279 CHECK(vb == true);
280 int vi = jn.get<int>();
281 CHECK(vi == 42);
282
283 // etc.
284 }
285
286 {
287 // a JSON value
288 json j_original = R"({
289 "baz": ["one", "two", "three"],
290 "foo": "bar"
291 })"_json;
292
293 // access members with a JSON pointer (RFC 6901)
294 j_original["/baz/1"_json_pointer];
295 // "two"
296
297 // a JSON patch (RFC 6902)
298 json j_patch = R"([
299 { "op": "replace", "path": "/baz", "value": "boo" },
300 { "op": "add", "path": "/hello", "value": ["world"] },
301 { "op": "remove", "path": "/foo"}
302 ])"_json;
303
304 // apply the patch
305 json j_result = j_original.patch(j_patch);
306 // {
307 // "baz": "boo",
308 // "hello": ["world"]
309 // }
310
311 // calculate a JSON patch from two JSON values
312 auto res = json::diff(j_result, j_original);
313 // [
314 // { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] },
315 // { "op":"remove","path":"/hello" },
316 // { "op":"add","path":"/foo","value":"bar" }
317 // ]
318 }
319
320 // restore old std::cout
321 std::cout.rdbuf(old_cout_buffer);
322 }
323 }
324
325 #if defined(_MSC_VER)
326 #pragma warning (pop)
327 #endif
328