summaryrefslogtreecommitdiff
path: root/json4cpp/tests/src/unit-serialization.cpp
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:42:50 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:42:50 +0300
commit5fad10f89c485cfdc7b99011f07609f8871160d4 (patch)
tree1860b39753b652dfe54d3cbbc80c875f40198d1f /json4cpp/tests/src/unit-serialization.cpp
parent292baed7ac0cf84263263966ed32ed113cae857f (diff)
parent9a737481aed085fd289f82dff1fa8c3c66627a7e (diff)
downloadProject-Tick-5fad10f89c485cfdc7b99011f07609f8871160d4.tar.gz
Project-Tick-5fad10f89c485cfdc7b99011f07609f8871160d4.zip
Add 'json4cpp/' from commit '9a737481aed085fd289f82dff1fa8c3c66627a7e'
git-subtree-dir: json4cpp git-subtree-mainline: 292baed7ac0cf84263263966ed32ed113cae857f git-subtree-split: 9a737481aed085fd289f82dff1fa8c3c66627a7e
Diffstat (limited to 'json4cpp/tests/src/unit-serialization.cpp')
-rw-r--r--json4cpp/tests/src/unit-serialization.cpp297
1 files changed, 297 insertions, 0 deletions
diff --git a/json4cpp/tests/src/unit-serialization.cpp b/json4cpp/tests/src/unit-serialization.cpp
new file mode 100644
index 0000000000..5c2ab81482
--- /dev/null
+++ b/json4cpp/tests/src/unit-serialization.cpp
@@ -0,0 +1,297 @@
+// __ _____ _____ _____
+// __| | __| | | | JSON for Modern C++ (supporting code)
+// | | |__ | | | | | | version 3.12.0
+// |_____|_____|_____|_|___| https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#include "doctest_compatibility.h"
+
+#include <nlohmann/json.hpp>
+using nlohmann::json;
+
+#include <sstream>
+#include <iomanip>
+
+TEST_CASE("serialization")
+{
+ SECTION("operator<<")
+ {
+ SECTION("no given width")
+ {
+ std::stringstream ss;
+ const json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
+ ss << j;
+ CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]");
+ }
+
+ SECTION("given width")
+ {
+ std::stringstream ss;
+ const json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
+ ss << std::setw(4) << j;
+ CHECK(ss.str() ==
+ "[\n \"foo\",\n 1,\n 2,\n 3,\n false,\n {\n \"one\": 1\n }\n]");
+ }
+
+ SECTION("given fill")
+ {
+ std::stringstream ss;
+ const json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
+ ss << std::setw(1) << std::setfill('\t') << j;
+ CHECK(ss.str() ==
+ "[\n\t\"foo\",\n\t1,\n\t2,\n\t3,\n\tfalse,\n\t{\n\t\t\"one\": 1\n\t}\n]");
+ }
+ }
+
+ SECTION("operator>>")
+ {
+ SECTION("no given width")
+ {
+ std::stringstream ss;
+ const json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
+ j >> ss;
+ CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]");
+ }
+
+ SECTION("given width")
+ {
+ std::stringstream ss;
+ const json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
+ ss.width(4);
+ j >> ss;
+ CHECK(ss.str() ==
+ "[\n \"foo\",\n 1,\n 2,\n 3,\n false,\n {\n \"one\": 1\n }\n]");
+ }
+
+ SECTION("given fill")
+ {
+ std::stringstream ss;
+ const json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
+ ss.width(1);
+ ss.fill('\t');
+ j >> ss;
+ CHECK(ss.str() ==
+ "[\n\t\"foo\",\n\t1,\n\t2,\n\t3,\n\tfalse,\n\t{\n\t\t\"one\": 1\n\t}\n]");
+ }
+ }
+
+ SECTION("dump")
+ {
+ SECTION("invalid character")
+ {
+ const json j = "ä\xA9ü";
+
+ CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9", json::type_error&);
+ 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&);
+ CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"äü\"");
+ CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"ä\xEF\xBF\xBDü\"");
+ CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"\\u00e4\\ufffd\\u00fc\"");
+ }
+
+ SECTION("ending with incomplete character")
+ {
+ const json j = "123\xC2";
+
+ CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&);
+ CHECK_THROWS_AS(j.dump(1, ' ', false, json::error_handler_t::strict), json::type_error&);
+ CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123\"");
+ CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\"");
+ CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd\"");
+ }
+
+ SECTION("unexpected character")
+ {
+ const json j = "123\xF1\xB0\x34\x35\x36";
+
+ CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] invalid UTF-8 byte at index 5: 0x34", json::type_error&);
+ CHECK_THROWS_AS(j.dump(1, ' ', false, json::error_handler_t::strict), json::type_error&);
+ CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123456\"");
+ CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\x34\x35\x36\"");
+ CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd456\"");
+ }
+
+ SECTION("U+FFFD Substitution of Maximal Subparts")
+ {
+ // Some tests (mostly) from
+ // https://www.unicode.org/versions/Unicode11.0.0/ch03.pdf
+ // Section 3.9 -- U+FFFD Substitution of Maximal Subparts
+
+ auto test = [&](std::string const & input, std::string const & expected)
+ {
+ const json j = input;
+ CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"" + expected + "\"");
+ };
+
+ test("\xC2", "\\ufffd");
+ test("\xC2\x41\x42", "\\ufffd" "\x41" "\x42");
+ test("\xC2\xF4", "\\ufffd" "\\ufffd");
+
+ test("\xF0\x80\x80\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
+ test("\xF1\x80\x80\x41", "\\ufffd" "\x41");
+ test("\xF2\x80\x80\x41", "\\ufffd" "\x41");
+ test("\xF3\x80\x80\x41", "\\ufffd" "\x41");
+ test("\xF4\x80\x80\x41", "\\ufffd" "\x41");
+ test("\xF5\x80\x80\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
+
+ test("\xF0\x90\x80\x41", "\\ufffd" "\x41");
+ test("\xF1\x90\x80\x41", "\\ufffd" "\x41");
+ test("\xF2\x90\x80\x41", "\\ufffd" "\x41");
+ test("\xF3\x90\x80\x41", "\\ufffd" "\x41");
+ test("\xF4\x90\x80\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
+ test("\xF5\x90\x80\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
+
+ test("\xC0\xAF\xE0\x80\xBF\xF0\x81\x82\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
+ test("\xED\xA0\x80\xED\xBF\xBF\xED\xAF\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
+ test("\xF4\x91\x92\x93\xFF\x41\x80\xBF\x42", "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\x41" "\\ufffd""\\ufffd" "\x42");
+ test("\xE1\x80\xE2\xF0\x91\x92\xF1\xBF\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
+ }
+ }
+
+ SECTION("to_string")
+ {
+ auto test = [&](std::string const & input, std::string const & expected)
+ {
+ using std::to_string;
+ const json j = input;
+ CHECK(to_string(j) == "\"" + expected + "\"");
+ };
+
+ test(R"({"x":5,"y":6})", R"({\"x\":5,\"y\":6})");
+ test("{\"x\":[10,null,null,null]}", R"({\"x\":[10,null,null,null]})");
+ test("test", "test");
+ test("[3,\"false\",false]", R"([3,\"false\",false])");
+ }
+}
+
+TEST_CASE_TEMPLATE("serialization for extreme integer values", T, int32_t, uint32_t, int64_t, uint64_t) // NOLINT(readability-math-missing-parentheses, bugprone-throwing-static-initialization)
+{
+ SECTION("minimum")
+ {
+ constexpr auto minimum = (std::numeric_limits<T>::min)();
+ const json j = minimum;
+ CHECK(j.dump() == std::to_string(minimum));
+ }
+
+ SECTION("maximum")
+ {
+ constexpr auto maximum = (std::numeric_limits<T>::max)();
+ const json j = maximum;
+ CHECK(j.dump() == std::to_string(maximum));
+ }
+}
+
+TEST_CASE("dump with binary values")
+{
+ auto binary = json::binary({1, 2, 3, 4});
+ auto binary_empty = json::binary({});
+ auto binary_with_subtype = json::binary({1, 2, 3, 4}, 128);
+ auto binary_empty_with_subtype = json::binary({}, 128);
+
+ const json object = {{"key", binary}};
+ const json object_empty = {{"key", binary_empty}};
+ const json object_with_subtype = {{"key", binary_with_subtype}};
+ const json object_empty_with_subtype = {{"key", binary_empty_with_subtype}};
+
+ const json array = {"value", 1, binary};
+ const json array_empty = {"value", 1, binary_empty};
+ const json array_with_subtype = {"value", 1, binary_with_subtype};
+ const json array_empty_with_subtype = {"value", 1, binary_empty_with_subtype};
+
+ SECTION("normal")
+ {
+ CHECK(binary.dump() == "{\"bytes\":[1,2,3,4],\"subtype\":null}");
+ CHECK(binary_empty.dump() == "{\"bytes\":[],\"subtype\":null}");
+ CHECK(binary_with_subtype.dump() == "{\"bytes\":[1,2,3,4],\"subtype\":128}");
+ CHECK(binary_empty_with_subtype.dump() == "{\"bytes\":[],\"subtype\":128}");
+
+ CHECK(object.dump() == "{\"key\":{\"bytes\":[1,2,3,4],\"subtype\":null}}");
+ CHECK(object_empty.dump() == "{\"key\":{\"bytes\":[],\"subtype\":null}}");
+ CHECK(object_with_subtype.dump() == "{\"key\":{\"bytes\":[1,2,3,4],\"subtype\":128}}");
+ CHECK(object_empty_with_subtype.dump() == "{\"key\":{\"bytes\":[],\"subtype\":128}}");
+
+ CHECK(array.dump() == "[\"value\",1,{\"bytes\":[1,2,3,4],\"subtype\":null}]");
+ CHECK(array_empty.dump() == "[\"value\",1,{\"bytes\":[],\"subtype\":null}]");
+ CHECK(array_with_subtype.dump() == "[\"value\",1,{\"bytes\":[1,2,3,4],\"subtype\":128}]");
+ CHECK(array_empty_with_subtype.dump() == "[\"value\",1,{\"bytes\":[],\"subtype\":128}]");
+ }
+
+ SECTION("pretty-printed")
+ {
+ CHECK(binary.dump(4) == "{\n"
+ " \"bytes\": [1, 2, 3, 4],\n"
+ " \"subtype\": null\n"
+ "}");
+ CHECK(binary_empty.dump(4) == "{\n"
+ " \"bytes\": [],\n"
+ " \"subtype\": null\n"
+ "}");
+ CHECK(binary_with_subtype.dump(4) == "{\n"
+ " \"bytes\": [1, 2, 3, 4],\n"
+ " \"subtype\": 128\n"
+ "}");
+ CHECK(binary_empty_with_subtype.dump(4) == "{\n"
+ " \"bytes\": [],\n"
+ " \"subtype\": 128\n"
+ "}");
+
+ CHECK(object.dump(4) == "{\n"
+ " \"key\": {\n"
+ " \"bytes\": [1, 2, 3, 4],\n"
+ " \"subtype\": null\n"
+ " }\n"
+ "}");
+ CHECK(object_empty.dump(4) == "{\n"
+ " \"key\": {\n"
+ " \"bytes\": [],\n"
+ " \"subtype\": null\n"
+ " }\n"
+ "}");
+ CHECK(object_with_subtype.dump(4) == "{\n"
+ " \"key\": {\n"
+ " \"bytes\": [1, 2, 3, 4],\n"
+ " \"subtype\": 128\n"
+ " }\n"
+ "}");
+ CHECK(object_empty_with_subtype.dump(4) == "{\n"
+ " \"key\": {\n"
+ " \"bytes\": [],\n"
+ " \"subtype\": 128\n"
+ " }\n"
+ "}");
+
+ CHECK(array.dump(4) == "[\n"
+ " \"value\",\n"
+ " 1,\n"
+ " {\n"
+ " \"bytes\": [1, 2, 3, 4],\n"
+ " \"subtype\": null\n"
+ " }\n"
+ "]");
+ CHECK(array_empty.dump(4) == "[\n"
+ " \"value\",\n"
+ " 1,\n"
+ " {\n"
+ " \"bytes\": [],\n"
+ " \"subtype\": null\n"
+ " }\n"
+ "]");
+ CHECK(array_with_subtype.dump(4) == "[\n"
+ " \"value\",\n"
+ " 1,\n"
+ " {\n"
+ " \"bytes\": [1, 2, 3, 4],\n"
+ " \"subtype\": 128\n"
+ " }\n"
+ "]");
+ CHECK(array_empty_with_subtype.dump(4) == "[\n"
+ " \"value\",\n"
+ " 1,\n"
+ " {\n"
+ " \"bytes\": [],\n"
+ " \"subtype\": 128\n"
+ " }\n"
+ "]");
+ }
+}