unit-serialization.cpp 11 KB

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