• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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