1 /*
2 __ _____ _____ _____
3 __| | __| | | | JSON for Modern C++ (test suite)
4 | | |__ | | | | | | version 3.10.0
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
32 #include <nlohmann/json.hpp>
33 using nlohmann::json;
34
35 #include <deque>
36 #include <forward_list>
37 #include <list>
38 #include <set>
39 #include <unordered_map>
40 #include <unordered_set>
41 #include <iostream>
42 #include <sstream>
43 #include <iomanip>
44
45 // local variable is initialized but not referenced
46 DOCTEST_MSVC_SUPPRESS_WARNING_PUSH
47 DOCTEST_MSVC_SUPPRESS_WARNING(4189)
48
skip()49 TEST_CASE("README" * doctest::skip())
50 {
51 {
52 // redirect std::cout for the README file
53 auto* old_cout_buffer = std::cout.rdbuf();
54 std::ostringstream new_stream;
55 std::cout.rdbuf(new_stream.rdbuf());
56 {
57 // create an empty structure (null)
58 json j;
59
60 // add a number that is stored as double (note the implicit conversion of j to an object)
61 j["pi"] = 3.141;
62
63 // add a Boolean that is stored as bool
64 j["happy"] = true;
65
66 // add a string that is stored as std::string
67 j["name"] = "Niels";
68
69 // add another null object by passing nullptr
70 j["nothing"] = nullptr;
71
72 // add an object inside the object
73 j["answer"]["everything"] = 42;
74
75 // add an array that is stored as std::vector (using an initializer list)
76 j["list"] = { 1, 0, 2 };
77
78 // add another object (using an initializer list of pairs)
79 j["object"] = { {"currency", "USD"}, {"value", 42.99} };
80
81 // instead, you could also write (which looks very similar to the JSON above)
82 json j2 =
83 {
84 {"pi", 3.141},
85 {"happy", true},
86 {"name", "Niels"},
87 {"nothing", nullptr},
88 {
89 "answer", {
90 {"everything", 42}
91 }
92 },
93 {"list", {1, 0, 2}},
94 {
95 "object", {
96 {"currency", "USD"},
97 {"value", 42.99}
98 }
99 }
100 };
101 }
102
103 {
104 // ways to express the empty array []
105 json empty_array_implicit = {{}};
106 CHECK(empty_array_implicit.is_array());
107 json empty_array_explicit = json::array();
108 CHECK(empty_array_explicit.is_array());
109
110 // a way to express the empty object {}
111 json empty_object_explicit = json::object();
112 CHECK(empty_object_explicit.is_object());
113
114 // a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]]
115 json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} });
116 CHECK(array_not_object.is_array());
117 CHECK(array_not_object.size() == 2);
118 CHECK(array_not_object[0].is_array());
119 CHECK(array_not_object[1].is_array());
120 }
121
122 {
123 // create object from string literal
124 json j = "{ \"happy\": true, \"pi\": 3.141 }"_json; // NOLINT(modernize-raw-string-literal)
125
126 // or even nicer with a raw string literal
127 auto j2 = R"(
128 {
129 "happy": true,
130 "pi": 3.141
131 }
132 )"_json;
133
134 // or explicitly
135 auto j3 = json::parse(R"({"happy": true, "pi": 3.141})");
136
137 // explicit conversion to string
138 std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141}
139
140 // serialization with pretty printing
141 // pass in the amount of spaces to indent
142 std::cout << j.dump(4) << std::endl;
143 // {
144 // "happy": true,
145 // "pi": 3.141
146 // }
147
148 std::cout << std::setw(2) << j << std::endl;
149 }
150
151 {
152 // create an array using push_back
153 json j;
154 j.push_back("foo");
155 j.push_back(1);
156 j.push_back(true);
157
158 // comparison
159 bool x = (j == R"(["foo", 1, true])"_json); // true
160 CHECK(x == true);
161
162 // iterate the array
163 for (json::iterator it = j.begin(); it != j.end(); ++it) // NOLINT(modernize-loop-convert)
164 {
165 std::cout << *it << '\n';
166 }
167
168 // range-based for
169 for (auto& element : j)
170 {
171 std::cout << element << '\n';
172 }
173
174 // getter/setter
175 const auto tmp = j[0].get<std::string>();
176 j[1] = 42;
177 bool foo{j.at(2)};
178 CHECK(foo == true);
179
180 // other stuff
181 j.size(); // 3 entries
182 j.empty(); // false
183 j.type(); // json::value_t::array
184 j.clear(); // the array is empty again
185
186 // create an object
187 json o;
188 o["foo"] = 23;
189 o["bar"] = false;
190 o["baz"] = 3.141;
191
192 // find an entry
193 if (o.find("foo") != o.end())
194 {
195 // there is an entry with key "foo"
196 }
197 }
198
199 {
200 std::vector<int> c_vector {1, 2, 3, 4};
201 json j_vec(c_vector);
202 // [1, 2, 3, 4]
203
204 std::deque<float> c_deque {1.2f, 2.3f, 3.4f, 5.6f};
205 json j_deque(c_deque);
206 // [1.2, 2.3, 3.4, 5.6]
207
208 std::list<bool> c_list {true, true, false, true};
209 json j_list(c_list);
210 // [true, true, false, true]
211
212 std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
213 json j_flist(c_flist);
214 // [12345678909876, 23456789098765, 34567890987654, 45678909876543]
215
216 std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
217 json j_array(c_array);
218 // [1, 2, 3, 4]
219
220 std::set<std::string> c_set {"one", "two", "three", "four", "one"};
221 json j_set(c_set); // only one entry for "one" is used
222 // ["four", "one", "three", "two"]
223
224 std::unordered_set<std::string> c_uset {"one", "two", "three", "four", "one"};
225 json j_uset(c_uset); // only one entry for "one" is used
226 // maybe ["two", "three", "four", "one"]
227
228 std::multiset<std::string> c_mset {"one", "two", "one", "four"};
229 json j_mset(c_mset); // both entries for "one" are used
230 // maybe ["one", "two", "one", "four"]
231
232 std::unordered_multiset<std::string> c_umset {"one", "two", "one", "four"};
233 json j_umset(c_umset); // both entries for "one" are used
234 // maybe ["one", "two", "one", "four"]
235 }
236
237 {
238 std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
239 json j_map(c_map);
240 // {"one": 1, "two": 2, "three": 3}
241
242 std::unordered_map<const char*, float> c_umap { {"one", 1.2f}, {"two", 2.3f}, {"three", 3.4f} };
243 json j_umap(c_umap);
244 // {"one": 1.2, "two": 2.3, "three": 3.4}
245
246 std::multimap<std::string, bool> c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
247 json j_mmap(c_mmap); // only one entry for key "three" is used
248 // maybe {"one": true, "two": true, "three": true}
249
250 std::unordered_multimap<std::string, bool> c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
251 json j_ummap(c_ummap); // only one entry for key "three" is used
252 // maybe {"one": true, "two": true, "three": true}
253 }
254
255 {
256 // strings
257 std::string s1 = "Hello, world!";
258 json js = s1;
259 auto s2 = js.get<std::string>();
260
261 // Booleans
262 bool b1 = true;
263 json jb = b1;
264 bool b2{jb};
265 CHECK(b2 == true);
266
267 // numbers
268 int i = 42;
269 json jn = i;
270 double f{jn};
271 CHECK(f == 42);
272
273 // etc.
274
275 std::string vs = js.get<std::string>();
276 bool vb = jb.get<bool>();
277 CHECK(vb == true);
278 int vi = jn.get<int>();
279 CHECK(vi == 42);
280
281 // etc.
282 }
283
284 {
285 // a JSON value
286 json j_original = R"({
287 "baz": ["one", "two", "three"],
288 "foo": "bar"
289 })"_json;
290
291 // access members with a JSON pointer (RFC 6901)
292 j_original["/baz/1"_json_pointer];
293 // "two"
294
295 // a JSON patch (RFC 6902)
296 json j_patch = R"([
297 { "op": "replace", "path": "/baz", "value": "boo" },
298 { "op": "add", "path": "/hello", "value": ["world"] },
299 { "op": "remove", "path": "/foo"}
300 ])"_json;
301
302 // apply the patch
303 json j_result = j_original.patch(j_patch);
304 // {
305 // "baz": "boo",
306 // "hello": ["world"]
307 // }
308
309 // calculate a JSON patch from two JSON values
310 auto res = json::diff(j_result, j_original);
311 // [
312 // { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] },
313 // { "op":"remove","path":"/hello" },
314 // { "op":"add","path":"/foo","value":"bar" }
315 // ]
316 }
317
318 // restore old std::cout
319 std::cout.rdbuf(old_cout_buffer);
320 }
321 }
322
323 DOCTEST_MSVC_SUPPRESS_WARNING_POP
324