diff options
author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/json/writer/json_ut.cpp |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/json/writer/json_ut.cpp')
-rw-r--r-- | library/cpp/json/writer/json_ut.cpp | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/library/cpp/json/writer/json_ut.cpp b/library/cpp/json/writer/json_ut.cpp new file mode 100644 index 00000000000..9980555683f --- /dev/null +++ b/library/cpp/json/writer/json_ut.cpp @@ -0,0 +1,307 @@ +#include <library/cpp/testing/unittest/registar.h> +#include <util/system/sanitizers.h> + +#include "json.h" +#include <library/cpp/json/json_value.h> + +#include <limits> + +Y_UNIT_TEST_SUITE(JsonWriter) { + Y_UNIT_TEST(Struct) { + NJsonWriter::TBuf w; + w.BeginList(); + w.BeginObject() + .WriteKey("key") + .WriteString("value") + .UnsafeWritePair("\"xk\":13") + .WriteKey("key2") + .BeginList() + .BeginObject() + .EndObject() + .BeginObject() + .EndObject() + .EndList() + .EndObject(); + w.WriteInt(43); + w.UnsafeWriteValue("\"x\""); + w.WriteString("..."); + w.EndList(); + const char* exp = "[{\"key\":\"value\",\"xk\":13,\"key2\":[{},{}]},43,\"x\",\"...\"]"; + UNIT_ASSERT_EQUAL(w.Str(), exp); + } + Y_UNIT_TEST(EscapedString) { + NJsonWriter::TBuf w(NJsonWriter::HEM_ESCAPE_HTML); + w.WriteString(" \n \r \t \007 \b \f ' <tag> &ent; \"txt\" "); + TString ws = w.Str(); + const char* exp = "\" \\n \\r \\t \\u0007 \\b \\f ' <tag> &ent; "txt" \""; + UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp); + } + Y_UNIT_TEST(UnescapedString) { + NJsonWriter::TBuf w; + w.WriteString(" \n \r \t \b \f '; -- <tag> &ent; \"txt\"", NJsonWriter::HEM_DONT_ESCAPE_HTML); + TString ws = w.Str(); + const char* exp = "\" \\n \\r \\t \\b \\f \\u0027; -- \\u003Ctag\\u003E &ent; \\\"txt\\\"\""; + UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp); + } + Y_UNIT_TEST(UnescapedChaining) { + NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML); + w.UnsafeWriteRawBytes("(", 1); + w.BeginList().WriteString("<>&'\\").BeginList(); + w.EndList().EndList(); + TString ws = w.Str(); + const char* exp = "([\"\\u003C\\u003E&\\u0027\\\\\",[]]"; + UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp); + } + Y_UNIT_TEST(Utf8) { + TString ws = NJsonWriter::TBuf().WriteString("яЯ σΣ ש א").Str(); + const char* exp = "\"яЯ σΣ ש א\""; + UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp); + } + Y_UNIT_TEST(WrongObject) { + NJsonWriter::TBuf w; + w.BeginObject(); + UNIT_ASSERT_EXCEPTION(w.WriteString("hehe"), NJsonWriter::TError); + } + Y_UNIT_TEST(WrongList) { + NJsonWriter::TBuf w; + w.BeginList(); + UNIT_ASSERT_EXCEPTION(w.WriteKey("hehe"), NJsonWriter::TError); + } + Y_UNIT_TEST(Incomplete) { + NJsonWriter::TBuf w; + w.BeginList(); + UNIT_ASSERT_EXCEPTION(w.Str(), NJsonWriter::TError); + } + Y_UNIT_TEST(BareKey) { + NJsonWriter::TBuf w; + w.BeginObject() + .CompatWriteKeyWithoutQuotes("p") + .WriteInt(1) + .CompatWriteKeyWithoutQuotes("n") + .WriteInt(0) + .EndObject(); + TString ws = w.Str(); + const char* exp = "{p:1,n:0}"; + UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp); + } + Y_UNIT_TEST(UnescapedStringInObject) { + NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML); + w.BeginObject().WriteKey("key").WriteString("</&>'").EndObject(); + TString ws = w.Str(); + const char* exp = "{\"key\":\"\\u003C\\/&\\u003E\\u0027\"}"; + UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp); + } + Y_UNIT_TEST(ForeignStreamStr) { + NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML, &Cerr); + UNIT_ASSERT_EXCEPTION(w.Str(), NJsonWriter::TError); + } + Y_UNIT_TEST(ForeignStreamValue) { + TStringStream ss; + NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML, &ss); + w.WriteInt(1543); + UNIT_ASSERT_STRINGS_EQUAL(ss.Str(), "1543"); + } + Y_UNIT_TEST(Indentation) { + NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML); + w.SetIndentSpaces(2); + w.BeginList() + .WriteInt(1) + .WriteString("hello") + .BeginObject() + .WriteKey("abc") + .WriteInt(3) + .WriteKey("def") + .WriteInt(4) + .EndObject() + .EndList(); + const char* exp = "[\n" + " 1,\n" + " \"hello\",\n" + " {\n" + " \"abc\":3,\n" + " \"def\":4\n" + " }\n" + "]"; + UNIT_ASSERT_STRINGS_EQUAL(exp, w.Str()); + } + Y_UNIT_TEST(WriteJsonValue) { + using namespace NJson; + TJsonValue val; + val.AppendValue(1); + val.AppendValue("2"); + val.AppendValue(3.5); + TJsonValue obj; + obj.InsertValue("key", TJsonValue("value")); + + val.AppendValue(obj); + val.AppendValue(TJsonValue(JSON_NULL)); + + NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML); + w.WriteJsonValue(&val); + + const char exp[] = "[1,\"2\",3.5,{\"key\":\"value\"},null]"; + UNIT_ASSERT_STRINGS_EQUAL(exp, w.Str()); + } + Y_UNIT_TEST(WriteJsonValueSorted) { + using namespace NJson; + TJsonValue val; + val.InsertValue("1", TJsonValue(1)); + val.InsertValue("2", TJsonValue(2)); + + TJsonValue obj; + obj.InsertValue("zero", TJsonValue(0)); + obj.InsertValue("succ", TJsonValue(1)); + val.InsertValue("0", obj); + + NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML); + w.WriteJsonValue(&val, true); + + const char exp[] = "{\"0\":{\"succ\":1,\"zero\":0},\"1\":1,\"2\":2}"; + UNIT_ASSERT_STRINGS_EQUAL(exp, w.Str()); + } + Y_UNIT_TEST(Unescaped) { + NJsonWriter::TBuf buf(NJsonWriter::HEM_UNSAFE); + buf.WriteString("</security>'"); + UNIT_ASSERT_STRINGS_EQUAL("\"</security>'\"", buf.Str()); + } + Y_UNIT_TEST(LittleBobbyJsonp) { + NJsonWriter::TBuf buf; + buf.WriteString("hello\xe2\x80\xa8\xe2\x80\xa9stranger"); + UNIT_ASSERT_STRINGS_EQUAL("\"hello\\u2028\\u2029stranger\"", buf.Str()); + } + Y_UNIT_TEST(LittleBobbyInvalid) { + NJsonWriter::TBuf buf; + TStringBuf incomplete("\xe2\x80\xa8", 2); + buf.WriteString(incomplete); + // garbage in - garbage out + UNIT_ASSERT_STRINGS_EQUAL("\"\xe2\x80\"", buf.Str()); + } + Y_UNIT_TEST(OverlyZealous) { + NJsonWriter::TBuf buf; + buf.WriteString("—"); + UNIT_ASSERT_STRINGS_EQUAL("\"—\"", buf.Str()); + } + Y_UNIT_TEST(RelaxedEscaping) { + NJsonWriter::TBuf buf(NJsonWriter::HEM_RELAXED); + buf.WriteString("</>"); + UNIT_ASSERT_STRINGS_EQUAL("\"\\u003C/\\u003E\"", buf.Str()); + } + + Y_UNIT_TEST(FloatFormatting) { + NJsonWriter::TBuf buf(NJsonWriter::HEM_DONT_ESCAPE_HTML); + buf.BeginList() + .WriteFloat(0.12345678987654321f) + .WriteDouble(0.12345678987654321) + .WriteFloat(0.315501, PREC_NDIGITS, 3) + .WriteFloat(244.13854, PREC_NDIGITS, 4) + .WriteFloat(10385.8324, PREC_POINT_DIGITS, 2) + .BeginObject() + .WriteKey("1") + .WriteDouble(1111.71, PREC_POINT_DIGITS, 0) + .WriteKey("2") + .WriteDouble(1111.71, PREC_NDIGITS, 1) + .EndObject() + .EndList(); + const char exp[] = "[0.123457,0.1234567899,0.316,244.1,10385.83,{\"1\":1112,\"2\":1e+03}]"; + UNIT_ASSERT_STRINGS_EQUAL(exp, buf.Str()); + } + + Y_UNIT_TEST(NanFormatting) { + { + NJsonWriter::TBuf buf; + buf.BeginObject(); + buf.WriteKey("nanvalue"); + UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits<double>::quiet_NaN()), yexception); + } + + { + NJsonWriter::TBuf buf; + buf.BeginObject(); + buf.WriteKey("infvalue"); + UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits<double>::infinity()), yexception); + } + + { + NJsonWriter::TBuf buf; + buf.BeginList(); + UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits<double>::quiet_NaN()), yexception); + } + + { + NJsonWriter::TBuf buf; + buf.BeginList(); + UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits<double>::infinity()), yexception); + } + + { + NJsonWriter::TBuf buf; + buf.SetWriteNanAsString(); + + buf.BeginObject() + .WriteKey("nanvalue") + .WriteFloat(std::numeric_limits<double>::quiet_NaN()) + .WriteKey("infvalue") + .WriteFloat(std::numeric_limits<double>::infinity()) + .WriteKey("minus_infvalue") + .WriteFloat(-std::numeric_limits<float>::infinity()) + .WriteKey("l") + .BeginList() + .WriteFloat(std::numeric_limits<float>::quiet_NaN()) + .EndList() + .EndObject(); + + UNIT_ASSERT_STRINGS_EQUAL(buf.Str(), R"raw_json({"nanvalue":"nan","infvalue":"inf","minus_infvalue":"-inf","l":["nan"]})raw_json"); + } + + { + NJsonWriter::TBuf buf; + buf.BeginObject() + .WriteKey("<>&") + .WriteString("Ololo") + .UnsafeWriteKey("<>&") + .WriteString("Ololo2") + .EndObject(); + + UNIT_ASSERT_STRINGS_EQUAL(buf.Str(), R"({"\u003C\u003E&":"Ololo","<>&":"Ololo2"})"); + } + } + + Y_UNIT_TEST(WriteUninitializedBoolDoesntCrashProgram) { + // makes sense only in release build w/ address sanitizer + // + // passing uninitialized boolean into WriteBool can make cleverly optimized code which is emitted by compiler crash program + // https://stackoverflow.com/questions/54120862/does-the-c-standard-allow-for-an-uninitialized-bool-to-crash-a-program + + // looks like compiler can detect UB at compile time in simple cases, but not in this one + class TSensorConf { + public: + class TAggrRuleItem { + public: + TVector<TString> Cond; + TVector<TString> Target; + }; + + TString ToString() const { + NJson::TJsonValue jsonValue; + NJsonWriter::TBuf jsonOutput; + jsonOutput.BeginObject() + .WriteKey("rawDataMemOnly").WriteBool(RawDataMemOnly) + .WriteKey("aggrRules").BeginList(); + + jsonOutput.EndList() + .EndObject(); + + return jsonOutput.Str(); + } + + TVector<TAggrRuleItem> AggrRules; + bool RawDataMemOnly; + }; + + TSensorConf s; + NSan::Unpoison(&s.RawDataMemOnly, sizeof(s.RawDataMemOnly)); + auto p = s.ToString(); + // doesn't really matter + UNIT_ASSERT(!p.empty()); + } +} |