json_ut.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. #include <library/cpp/testing/unittest/registar.h>
  2. #include <util/system/sanitizers.h>
  3. #include "json.h"
  4. #include <library/cpp/json/json_value.h>
  5. #include <limits>
  6. Y_UNIT_TEST_SUITE(JsonWriter) {
  7. Y_UNIT_TEST(Struct) {
  8. NJsonWriter::TBuf w;
  9. w.BeginList();
  10. w.BeginObject()
  11. .WriteKey("key")
  12. .WriteString("value")
  13. .UnsafeWritePair("\"xk\":13")
  14. .WriteKey("key2")
  15. .BeginList()
  16. .BeginObject()
  17. .EndObject()
  18. .BeginObject()
  19. .EndObject()
  20. .EndList()
  21. .EndObject();
  22. w.WriteInt(43);
  23. w.UnsafeWriteValue("\"x\"");
  24. w.WriteString("...");
  25. w.EndList();
  26. const char* exp = "[{\"key\":\"value\",\"xk\":13,\"key2\":[{},{}]},43,\"x\",\"...\"]";
  27. UNIT_ASSERT_EQUAL(w.Str(), exp);
  28. }
  29. Y_UNIT_TEST(EscapedString) {
  30. NJsonWriter::TBuf w(NJsonWriter::HEM_ESCAPE_HTML);
  31. w.WriteString(" \n \r \t \007 \b \f ' <tag> &ent; \"txt\" ");
  32. TString ws = w.Str();
  33. const char* exp = "\" \\n \\r \\t \\u0007 \\b \\f &#39; &lt;tag&gt; &amp;ent; &quot;txt&quot; \"";
  34. UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp);
  35. }
  36. Y_UNIT_TEST(UnescapedString) {
  37. NJsonWriter::TBuf w;
  38. w.WriteString(" \n \r \t \b \f '; -- <tag> &ent; \"txt\"", NJsonWriter::HEM_DONT_ESCAPE_HTML);
  39. TString ws = w.Str();
  40. const char* exp = "\" \\n \\r \\t \\b \\f \\u0027; -- \\u003Ctag\\u003E &ent; \\\"txt\\\"\"";
  41. UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp);
  42. }
  43. Y_UNIT_TEST(UnescapedChaining) {
  44. NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML);
  45. w.UnsafeWriteRawBytes("(", 1);
  46. w.BeginList().WriteString("<>&'\\").BeginList();
  47. w.EndList().EndList();
  48. TString ws = w.Str();
  49. const char* exp = "([\"\\u003C\\u003E&\\u0027\\\\\",[]]";
  50. UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp);
  51. }
  52. Y_UNIT_TEST(Utf8) {
  53. TString ws = NJsonWriter::TBuf().WriteString("яЯ σΣ ש א").Str();
  54. const char* exp = "\"яЯ σΣ ש א\"";
  55. UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp);
  56. }
  57. Y_UNIT_TEST(WrongObject) {
  58. NJsonWriter::TBuf w;
  59. w.BeginObject();
  60. UNIT_ASSERT_EXCEPTION(w.WriteString("hehe"), NJsonWriter::TError);
  61. }
  62. Y_UNIT_TEST(WrongList) {
  63. NJsonWriter::TBuf w;
  64. w.BeginList();
  65. UNIT_ASSERT_EXCEPTION(w.WriteKey("hehe"), NJsonWriter::TError);
  66. }
  67. Y_UNIT_TEST(Incomplete) {
  68. NJsonWriter::TBuf w;
  69. w.BeginList();
  70. UNIT_ASSERT_EXCEPTION(w.Str(), NJsonWriter::TError);
  71. }
  72. Y_UNIT_TEST(BareKey) {
  73. NJsonWriter::TBuf w;
  74. w.BeginObject()
  75. .CompatWriteKeyWithoutQuotes("p")
  76. .WriteInt(1)
  77. .CompatWriteKeyWithoutQuotes("n")
  78. .WriteInt(0)
  79. .EndObject();
  80. TString ws = w.Str();
  81. const char* exp = "{p:1,n:0}";
  82. UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp);
  83. }
  84. Y_UNIT_TEST(UnescapedStringInObject) {
  85. NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML);
  86. w.BeginObject().WriteKey("key").WriteString("</&>'").EndObject();
  87. TString ws = w.Str();
  88. const char* exp = "{\"key\":\"\\u003C\\/&\\u003E\\u0027\"}";
  89. UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp);
  90. }
  91. Y_UNIT_TEST(ForeignStreamStr) {
  92. NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML, &Cerr);
  93. UNIT_ASSERT_EXCEPTION(w.Str(), NJsonWriter::TError);
  94. }
  95. Y_UNIT_TEST(ForeignStreamValue) {
  96. TStringStream ss;
  97. NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML, &ss);
  98. w.WriteInt(1543);
  99. UNIT_ASSERT_STRINGS_EQUAL(ss.Str(), "1543");
  100. }
  101. Y_UNIT_TEST(Indentation) {
  102. NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML);
  103. w.SetIndentSpaces(2);
  104. w.BeginList()
  105. .WriteInt(1)
  106. .WriteString("hello")
  107. .BeginObject()
  108. .WriteKey("abc")
  109. .WriteInt(3)
  110. .WriteKey("def")
  111. .WriteInt(4)
  112. .EndObject()
  113. .EndList();
  114. const char* exp = "[\n"
  115. " 1,\n"
  116. " \"hello\",\n"
  117. " {\n"
  118. " \"abc\":3,\n"
  119. " \"def\":4\n"
  120. " }\n"
  121. "]";
  122. UNIT_ASSERT_STRINGS_EQUAL(exp, w.Str());
  123. }
  124. Y_UNIT_TEST(WriteJsonValue) {
  125. using namespace NJson;
  126. TJsonValue val;
  127. val.AppendValue(1);
  128. val.AppendValue("2");
  129. val.AppendValue(3.5);
  130. TJsonValue obj;
  131. obj.InsertValue("key", TJsonValue("value"));
  132. val.AppendValue(obj);
  133. val.AppendValue(TJsonValue(JSON_NULL));
  134. NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML);
  135. w.WriteJsonValue(&val);
  136. const char exp[] = "[1,\"2\",3.5,{\"key\":\"value\"},null]";
  137. UNIT_ASSERT_STRINGS_EQUAL(exp, w.Str());
  138. }
  139. Y_UNIT_TEST(WriteJsonValueSorted) {
  140. using namespace NJson;
  141. TJsonValue val;
  142. val.InsertValue("1", TJsonValue(1));
  143. val.InsertValue("2", TJsonValue(2));
  144. TJsonValue obj;
  145. obj.InsertValue("zero", TJsonValue(0));
  146. obj.InsertValue("succ", TJsonValue(1));
  147. val.InsertValue("0", obj);
  148. NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML);
  149. w.WriteJsonValue(&val, true);
  150. const char exp[] = "{\"0\":{\"succ\":1,\"zero\":0},\"1\":1,\"2\":2}";
  151. UNIT_ASSERT_STRINGS_EQUAL(exp, w.Str());
  152. }
  153. Y_UNIT_TEST(Unescaped) {
  154. NJsonWriter::TBuf buf(NJsonWriter::HEM_UNSAFE);
  155. buf.WriteString("</security>'");
  156. UNIT_ASSERT_STRINGS_EQUAL("\"</security>'\"", buf.Str());
  157. }
  158. Y_UNIT_TEST(LittleBobbyJsonp) {
  159. NJsonWriter::TBuf buf;
  160. buf.WriteString("hello\xe2\x80\xa8\xe2\x80\xa9stranger");
  161. UNIT_ASSERT_STRINGS_EQUAL("\"hello\\u2028\\u2029stranger\"", buf.Str());
  162. }
  163. Y_UNIT_TEST(LittleBobbyInvalid) {
  164. NJsonWriter::TBuf buf;
  165. TStringBuf incomplete("\xe2\x80\xa8", 2);
  166. buf.WriteString(incomplete);
  167. // garbage in - garbage out
  168. UNIT_ASSERT_STRINGS_EQUAL("\"\xe2\x80\"", buf.Str());
  169. }
  170. Y_UNIT_TEST(OverlyZealous) {
  171. NJsonWriter::TBuf buf;
  172. buf.WriteString("—");
  173. UNIT_ASSERT_STRINGS_EQUAL("\"—\"", buf.Str());
  174. }
  175. Y_UNIT_TEST(RelaxedEscaping) {
  176. NJsonWriter::TBuf buf(NJsonWriter::HEM_RELAXED);
  177. buf.WriteString("</>");
  178. UNIT_ASSERT_STRINGS_EQUAL("\"\\u003C/\\u003E\"", buf.Str());
  179. }
  180. Y_UNIT_TEST(FloatFormatting) {
  181. NJsonWriter::TBuf buf(NJsonWriter::HEM_DONT_ESCAPE_HTML);
  182. buf.BeginList()
  183. .WriteFloat(0.12345678987654321f)
  184. .WriteDouble(0.12345678987654321)
  185. .WriteFloat(0.315501, PREC_NDIGITS, 3)
  186. .WriteFloat(244.13854, PREC_NDIGITS, 4)
  187. .WriteFloat(10385.8324, PREC_POINT_DIGITS, 2)
  188. .BeginObject()
  189. .WriteKey("1")
  190. .WriteDouble(1111.71, PREC_POINT_DIGITS, 0)
  191. .WriteKey("2")
  192. .WriteDouble(1111.71, PREC_NDIGITS, 1)
  193. .EndObject()
  194. .EndList();
  195. const char exp[] = "[0.123457,0.1234567899,0.316,244.1,10385.83,{\"1\":1112,\"2\":1e+03}]";
  196. UNIT_ASSERT_STRINGS_EQUAL(exp, buf.Str());
  197. }
  198. Y_UNIT_TEST(NanFormatting) {
  199. {
  200. NJsonWriter::TBuf buf;
  201. buf.BeginObject();
  202. buf.WriteKey("nanvalue");
  203. UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits<double>::quiet_NaN()), yexception);
  204. }
  205. {
  206. NJsonWriter::TBuf buf;
  207. buf.BeginObject();
  208. buf.WriteKey("infvalue");
  209. UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits<double>::infinity()), yexception);
  210. }
  211. {
  212. NJsonWriter::TBuf buf;
  213. buf.BeginList();
  214. UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits<double>::quiet_NaN()), yexception);
  215. }
  216. {
  217. NJsonWriter::TBuf buf;
  218. buf.BeginList();
  219. UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits<double>::infinity()), yexception);
  220. }
  221. {
  222. NJsonWriter::TBuf buf;
  223. buf.SetWriteNanAsString();
  224. buf.BeginObject()
  225. .WriteKey("nanvalue")
  226. .WriteFloat(std::numeric_limits<double>::quiet_NaN())
  227. .WriteKey("infvalue")
  228. .WriteFloat(std::numeric_limits<double>::infinity())
  229. .WriteKey("minus_infvalue")
  230. .WriteFloat(-std::numeric_limits<float>::infinity())
  231. .WriteKey("l")
  232. .BeginList()
  233. .WriteFloat(std::numeric_limits<float>::quiet_NaN())
  234. .EndList()
  235. .EndObject();
  236. UNIT_ASSERT_STRINGS_EQUAL(buf.Str(), R"raw_json({"nanvalue":"nan","infvalue":"inf","minus_infvalue":"-inf","l":["nan"]})raw_json");
  237. }
  238. {
  239. NJsonWriter::TBuf buf;
  240. buf.BeginObject()
  241. .WriteKey("<>&")
  242. .WriteString("Ololo")
  243. .UnsafeWriteKey("<>&")
  244. .WriteString("Ololo2")
  245. .EndObject();
  246. UNIT_ASSERT_STRINGS_EQUAL(buf.Str(), R"({"\u003C\u003E&":"Ololo","<>&":"Ololo2"})");
  247. }
  248. }
  249. }