1 /* 2 __ _____ _____ _____ 3 __| | __| | | | JSON for Modern C++ (test suite) 4 | | |__ | | | | | | version 3.7.3 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 <fstream> 36 #include <sstream> 37 38 TEST_CASE("object inspection") 39 { 40 SECTION("convenience type checker") 41 { 42 SECTION("object") 43 { 44 json j {{"foo", 1}, {"bar", false}}; 45 CHECK(not j.is_null()); 46 CHECK(not j.is_boolean()); 47 CHECK(not j.is_number()); 48 CHECK(not j.is_number_integer()); 49 CHECK(not j.is_number_unsigned()); 50 CHECK(not j.is_number_float()); 51 CHECK(j.is_object()); 52 CHECK(not j.is_array()); 53 CHECK(not j.is_string()); 54 CHECK(not j.is_discarded()); 55 CHECK(not j.is_primitive()); 56 CHECK(j.is_structured()); 57 } 58 59 SECTION("array") 60 { 61 json j {"foo", 1, 1u, 42.23, false}; 62 CHECK(not j.is_null()); 63 CHECK(not j.is_boolean()); 64 CHECK(not j.is_number()); 65 CHECK(not j.is_number_integer()); 66 CHECK(not j.is_number_unsigned()); 67 CHECK(not j.is_number_float()); 68 CHECK(not j.is_object()); 69 CHECK(j.is_array()); 70 CHECK(not j.is_string()); 71 CHECK(not j.is_discarded()); 72 CHECK(not j.is_primitive()); 73 CHECK(j.is_structured()); 74 } 75 76 SECTION("null") 77 { 78 json j(nullptr); 79 CHECK(j.is_null()); 80 CHECK(not j.is_boolean()); 81 CHECK(not j.is_number()); 82 CHECK(not j.is_number_integer()); 83 CHECK(not j.is_number_unsigned()); 84 CHECK(not j.is_number_float()); 85 CHECK(not j.is_object()); 86 CHECK(not j.is_array()); 87 CHECK(not j.is_string()); 88 CHECK(not j.is_discarded()); 89 CHECK(j.is_primitive()); 90 CHECK(not j.is_structured()); 91 } 92 93 SECTION("boolean") 94 { 95 json j(true); 96 CHECK(not j.is_null()); 97 CHECK(j.is_boolean()); 98 CHECK(not j.is_number()); 99 CHECK(not j.is_number_integer()); 100 CHECK(not j.is_number_unsigned()); 101 CHECK(not j.is_number_float()); 102 CHECK(not j.is_object()); 103 CHECK(not j.is_array()); 104 CHECK(not j.is_string()); 105 CHECK(not j.is_discarded()); 106 CHECK(j.is_primitive()); 107 CHECK(not j.is_structured()); 108 } 109 110 SECTION("string") 111 { 112 json j("Hello world"); 113 CHECK(not j.is_null()); 114 CHECK(not j.is_boolean()); 115 CHECK(not j.is_number()); 116 CHECK(not j.is_number_integer()); 117 CHECK(not j.is_number_unsigned()); 118 CHECK(not j.is_number_float()); 119 CHECK(not j.is_object()); 120 CHECK(not j.is_array()); 121 CHECK(j.is_string()); 122 CHECK(not j.is_discarded()); 123 CHECK(j.is_primitive()); 124 CHECK(not j.is_structured()); 125 } 126 127 SECTION("number (integer)") 128 { 129 json j(42); 130 CHECK(not j.is_null()); 131 CHECK(not j.is_boolean()); 132 CHECK(j.is_number()); 133 CHECK(j.is_number_integer()); 134 CHECK(not j.is_number_unsigned()); 135 CHECK(not j.is_number_float()); 136 CHECK(not j.is_object()); 137 CHECK(not j.is_array()); 138 CHECK(not j.is_string()); 139 CHECK(not j.is_discarded()); 140 CHECK(j.is_primitive()); 141 CHECK(not j.is_structured()); 142 } 143 144 SECTION("number (unsigned)") 145 { 146 json j(42u); 147 CHECK(not j.is_null()); 148 CHECK(not j.is_boolean()); 149 CHECK(j.is_number()); 150 CHECK(j.is_number_integer()); 151 CHECK(j.is_number_unsigned()); 152 CHECK(not j.is_number_float()); 153 CHECK(not j.is_object()); 154 CHECK(not j.is_array()); 155 CHECK(not j.is_string()); 156 CHECK(not j.is_discarded()); 157 CHECK(j.is_primitive()); 158 CHECK(not j.is_structured()); 159 } 160 161 SECTION("number (floating-point)") 162 { 163 json j(42.23); 164 CHECK(not j.is_null()); 165 CHECK(not j.is_boolean()); 166 CHECK(j.is_number()); 167 CHECK(not j.is_number_integer()); 168 CHECK(not j.is_number_unsigned()); 169 CHECK(j.is_number_float()); 170 CHECK(not j.is_object()); 171 CHECK(not j.is_array()); 172 CHECK(not j.is_string()); 173 CHECK(not j.is_discarded()); 174 CHECK(j.is_primitive()); 175 CHECK(not j.is_structured()); 176 } 177 178 SECTION("discarded") 179 { 180 json j(json::value_t::discarded); 181 CHECK(not j.is_null()); 182 CHECK(not j.is_boolean()); 183 CHECK(not j.is_number()); 184 CHECK(not j.is_number_integer()); 185 CHECK(not j.is_number_unsigned()); 186 CHECK(not j.is_number_float()); 187 CHECK(not j.is_object()); 188 CHECK(not j.is_array()); 189 CHECK(not j.is_string()); 190 CHECK(j.is_discarded()); 191 CHECK(not j.is_primitive()); 192 CHECK(not j.is_structured()); 193 } 194 } 195 196 SECTION("serialization") 197 { 198 json j {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} }; 199 200 SECTION("no indent / indent=-1") 201 { 202 CHECK(j.dump() == 203 "{\"array\":[1,2,3,4],\"boolean\":false,\"null\":null,\"number\":42,\"object\":{},\"string\":\"Hello world\"}"); 204 205 CHECK(j.dump() == j.dump(-1)); 206 } 207 208 SECTION("indent=0") 209 { 210 CHECK(j.dump(0) == 211 "{\n\"array\": [\n1,\n2,\n3,\n4\n],\n\"boolean\": false,\n\"null\": null,\n\"number\": 42,\n\"object\": {},\n\"string\": \"Hello world\"\n}"); 212 } 213 214 SECTION("indent=1, space='\t'") 215 { 216 CHECK(j.dump(1, '\t') == 217 "{\n\t\"array\": [\n\t\t1,\n\t\t2,\n\t\t3,\n\t\t4\n\t],\n\t\"boolean\": false,\n\t\"null\": null,\n\t\"number\": 42,\n\t\"object\": {},\n\t\"string\": \"Hello world\"\n}"); 218 } 219 220 SECTION("indent=4") 221 { 222 CHECK(j.dump(4) == 223 "{\n \"array\": [\n 1,\n 2,\n 3,\n 4\n ],\n \"boolean\": false,\n \"null\": null,\n \"number\": 42,\n \"object\": {},\n \"string\": \"Hello world\"\n}"); 224 } 225 226 SECTION("indent=x") 227 { 228 CHECK(j.dump().size() == 94); 229 CHECK(j.dump(1).size() == 127); 230 CHECK(j.dump(2).size() == 142); 231 CHECK(j.dump(512).size() == 7792); 232 233 // important test, because it yields a resize of the indent_string 234 // inside the dump() function 235 CHECK(j.dump(1024).size() == 15472); 236 } 237 238 SECTION("dump and floating-point numbers") 239 { 240 auto s = json(42.23).dump(); 241 CHECK(s.find("42.23") != std::string::npos); 242 } 243 244 SECTION("dump and small floating-point numbers") 245 { 246 auto s = json(1.23456e-78).dump(); 247 CHECK(s.find("1.23456e-78") != std::string::npos); 248 } 249 250 SECTION("dump and non-ASCII characters") 251 { 252 CHECK(json("ä").dump() == "\"ä\""); 253 CHECK(json("Ö").dump() == "\"Ö\""); 254 CHECK(json("❤️").dump() == "\"❤️\""); 255 } 256 257 SECTION("dump with ensure_ascii and non-ASCII characters") 258 { 259 CHECK(json("ä").dump(-1, ' ', true) == "\"\\u00e4\""); 260 CHECK(json("Ö").dump(-1, ' ', true) == "\"\\u00d6\""); 261 CHECK(json("❤️").dump(-1, ' ', true) == "\"\\u2764\\ufe0f\""); 262 } 263 264 SECTION("full Unicode escaping to ASCII") 265 { 266 SECTION("parsing yields the same JSON value") 267 { 268 std::ifstream f_escaped("test/data/json_nlohmann_tests/all_unicode_ascii.json"); 269 std::ifstream f_unescaped("test/data/json_nlohmann_tests/all_unicode.json"); 270 271 json j1 = json::parse(f_escaped); 272 json j2 = json::parse(f_unescaped); 273 CHECK(j1 == j2); 274 } 275 276 SECTION("dumping yields the same JSON text") 277 { 278 std::ifstream f_escaped("test/data/json_nlohmann_tests/all_unicode_ascii.json"); 279 std::ifstream f_unescaped("test/data/json_nlohmann_tests/all_unicode.json"); 280 281 json value = json::parse(f_unescaped); 282 std::string text = value.dump(4, ' ', true); 283 284 std::string expected((std::istreambuf_iterator<char>(f_escaped)), 285 std::istreambuf_iterator<char>()); 286 CHECK(text == expected); 287 } 288 } 289 290 SECTION("serialization of discarded element") 291 { 292 json j_discarded(json::value_t::discarded); 293 CHECK(j_discarded.dump() == "<discarded>"); 294 } 295 296 SECTION("check that precision is reset after serialization") 297 { 298 // create stringstream and set precision 299 std::stringstream ss; 300 ss.precision(3); 301 ss << 3.141592653589793 << std::fixed; 302 CHECK(ss.str() == "3.14"); 303 304 // reset stringstream 305 ss.str(std::string()); 306 307 // use stringstream for JSON serialization 308 json j_number = 3.14159265358979; 309 ss << j_number; 310 311 // check that precision has been overridden during serialization 312 CHECK(ss.str() == "3.14159265358979"); 313 314 // check that precision has been restored 315 CHECK(ss.precision() == 3); 316 } 317 } 318 319 SECTION("round trips") 320 { 321 for (const auto& s : 322 {"3.141592653589793", "1000000000000000010E5" 323 }) 324 { 325 json j1 = json::parse(s); 326 std::string s1 = j1.dump(); 327 json j2 = json::parse(s1); 328 std::string s2 = j2.dump(); 329 CHECK(s1 == s2); 330 } 331 } 332 333 SECTION("return the type of the object (explicit)") 334 { 335 SECTION("null") 336 { 337 json j = nullptr; 338 CHECK(j.type() == json::value_t::null); 339 } 340 341 SECTION("object") 342 { 343 json j = {{"foo", "bar"}}; 344 CHECK(j.type() == json::value_t::object); 345 } 346 347 SECTION("array") 348 { 349 json j = {1, 2, 3, 4}; 350 CHECK(j.type() == json::value_t::array); 351 } 352 353 SECTION("boolean") 354 { 355 json j = true; 356 CHECK(j.type() == json::value_t::boolean); 357 } 358 359 SECTION("string") 360 { 361 json j = "Hello world"; 362 CHECK(j.type() == json::value_t::string); 363 } 364 365 SECTION("number (integer)") 366 { 367 json j = 23; 368 CHECK(j.type() == json::value_t::number_integer); 369 } 370 371 SECTION("number (unsigned)") 372 { 373 json j = 23u; 374 CHECK(j.type() == json::value_t::number_unsigned); 375 } 376 377 SECTION("number (floating-point)") 378 { 379 json j = 42.23; 380 CHECK(j.type() == json::value_t::number_float); 381 } 382 } 383 384 SECTION("return the type of the object (implicit)") 385 { 386 SECTION("null") 387 { 388 json j = nullptr; 389 json::value_t t = j; 390 CHECK(t == j.type()); 391 } 392 393 SECTION("object") 394 { 395 json j = {{"foo", "bar"}}; 396 json::value_t t = j; 397 CHECK(t == j.type()); 398 } 399 400 SECTION("array") 401 { 402 json j = {1, 2, 3, 4}; 403 json::value_t t = j; 404 CHECK(t == j.type()); 405 } 406 407 SECTION("boolean") 408 { 409 json j = true; 410 json::value_t t = j; 411 CHECK(t == j.type()); 412 } 413 414 SECTION("string") 415 { 416 json j = "Hello world"; 417 json::value_t t = j; 418 CHECK(t == j.type()); 419 } 420 421 SECTION("number (integer)") 422 { 423 json j = 23; 424 json::value_t t = j; 425 CHECK(t == j.type()); 426 } 427 428 SECTION("number (unsigned)") 429 { 430 json j = 23u; 431 json::value_t t = j; 432 CHECK(t == j.type()); 433 } 434 435 SECTION("number (floating-point)") 436 { 437 json j = 42.23; 438 json::value_t t = j; 439 CHECK(t == j.type()); 440 } 441 } 442 } 443