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