diff --git a/src/JsonDumper.h b/src/JsonDumper.h index 996f97d..c493857 100644 --- a/src/JsonDumper.h +++ b/src/JsonDumper.h @@ -39,7 +39,7 @@ class JsonDumper { JsonDumper& StartObject(bool is_array = false) { - NextItem(); + NextItem(true); Push(is_array); s << (is_array ? '[' : '{'); if (state.wrap) { @@ -106,19 +106,28 @@ class JsonDumper { return *this << std::string_view(str); } + JsonDumper& operator<<(char* str) + { + return *this << std::string_view(str); + } + JsonDumper& operator<<(const std::string& str) { return *this << std::string_view(str); } + JsonDumper& operator<<(char ch) + { +// char tmp[2] = { ch, '\0' }; + return *this << std::string_view(&ch, 1); + } + JsonDumper& operator<<(double v) { if (std::isnan(v)) { return *this << "nan"; } - if (state.in_array) { - NextItem(); - } + NextItem(); s << v; member_started = false; return *this; @@ -134,9 +143,7 @@ class JsonDumper { JsonDumper& operator<<(int64_t v) { - if (state.in_array) { - NextItem(); - } + NextItem(); s << v; member_started = false; return *this; @@ -144,9 +151,7 @@ class JsonDumper { JsonDumper& operator<<(uint64_t v) { - if (state.in_array) { - NextItem(); - } + NextItem(); s << v; member_started = false; return *this; @@ -161,9 +166,7 @@ class JsonDumper { template JsonDumper& operator<<(T v) { - if (state.in_array) { - NextItem(); - } + NextItem(); s << '"' << v << '"'; member_started = false; return *this; @@ -171,9 +174,7 @@ class JsonDumper { JsonDumper& operator<<(std::string_view sv) { - if (state.in_array) { - NextItem(); - } + NextItem(); s << '"'; for (auto c : sv) { if ((c == '"') || (c == '\\') || (('\0' < c) && (c < ' '))) { @@ -226,8 +227,12 @@ class JsonDumper { state = state_storage.top(); state_storage.pop(); } - void NextItem() + + void NextItem(bool force = false) { + if (!force && !state.in_array) { + return; + } if (!state.first_element && state.in_array) { if (state_storage.size() > 1) { s << ','; diff --git a/tests/JsonDumperTest.cpp b/tests/JsonDumperTest.cpp index bcd9348..188a7b4 100644 --- a/tests/JsonDumperTest.cpp +++ b/tests/JsonDumperTest.cpp @@ -1,6 +1,36 @@ #include "JsonDumper.h" #include "gtest/gtest.h" +static void TestEscape(char ch, const char* escaped) { + char expected[100]; + snprintf(expected, sizeof(expected), "\"%s\"", escaped); + { //As char + std::ostringstream ss; + JsonDumper j(ss); + j << ch; + EXPECT_EQ(expected, ss.str()); + } + { // As string + std::ostringstream ss; + JsonDumper j(ss); + char str[2] = { ch, '\0' }; + j << str; + EXPECT_EQ(expected, ss.str()); + } +} + +TEST(JsonDumper, Escape) { + TestEscape('A', "A"); //No escape + TestEscape('"', "\\\""); + TestEscape('\\', "\\\\"); + TestEscape('\n', "\\n"); + TestEscape('\r', "\\r"); + TestEscape('\b', "\\b"); + TestEscape('\f', "\\f"); + TestEscape('\t', "\\t"); + TestEscape('\x01', "\\u0001"); +} + TEST(JsonDumper, EmptyObject) { std::ostringstream ss; @@ -31,6 +61,8 @@ static void DumpTest(JsonDumper& j) j.StartMember("UInt16") << (uint16_t)10; j.StartMember("UInt32") << (uint32_t)10; j.StartMember("UInt64") << (uint64_t)10; + j.StartMember("double") << 12.345; + j.StartMember("float") << 12.345f; j.StartMember("Char") << (char)'c'; j.StartMember("c_str") << "c_string"; j.StartMember("std_str") << std::string("std::string"); @@ -61,6 +93,8 @@ TEST(JsonDumper, Object) " \"UInt16\": 10,\n" " \"UInt32\": 10,\n" " \"UInt64\": 10,\n" + " \"double\": 12.345,\n" + " \"float\": 12.345,\n" " \"Char\": \"c\",\n" " \"c_str\": \"c_string\",\n" " \"std_str\": \"std::string\",\n"