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