#include #include #include "json.h" #include #include 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 ' &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 '; -- &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("'"); UNIT_ASSERT_STRINGS_EQUAL("\"'\"", 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::quiet_NaN()), yexception); } { NJsonWriter::TBuf buf; buf.BeginObject(); buf.WriteKey("infvalue"); UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits::infinity()), yexception); } { NJsonWriter::TBuf buf; buf.BeginList(); UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits::quiet_NaN()), yexception); } { NJsonWriter::TBuf buf; buf.BeginList(); UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits::infinity()), yexception); } { NJsonWriter::TBuf buf; buf.SetWriteNanAsString(); buf.BeginObject() .WriteKey("nanvalue") .WriteFloat(std::numeric_limits::quiet_NaN()) .WriteKey("infvalue") .WriteFloat(std::numeric_limits::infinity()) .WriteKey("minus_infvalue") .WriteFloat(-std::numeric_limits::infinity()) .WriteKey("l") .BeginList() .WriteFloat(std::numeric_limits::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"})"); } } }