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> 12using 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 28DOCTEST_MSVC_SUPPRESS_WARNING_PUSH 29DOCTEST_MSVC_SUPPRESS_WARNING(4189) 30 31TEST_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 304DOCTEST_MSVC_SUPPRESS_WARNING_POP 305