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 14#include <sstream> 15#include <iomanip> 16 17TEST_CASE("serialization") 18{ 19 SECTION("operator<<") 20 { 21 SECTION("no given width") 22 { 23 std::stringstream ss; 24 json j = {"foo", 1, 2, 3, false, {{"one", 1}}}; 25 ss << j; 26 CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]"); 27 } 28 29 SECTION("given width") 30 { 31 std::stringstream ss; 32 json j = {"foo", 1, 2, 3, false, {{"one", 1}}}; 33 ss << std::setw(4) << j; 34 CHECK(ss.str() == 35 "[\n \"foo\",\n 1,\n 2,\n 3,\n false,\n {\n \"one\": 1\n }\n]"); 36 } 37 38 SECTION("given fill") 39 { 40 std::stringstream ss; 41 json j = {"foo", 1, 2, 3, false, {{"one", 1}}}; 42 ss << std::setw(1) << std::setfill('\t') << j; 43 CHECK(ss.str() == 44 "[\n\t\"foo\",\n\t1,\n\t2,\n\t3,\n\tfalse,\n\t{\n\t\t\"one\": 1\n\t}\n]"); 45 } 46 } 47 48 SECTION("operator>>") 49 { 50 SECTION("no given width") 51 { 52 std::stringstream ss; 53 json j = {"foo", 1, 2, 3, false, {{"one", 1}}}; 54 j >> ss; 55 CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]"); 56 } 57 58 SECTION("given width") 59 { 60 std::stringstream ss; 61 json j = {"foo", 1, 2, 3, false, {{"one", 1}}}; 62 ss.width(4); 63 j >> ss; 64 CHECK(ss.str() == 65 "[\n \"foo\",\n 1,\n 2,\n 3,\n false,\n {\n \"one\": 1\n }\n]"); 66 } 67 68 SECTION("given fill") 69 { 70 std::stringstream ss; 71 json j = {"foo", 1, 2, 3, false, {{"one", 1}}}; 72 ss.width(1); 73 ss.fill('\t'); 74 j >> ss; 75 CHECK(ss.str() == 76 "[\n\t\"foo\",\n\t1,\n\t2,\n\t3,\n\tfalse,\n\t{\n\t\t\"one\": 1\n\t}\n]"); 77 } 78 } 79 80 SECTION("dump") 81 { 82 SECTION("invalid character") 83 { 84 json j = "ä\xA9ü"; 85 86 CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9", json::type_error&); 87 CHECK_THROWS_WITH_AS(j.dump(1, ' ', false, json::error_handler_t::strict), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9", json::type_error&); 88 CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"äü\""); 89 CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"ä\xEF\xBF\xBDü\""); 90 CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"\\u00e4\\ufffd\\u00fc\""); 91 } 92 93 SECTION("ending with incomplete character") 94 { 95 json j = "123\xC2"; 96 97 CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&); 98 CHECK_THROWS_AS(j.dump(1, ' ', false, json::error_handler_t::strict), json::type_error&); 99 CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123\""); 100 CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\""); 101 CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd\""); 102 } 103 104 SECTION("unexpected character") 105 { 106 json j = "123\xF1\xB0\x34\x35\x36"; 107 108 CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] invalid UTF-8 byte at index 5: 0x34", json::type_error&); 109 CHECK_THROWS_AS(j.dump(1, ' ', false, json::error_handler_t::strict), json::type_error&); 110 CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123456\""); 111 CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\x34\x35\x36\""); 112 CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd456\""); 113 } 114 115 SECTION("U+FFFD Substitution of Maximal Subparts") 116 { 117 // Some tests (mostly) from 118 // https://www.unicode.org/versions/Unicode11.0.0/ch03.pdf 119 // Section 3.9 -- U+FFFD Substitution of Maximal Subparts 120 121 auto test = [&](std::string const & input, std::string const & expected) 122 { 123 json j = input; 124 CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"" + expected + "\""); 125 }; 126 127 test("\xC2", "\\ufffd"); 128 test("\xC2\x41\x42", "\\ufffd" "\x41" "\x42"); 129 test("\xC2\xF4", "\\ufffd" "\\ufffd"); 130 131 test("\xF0\x80\x80\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\x41"); 132 test("\xF1\x80\x80\x41", "\\ufffd" "\x41"); 133 test("\xF2\x80\x80\x41", "\\ufffd" "\x41"); 134 test("\xF3\x80\x80\x41", "\\ufffd" "\x41"); 135 test("\xF4\x80\x80\x41", "\\ufffd" "\x41"); 136 test("\xF5\x80\x80\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\x41"); 137 138 test("\xF0\x90\x80\x41", "\\ufffd" "\x41"); 139 test("\xF1\x90\x80\x41", "\\ufffd" "\x41"); 140 test("\xF2\x90\x80\x41", "\\ufffd" "\x41"); 141 test("\xF3\x90\x80\x41", "\\ufffd" "\x41"); 142 test("\xF4\x90\x80\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\x41"); 143 test("\xF5\x90\x80\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\x41"); 144 145 test("\xC0\xAF\xE0\x80\xBF\xF0\x81\x82\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\x41"); 146 test("\xED\xA0\x80\xED\xBF\xBF\xED\xAF\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\x41"); 147 test("\xF4\x91\x92\x93\xFF\x41\x80\xBF\x42", "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\x41" "\\ufffd""\\ufffd" "\x42"); 148 test("\xE1\x80\xE2\xF0\x91\x92\xF1\xBF\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\x41"); 149 } 150 } 151 152 SECTION("to_string") 153 { 154 auto test = [&](std::string const & input, std::string const & expected) 155 { 156 using std::to_string; 157 json j = input; 158 CHECK(to_string(j) == "\"" + expected + "\""); 159 }; 160 161 test(R"({"x":5,"y":6})", R"({\"x\":5,\"y\":6})"); 162 test("{\"x\":[10,null,null,null]}", R"({\"x\":[10,null,null,null]})"); 163 test("test", "test"); 164 test("[3,\"false\",false]", R"([3,\"false\",false])"); 165 } 166} 167 168TEST_CASE_TEMPLATE("serialization for extreme integer values", T, int32_t, uint32_t, int64_t, uint64_t) 169{ 170 SECTION("minimum") 171 { 172 constexpr auto minimum = (std::numeric_limits<T>::min)(); 173 json j = minimum; 174 CHECK(j.dump() == std::to_string(minimum)); 175 } 176 177 SECTION("maximum") 178 { 179 constexpr auto maximum = (std::numeric_limits<T>::max)(); 180 json j = maximum; 181 CHECK(j.dump() == std::to_string(maximum)); 182 } 183} 184 185TEST_CASE("dump with binary values") 186{ 187 auto binary = json::binary({1, 2, 3, 4}); 188 auto binary_empty = json::binary({}); 189 auto binary_with_subtype = json::binary({1, 2, 3, 4}, 128); 190 auto binary_empty_with_subtype = json::binary({}, 128); 191 192 json object = {{"key", binary}}; 193 json object_empty = {{"key", binary_empty}}; 194 json object_with_subtype = {{"key", binary_with_subtype}}; 195 json object_empty_with_subtype = {{"key", binary_empty_with_subtype}}; 196 197 json array = {"value", 1, binary}; 198 json array_empty = {"value", 1, binary_empty}; 199 json array_with_subtype = {"value", 1, binary_with_subtype}; 200 json array_empty_with_subtype = {"value", 1, binary_empty_with_subtype}; 201 202 SECTION("normal") 203 { 204 CHECK(binary.dump() == "{\"bytes\":[1,2,3,4],\"subtype\":null}"); 205 CHECK(binary_empty.dump() == "{\"bytes\":[],\"subtype\":null}"); 206 CHECK(binary_with_subtype.dump() == "{\"bytes\":[1,2,3,4],\"subtype\":128}"); 207 CHECK(binary_empty_with_subtype.dump() == "{\"bytes\":[],\"subtype\":128}"); 208 209 CHECK(object.dump() == "{\"key\":{\"bytes\":[1,2,3,4],\"subtype\":null}}"); 210 CHECK(object_empty.dump() == "{\"key\":{\"bytes\":[],\"subtype\":null}}"); 211 CHECK(object_with_subtype.dump() == "{\"key\":{\"bytes\":[1,2,3,4],\"subtype\":128}}"); 212 CHECK(object_empty_with_subtype.dump() == "{\"key\":{\"bytes\":[],\"subtype\":128}}"); 213 214 CHECK(array.dump() == "[\"value\",1,{\"bytes\":[1,2,3,4],\"subtype\":null}]"); 215 CHECK(array_empty.dump() == "[\"value\",1,{\"bytes\":[],\"subtype\":null}]"); 216 CHECK(array_with_subtype.dump() == "[\"value\",1,{\"bytes\":[1,2,3,4],\"subtype\":128}]"); 217 CHECK(array_empty_with_subtype.dump() == "[\"value\",1,{\"bytes\":[],\"subtype\":128}]"); 218 } 219 220 SECTION("pretty-printed") 221 { 222 CHECK(binary.dump(4) == "{\n" 223 " \"bytes\": [1, 2, 3, 4],\n" 224 " \"subtype\": null\n" 225 "}"); 226 CHECK(binary_empty.dump(4) == "{\n" 227 " \"bytes\": [],\n" 228 " \"subtype\": null\n" 229 "}"); 230 CHECK(binary_with_subtype.dump(4) == "{\n" 231 " \"bytes\": [1, 2, 3, 4],\n" 232 " \"subtype\": 128\n" 233 "}"); 234 CHECK(binary_empty_with_subtype.dump(4) == "{\n" 235 " \"bytes\": [],\n" 236 " \"subtype\": 128\n" 237 "}"); 238 239 CHECK(object.dump(4) == "{\n" 240 " \"key\": {\n" 241 " \"bytes\": [1, 2, 3, 4],\n" 242 " \"subtype\": null\n" 243 " }\n" 244 "}"); 245 CHECK(object_empty.dump(4) == "{\n" 246 " \"key\": {\n" 247 " \"bytes\": [],\n" 248 " \"subtype\": null\n" 249 " }\n" 250 "}"); 251 CHECK(object_with_subtype.dump(4) == "{\n" 252 " \"key\": {\n" 253 " \"bytes\": [1, 2, 3, 4],\n" 254 " \"subtype\": 128\n" 255 " }\n" 256 "}"); 257 CHECK(object_empty_with_subtype.dump(4) == "{\n" 258 " \"key\": {\n" 259 " \"bytes\": [],\n" 260 " \"subtype\": 128\n" 261 " }\n" 262 "}"); 263 264 CHECK(array.dump(4) == "[\n" 265 " \"value\",\n" 266 " 1,\n" 267 " {\n" 268 " \"bytes\": [1, 2, 3, 4],\n" 269 " \"subtype\": null\n" 270 " }\n" 271 "]"); 272 CHECK(array_empty.dump(4) == "[\n" 273 " \"value\",\n" 274 " 1,\n" 275 " {\n" 276 " \"bytes\": [],\n" 277 " \"subtype\": null\n" 278 " }\n" 279 "]"); 280 CHECK(array_with_subtype.dump(4) == "[\n" 281 " \"value\",\n" 282 " 1,\n" 283 " {\n" 284 " \"bytes\": [1, 2, 3, 4],\n" 285 " \"subtype\": 128\n" 286 " }\n" 287 "]"); 288 CHECK(array_empty_with_subtype.dump(4) == "[\n" 289 " \"value\",\n" 290 " 1,\n" 291 " {\n" 292 " \"bytes\": [],\n" 293 " \"subtype\": 128\n" 294 " }\n" 295 "]"); 296 } 297} 298