From 57b727af4e1eea4ea118ca5e5028fa7ce86fb538 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 21 Apr 2021 11:31:46 +0200 Subject: json: Escape strings using \u escape sequences, add test This allows us to correctly encode strings containing quotation marks, escape characters and control characters. The test case is a bit nasty because it embeds private-cachefile.cc for linkage reasons. --- test/libapt/json_test.cc | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 test/libapt/json_test.cc (limited to 'test/libapt/json_test.cc') diff --git a/test/libapt/json_test.cc b/test/libapt/json_test.cc new file mode 100644 index 000000000..e3317afc4 --- /dev/null +++ b/test/libapt/json_test.cc @@ -0,0 +1,45 @@ +#include +#include "../../apt-private/private-cachefile.cc" +#include "../../apt-private/private-json-hooks.cc" +#include +#include + +TEST(JsonTest, JsonString) +{ + std::ostringstream os; + + // Check for escaping backslash and quotation marks, and ensure that we do not change number formatting + JsonWriter(os).value("H al\"l\\o").value(17); + + EXPECT_EQ("\"H al\\u0022l\\u005Co\"17", os.str()); + + for (int i = 0; i <= 0x1F; i++) + { + os.str(""); + + JsonWriter(os).encodeString(os, std::string("X") + char(i) + "Z"); + + std::string exp; + strprintf(exp, "\"X\\u%04XZ\"", i); + + EXPECT_EQ(exp, os.str()); + } +} + +TEST(JsonTest, JsonObject) +{ + std::ostringstream os; + + JsonWriter(os).beginObject().name("key").value("value").endObject(); + + EXPECT_EQ("{\"key\":\"value\"}", os.str()); +} + +TEST(JsonTest, JsonArrayAndValues) +{ + std::ostringstream os; + + JsonWriter(os).beginArray().value(0).value("value").value(1).value(true).endArray(); + + EXPECT_EQ("[0,\"value\",1,true]", os.str()); +} -- cgit v1.2.3-70-g09d2 From 09e3c0c855e339216784a1d43715c3ae2d79ec23 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 21 Apr 2021 12:17:55 +0200 Subject: json: Actually pop states The JSON encoder only looked at the top state, but did not pop it, so if we nested objects, we got stuck in whatever the last state we pushed aside was, so in our example, we wrongly get a comma inserted _after_ key "b": {"a":[{}], "b":,[{}] } --- apt-private/private-json-hooks.cc | 1 + test/libapt/json_test.cc | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) (limited to 'test/libapt/json_test.cc') diff --git a/apt-private/private-json-hooks.cc b/apt-private/private-json-hooks.cc index b61829cbf..ce1665b18 100644 --- a/apt-private/private-json-hooks.cc +++ b/apt-private/private-json-hooks.cc @@ -79,6 +79,7 @@ class APT_HIDDEN JsonWriter void popState() { this->state = old_states.top(); + old_states.pop(); } public: diff --git a/test/libapt/json_test.cc b/test/libapt/json_test.cc index e3317afc4..9c29936f6 100644 --- a/test/libapt/json_test.cc +++ b/test/libapt/json_test.cc @@ -43,3 +43,19 @@ TEST(JsonTest, JsonArrayAndValues) EXPECT_EQ("[0,\"value\",1,true]", os.str()); } +TEST(JsonTest, JsonStackRegression) +{ + std::ostringstream os; + + JsonWriter w(os); + + // Nest those things deeply such that we transition states: + // object -> array -> object; -> array -> object + // Older versions never popped back and got stuck on array state. + w.beginObject(); + w.name("a").beginArray().beginObject().endObject().endArray(); + w.name("b").beginArray().beginObject().endObject().endArray(); + w.endObject(); + + EXPECT_EQ("{\"a\":[{}],\"b\":[{}]}", os.str()); +} -- cgit v1.2.3-70-g09d2 From b5211b9b213273c642a790ae3c3f3bbe1a4cf51e Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 21 Apr 2021 12:21:41 +0200 Subject: json: Encode NULL strings as null This is the only nullable thing we have here. --- apt-private/private-json-hooks.cc | 5 ++++- test/libapt/json_test.cc | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'test/libapt/json_test.cc') diff --git a/apt-private/private-json-hooks.cc b/apt-private/private-json-hooks.cc index ce1665b18..7991a7d77 100644 --- a/apt-private/private-json-hooks.cc +++ b/apt-private/private-json-hooks.cc @@ -141,7 +141,10 @@ class APT_HIDDEN JsonWriter JsonWriter &value(const char *value) { maybeComma(); - encodeString(os, value); + if (value == nullptr) + os << "null"; + else + encodeString(os, value); return *this; } JsonWriter &value(int value) diff --git a/test/libapt/json_test.cc b/test/libapt/json_test.cc index 9c29936f6..ee8f3cebe 100644 --- a/test/libapt/json_test.cc +++ b/test/libapt/json_test.cc @@ -59,3 +59,11 @@ TEST(JsonTest, JsonStackRegression) EXPECT_EQ("{\"a\":[{}],\"b\":[{}]}", os.str()); } +TEST(JsonTest, JsonNull) +{ + std::ostringstream os; + + JsonWriter(os).value(nullptr); + + EXPECT_EQ("null", os.str()); +} -- cgit v1.2.3-70-g09d2