From 8f3b5b5cbe21d24c362b3541c1280de1c2422d4e Mon Sep 17 00:00:00 2001 From: sina-rostami Date: Sun, 21 Jan 2024 15:57:41 +0330 Subject: [PATCH] Add indentation to json dump method Closes #747 --- include/crow/json.h | 51 +++++++++++++++++++++++++++++++---- tests/unittest.cpp | 66 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 5 deletions(-) diff --git a/include/crow/json.h b/include/crow/json.h index d0a2138c0..ed1a4d993 100644 --- a/include/crow/json.h +++ b/include/crow/json.h @@ -1826,7 +1826,16 @@ namespace crow out.push_back('"'); } - inline void dump_internal(const wvalue& v, std::string& out) const + inline void dump_indentation_part(std::string& out, const int indent, const char separator, const int indent_level) const + { + out.push_back('\n'); + for (int i = 0; i < indent_level; i++) + for (int j = 0; j < indent; j++) + out.push_back(separator); + } + + + inline void dump_internal(const wvalue& v, std::string& out, const int indent, const char separator, const int indent_level = 0) const { switch (v.t_) { @@ -1909,6 +1918,10 @@ namespace crow case type::List: { out.push_back('['); + + if (indent >= 0) + dump_indentation_part(out, indent, separator, indent_level + 1); + if (v.l) { bool first = true; @@ -1917,17 +1930,28 @@ namespace crow if (!first) { out.push_back(','); + + if (indent >= 0) + dump_indentation_part(out, indent, separator, indent_level + 1); } first = false; - dump_internal(x, out); + dump_internal(x, out, indent, separator, indent_level + 1); } } + + if (indent >= 0) + dump_indentation_part(out, indent, separator, indent_level); + out.push_back(']'); } break; case type::Object: { out.push_back('{'); + + if (indent >= 0) + dump_indentation_part(out, indent, separator, indent_level + 1); + if (v.o) { bool first = true; @@ -1936,13 +1960,23 @@ namespace crow if (!first) { out.push_back(','); + if (indent >= 0) + dump_indentation_part(out, indent, separator, indent_level + 1); } first = false; dump_string(kv.first, out); out.push_back(':'); - dump_internal(kv.second, out); + + if (indent >= 0) + out.push_back(' '); + + dump_internal(kv.second, out, indent, separator, indent_level + 1); } } + + if (indent >= 0) + dump_indentation_part(out, indent, separator, indent_level); + out.push_back('}'); } break; @@ -1954,13 +1988,20 @@ namespace crow } public: - std::string dump() const + std::string dump(const int indent, const char separator = ' ') const { std::string ret; ret.reserve(estimate_length()); - dump_internal(*this, ret); + dump_internal(*this, ret, indent, separator); return ret; } + + std::string dump() const + { + static constexpr int DontIndent = -1; + + return dump(DontIndent); + } }; // Used for accessing the internals of a wvalue diff --git a/tests/unittest.cpp b/tests/unittest.cpp index b280f07d6..d6f7bc3ea 100644 --- a/tests/unittest.cpp +++ b/tests/unittest.cpp @@ -921,6 +921,72 @@ TEST_CASE("json_write") CHECK(R"({"scores":[1,2,3]})" == y.dump()); } // json_write +TEST_CASE("json_write_with_indent") +{ + static constexpr int IndentationLevelOne = 1; + static constexpr int IndentationLevelTwo = 2; + static constexpr int IndentationLevelFour = 4; + + json::wvalue y; + + y["scores"][0] = 1; + y["scores"][1] = "king"; + y["scores"][2][0] = "real"; + y["scores"][2][1] = false; + y["scores"][2][2] = true; + + CHECK(R"({ + "scores": [ + 1, + "king", + [ + "real", + false, + true + ] + ] +})" == y.dump(IndentationLevelOne)); + + CHECK(R"({ + "scores": [ + 1, + "king", + [ + "real", + false, + true + ] + ] +})" == y.dump(IndentationLevelTwo)); + + CHECK(R"({ + "scores": [ + 1, + "king", + [ + "real", + false, + true + ] + ] +})" == y.dump(IndentationLevelFour)); + + static constexpr char TabSeparator = '\t'; + + CHECK(R"({ + "scores": [ + 1, + "king", + [ + "real", + false, + true + ] + ] +})" == y.dump(IndentationLevelOne, TabSeparator)); +} // json_write_with_indent + + TEST_CASE("json_copy_r_to_w_to_w_to_r") { json::rvalue r = json::load(