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