json2proto_ut.cpp 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147
  1. #include "json.h"
  2. #include "proto.h"
  3. #include "proto2json.h"
  4. #include <library/cpp/protobuf/json/ut/test.pb.h>
  5. #include <library/cpp/json/json_value.h>
  6. #include <library/cpp/json/json_reader.h>
  7. #include <library/cpp/json/json_writer.h>
  8. #include <library/cpp/protobuf/json/json2proto.h>
  9. #include <library/cpp/testing/unittest/registar.h>
  10. #include <util/generic/hash_set.h>
  11. #include <util/generic/string.h>
  12. #include <util/generic/ylimits.h>
  13. #include <util/stream/str.h>
  14. #include <util/string/cast.h>
  15. #include <util/system/defaults.h>
  16. #include <util/system/yassert.h>
  17. using namespace NProtobufJson;
  18. using namespace NProtobufJsonTest;
  19. namespace google {
  20. namespace protobuf {
  21. namespace internal {
  22. void MapTestForceDeterministic() {
  23. google::protobuf::io::CodedOutputStream::SetDefaultSerializationDeterministic();
  24. }
  25. }
  26. } // namespace protobuf
  27. }
  28. namespace {
  29. class TInit {
  30. public:
  31. TInit() {
  32. ::google::protobuf::internal::MapTestForceDeterministic();
  33. }
  34. } Init;
  35. template <typename T>
  36. TString ConvertToString(T value) {
  37. return ToString(value);
  38. }
  39. // default ToString<double>() implementation loses precision
  40. TString ConvertToString(double value) {
  41. return FloatToString(value);
  42. }
  43. TString JsonValueToString(const NJson::TJsonValue& json) {
  44. NJsonWriter::TBuf buf(NJsonWriter::HEM_UNSAFE);
  45. return buf.WriteJsonValue(&json).Str();
  46. }
  47. void TestComplexMapAsObject(std::function<void(TComplexMapType&)>&& init, const TString& json, const TJson2ProtoConfig& config = TJson2ProtoConfig().SetMapAsObject(true)) {
  48. TComplexMapType modelProto;
  49. init(modelProto);
  50. TString modelStr(json);
  51. TComplexMapType proto;
  52. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TComplexMapType>(modelStr, config));
  53. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  54. }
  55. }
  56. Y_UNIT_TEST_SUITE(TJson2ProtoTest) {
  57. Y_UNIT_TEST(TestFlatOptional){
  58. {const NJson::TJsonValue& json = CreateFlatJson();
  59. TFlatOptional proto;
  60. Json2Proto(json, proto);
  61. TFlatOptional modelProto;
  62. FillFlatProto(&modelProto);
  63. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  64. }
  65. // Try to skip each field
  66. #define DEFINE_FIELD(name, value) \
  67. { \
  68. THashSet<TString> skippedField; \
  69. skippedField.insert(#name); \
  70. const NJson::TJsonValue& json = CreateFlatJson(skippedField); \
  71. TFlatOptional proto; \
  72. Json2Proto(json, proto); \
  73. TFlatOptional modelProto; \
  74. FillFlatProto(&modelProto, skippedField); \
  75. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto); \
  76. }
  77. #include <library/cpp/protobuf/json/ut/fields.incl>
  78. #undef DEFINE_FIELD
  79. } // TestFlatOptional
  80. Y_UNIT_TEST(TestFlatRequired){
  81. {const NJson::TJsonValue& json = CreateFlatJson();
  82. TFlatRequired proto;
  83. Json2Proto(json, proto);
  84. TFlatRequired modelProto;
  85. FillFlatProto(&modelProto);
  86. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  87. }
  88. // Try to skip each field
  89. #define DEFINE_FIELD(name, value) \
  90. { \
  91. THashSet<TString> skippedField; \
  92. skippedField.insert(#name); \
  93. const NJson::TJsonValue& json = CreateFlatJson(skippedField); \
  94. TFlatRequired proto; \
  95. UNIT_ASSERT_EXCEPTION(Json2Proto(json, proto), yexception); \
  96. }
  97. #include <library/cpp/protobuf/json/ut/fields.incl>
  98. #undef DEFINE_FIELD
  99. } // TestFlatRequired
  100. Y_UNIT_TEST(TestNameGenerator) {
  101. TJson2ProtoConfig cfg;
  102. cfg.SetNameGenerator([](const NProtoBuf::FieldDescriptor&) { return "42"; });
  103. TNameGeneratorType proto;
  104. Json2Proto(TStringBuf(R"({"42":42})"), proto, cfg);
  105. TNameGeneratorType expected;
  106. expected.SetField(42);
  107. UNIT_ASSERT_PROTOS_EQUAL(expected, proto);
  108. }
  109. Y_UNIT_TEST(TestFlatNoCheckRequired) {
  110. {
  111. const NJson::TJsonValue& json = CreateFlatJson();
  112. TFlatRequired proto;
  113. Json2Proto(json, proto);
  114. TFlatRequired modelProto;
  115. FillFlatProto(&modelProto);
  116. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  117. }
  118. TJson2ProtoConfig cfg;
  119. cfg.CheckRequiredFields = false;
  120. // Try to skip each field
  121. #define DEFINE_FIELD(name, value) \
  122. { \
  123. THashSet<TString> skippedField; \
  124. skippedField.insert(#name); \
  125. const NJson::TJsonValue& json = CreateFlatJson(skippedField); \
  126. TFlatRequired proto; \
  127. UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto, cfg)); \
  128. }
  129. #include <library/cpp/protobuf/json/ut/fields.incl>
  130. #undef DEFINE_FIELD
  131. } // TestFlatNoCheckRequired
  132. Y_UNIT_TEST(TestFlatRepeated){
  133. {const NJson::TJsonValue& json = CreateRepeatedFlatJson();
  134. TFlatRepeated proto;
  135. Json2Proto(json, proto);
  136. TFlatRepeated modelProto;
  137. FillRepeatedProto(&modelProto);
  138. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  139. }
  140. // Try to skip each field
  141. #define DEFINE_REPEATED_FIELD(name, ...) \
  142. { \
  143. THashSet<TString> skippedField; \
  144. skippedField.insert(#name); \
  145. const NJson::TJsonValue& json = CreateRepeatedFlatJson(skippedField); \
  146. TFlatRepeated proto; \
  147. Json2Proto(json, proto); \
  148. TFlatRepeated modelProto; \
  149. FillRepeatedProto(&modelProto, skippedField); \
  150. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto); \
  151. }
  152. #include <library/cpp/protobuf/json/ut/repeated_fields.incl>
  153. #undef DEFINE_REPEATED_FIELD
  154. } // TestFlatRepeated
  155. Y_UNIT_TEST(TestCompositeOptional){
  156. {const NJson::TJsonValue& json = CreateCompositeJson();
  157. TCompositeOptional proto;
  158. Json2Proto(json, proto);
  159. TCompositeOptional modelProto;
  160. FillCompositeProto(&modelProto);
  161. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  162. }
  163. // Try to skip each field
  164. #define DEFINE_FIELD(name, value) \
  165. { \
  166. THashSet<TString> skippedField; \
  167. skippedField.insert(#name); \
  168. const NJson::TJsonValue& json = CreateCompositeJson(skippedField); \
  169. TCompositeOptional proto; \
  170. Json2Proto(json, proto); \
  171. TCompositeOptional modelProto; \
  172. FillCompositeProto(&modelProto, skippedField); \
  173. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto); \
  174. }
  175. #include <library/cpp/protobuf/json/ut/fields.incl>
  176. #undef DEFINE_FIELD
  177. } // TestCompositeOptional
  178. Y_UNIT_TEST(TestCompositeOptionalStringBuf){
  179. {NJson::TJsonValue json = CreateCompositeJson();
  180. json["Part"]["Double"] = 42.5;
  181. TCompositeOptional proto;
  182. Json2Proto(JsonValueToString(json), proto);
  183. TCompositeOptional modelProto;
  184. FillCompositeProto(&modelProto);
  185. modelProto.MutablePart()->SetDouble(42.5);
  186. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  187. }
  188. // Try to skip each field
  189. #define DEFINE_FIELD(name, value) \
  190. { \
  191. THashSet<TString> skippedField; \
  192. skippedField.insert(#name); \
  193. NJson::TJsonValue json = CreateCompositeJson(skippedField); \
  194. if (json["Part"].Has("Double")) { \
  195. json["Part"]["Double"] = 42.5; \
  196. } \
  197. TCompositeOptional proto; \
  198. Json2Proto(JsonValueToString(json), proto); \
  199. TCompositeOptional modelProto; \
  200. FillCompositeProto(&modelProto, skippedField); \
  201. if (modelProto.GetPart().HasDouble()) { \
  202. modelProto.MutablePart()->SetDouble(42.5); \
  203. } \
  204. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto); \
  205. }
  206. #include <library/cpp/protobuf/json/ut/fields.incl>
  207. #undef DEFINE_FIELD
  208. } // TestCompositeOptionalStringBuf
  209. Y_UNIT_TEST(TestCompositeRequired) {
  210. {
  211. const NJson::TJsonValue& json = CreateCompositeJson();
  212. TCompositeRequired proto;
  213. Json2Proto(json, proto);
  214. TCompositeRequired modelProto;
  215. FillCompositeProto(&modelProto);
  216. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  217. }
  218. {
  219. NJson::TJsonValue json;
  220. TCompositeRequired proto;
  221. UNIT_ASSERT_EXCEPTION(Json2Proto(json, proto), yexception);
  222. }
  223. } // TestCompositeRequired
  224. Y_UNIT_TEST(TestCompositeRepeated) {
  225. {
  226. NJson::TJsonValue json;
  227. NJson::TJsonValue array;
  228. array.AppendValue(CreateFlatJson());
  229. json.InsertValue("Part", array);
  230. TCompositeRepeated proto;
  231. Json2Proto(json, proto);
  232. TFlatOptional partModelProto;
  233. FillFlatProto(&partModelProto);
  234. TCompositeRepeated modelProto;
  235. modelProto.AddPart()->CopyFrom(partModelProto);
  236. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  237. }
  238. {
  239. // Array of messages with each field skipped
  240. TCompositeRepeated modelProto;
  241. NJson::TJsonValue array;
  242. #define DEFINE_REPEATED_FIELD(name, ...) \
  243. { \
  244. THashSet<TString> skippedField; \
  245. skippedField.insert(#name); \
  246. TFlatOptional partModelProto; \
  247. FillFlatProto(&partModelProto, skippedField); \
  248. modelProto.AddPart()->CopyFrom(partModelProto); \
  249. array.AppendValue(CreateFlatJson(skippedField)); \
  250. }
  251. #include <library/cpp/protobuf/json/ut/repeated_fields.incl>
  252. #undef DEFINE_REPEATED_FIELD
  253. NJson::TJsonValue json;
  254. json.InsertValue("Part", array);
  255. TCompositeRepeated proto;
  256. Json2Proto(json, proto);
  257. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  258. }
  259. } // TestCompositeRepeated
  260. Y_UNIT_TEST(TestInvalidEnum) {
  261. {
  262. NJson::TJsonValue json;
  263. json.InsertValue("Enum", "E_100");
  264. TFlatOptional proto;
  265. UNIT_ASSERT_EXCEPTION(Json2Proto(json, proto), yexception);
  266. }
  267. {
  268. NJson::TJsonValue json;
  269. json.InsertValue("Enum", 100);
  270. TFlatOptional proto;
  271. UNIT_ASSERT_EXCEPTION(Json2Proto(json, proto), yexception);
  272. }
  273. }
  274. Y_UNIT_TEST(TestFieldNameMode) {
  275. // Original case 1
  276. {
  277. TString modelStr(R"_({"String":"value"})_");
  278. TFlatOptional proto;
  279. TJson2ProtoConfig config;
  280. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
  281. UNIT_ASSERT(proto.GetString() == "value");
  282. }
  283. // Original case 2
  284. {
  285. TString modelStr(R"_({"String":"value"})_");
  286. TFlatOptional proto;
  287. TJson2ProtoConfig config;
  288. config.FieldNameMode = TJson2ProtoConfig::FieldNameOriginalCase;
  289. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
  290. UNIT_ASSERT(proto.GetString() == "value");
  291. }
  292. // Lowercase
  293. {
  294. TString modelStr(R"_({"string":"value"})_");
  295. TFlatOptional proto;
  296. TJson2ProtoConfig config;
  297. config.FieldNameMode = TJson2ProtoConfig::FieldNameLowerCase;
  298. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
  299. UNIT_ASSERT(proto.GetString() == "value");
  300. }
  301. // Uppercase
  302. {
  303. TString modelStr(R"_({"STRING":"value"})_");
  304. TFlatOptional proto;
  305. TJson2ProtoConfig config;
  306. config.FieldNameMode = TJson2ProtoConfig::FieldNameUpperCase;
  307. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
  308. UNIT_ASSERT(proto.GetString() == "value");
  309. }
  310. // Camelcase
  311. {
  312. TString modelStr(R"_({"string":"value"})_");
  313. TFlatOptional proto;
  314. TJson2ProtoConfig config;
  315. config.FieldNameMode = TJson2ProtoConfig::FieldNameCamelCase;
  316. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
  317. UNIT_ASSERT(proto.GetString() == "value");
  318. }
  319. {
  320. TString modelStr(R"_({"oneString":"value"})_");
  321. TFlatOptional proto;
  322. TJson2ProtoConfig config;
  323. config.FieldNameMode = TJson2ProtoConfig::FieldNameCamelCase;
  324. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
  325. UNIT_ASSERT(proto.GetOneString() == "value");
  326. }
  327. {
  328. TString modelStr(R"_({"oneTwoString":"value"})_");
  329. TFlatOptional proto;
  330. TJson2ProtoConfig config;
  331. config.FieldNameMode = TJson2ProtoConfig::FieldNameCamelCase;
  332. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
  333. UNIT_ASSERT(proto.GetOneTwoString() == "value");
  334. }
  335. // snake_case
  336. {
  337. TString modelStr(R"_({"string":"value"})_");
  338. TFlatOptional proto;
  339. TJson2ProtoConfig config;
  340. config.FieldNameMode = TJson2ProtoConfig::FieldNameSnakeCase;
  341. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
  342. UNIT_ASSERT(proto.GetString() == "value");
  343. }
  344. {
  345. TString modelStr(R"_({"one_string":"value"})_");
  346. TFlatOptional proto;
  347. TJson2ProtoConfig config;
  348. config.FieldNameMode = TJson2ProtoConfig::FieldNameSnakeCase;
  349. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
  350. UNIT_ASSERT(proto.GetOneString() == "value");
  351. }
  352. {
  353. TString modelStr(R"_({"one_two_string":"value"})_");
  354. TFlatOptional proto;
  355. TJson2ProtoConfig config;
  356. config.FieldNameMode = TJson2ProtoConfig::FieldNameSnakeCase;
  357. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
  358. UNIT_ASSERT(proto.GetOneTwoString() == "value");
  359. }
  360. // Original case, repeated
  361. {
  362. TString modelStr(R"_({"I32":[1,2]})_");
  363. TFlatRepeated proto;
  364. TJson2ProtoConfig config;
  365. config.FieldNameMode = TJson2ProtoConfig::FieldNameOriginalCase;
  366. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatRepeated>(modelStr, config));
  367. UNIT_ASSERT(proto.I32Size() == 2);
  368. UNIT_ASSERT(proto.GetI32(0) == 1);
  369. UNIT_ASSERT(proto.GetI32(1) == 2);
  370. }
  371. // Lower case, repeated
  372. {
  373. TString modelStr(R"_({"i32":[1,2]})_");
  374. TFlatRepeated proto;
  375. TJson2ProtoConfig config;
  376. config.FieldNameMode = TJson2ProtoConfig::FieldNameLowerCase;
  377. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatRepeated>(modelStr, config));
  378. UNIT_ASSERT(proto.I32Size() == 2);
  379. UNIT_ASSERT(proto.GetI32(0) == 1);
  380. UNIT_ASSERT(proto.GetI32(1) == 2);
  381. }
  382. // UseJsonName
  383. {
  384. // FIXME(CONTRIB-139): since protobuf 3.1, Def_upper json name is
  385. // "DefUpper", but until kernel/ugc/schema and yweb/yasap/pdb are
  386. // updated, library/cpp/protobuf/json preserves compatibility with
  387. // protobuf 3.0 by lowercasing default names, making it "defUpper".
  388. TString modelStr(R"_({"My-Upper":1,"my-lower":2,"defUpper":3,"defLower":4})_");
  389. TWithJsonName proto;
  390. TJson2ProtoConfig config;
  391. config.SetUseJsonName(true);
  392. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TWithJsonName>(modelStr, config));
  393. UNIT_ASSERT_EQUAL(proto.Getmy_upper(), 1);
  394. UNIT_ASSERT_EQUAL(proto.GetMy_lower(), 2);
  395. UNIT_ASSERT_EQUAL(proto.GetDef_upper(), 3);
  396. UNIT_ASSERT_EQUAL(proto.Getdef_lower(), 4);
  397. }
  398. // FieldNameMode with UseJsonName
  399. {
  400. TJson2ProtoConfig config;
  401. config.SetFieldNameMode(TJson2ProtoConfig::FieldNameLowerCase);
  402. UNIT_ASSERT_EXCEPTION_CONTAINS(
  403. config.SetUseJsonName(true), yexception, "mutually exclusive");
  404. }
  405. {
  406. TJson2ProtoConfig config;
  407. config.SetUseJsonName(true);
  408. UNIT_ASSERT_EXCEPTION_CONTAINS(
  409. config.SetFieldNameMode(TJson2ProtoConfig::FieldNameLowerCase), yexception, "mutually exclusive");
  410. }
  411. } // TestFieldNameMode
  412. class TStringTransform: public IStringTransform {
  413. public:
  414. int GetType() const override {
  415. return 0;
  416. }
  417. void Transform(TString& str) const override {
  418. str = "transformed_any";
  419. }
  420. };
  421. class TBytesTransform: public IStringTransform {
  422. public:
  423. int GetType() const override {
  424. return 0;
  425. }
  426. void Transform(TString&) const override {
  427. }
  428. void TransformBytes(TString& str) const override {
  429. str = "transformed_bytes";
  430. }
  431. };
  432. Y_UNIT_TEST(TestInvalidJson) {
  433. NJson::TJsonValue val{"bad value"};
  434. TFlatOptional proto;
  435. UNIT_ASSERT_EXCEPTION(Json2Proto(val, proto), yexception);
  436. }
  437. Y_UNIT_TEST(TestInvalidRepeatedFieldWithMapAsObject) {
  438. TCompositeRepeated proto;
  439. TJson2ProtoConfig config;
  440. config.MapAsObject = true;
  441. UNIT_ASSERT_EXCEPTION(Json2Proto(TStringBuf(R"({"Part":{"Boo":{}}})"), proto, config), yexception);
  442. }
  443. Y_UNIT_TEST(TestStringTransforms) {
  444. // Check that strings and bytes are transformed
  445. {
  446. TString modelStr(R"_({"String":"value_str", "Bytes": "value_bytes"})_");
  447. TFlatOptional proto;
  448. TJson2ProtoConfig config;
  449. config.AddStringTransform(new TStringTransform);
  450. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
  451. UNIT_ASSERT(proto.GetString() == "transformed_any");
  452. UNIT_ASSERT(proto.GetBytes() == "transformed_any");
  453. }
  454. // Check that bytes are transformed, strings are left intact
  455. {
  456. TString modelStr(R"_({"String":"value_str", "Bytes": "value_bytes"})_");
  457. TFlatOptional proto;
  458. TJson2ProtoConfig config;
  459. config.AddStringTransform(new TBytesTransform);
  460. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
  461. UNIT_ASSERT(proto.GetString() == "value_str");
  462. UNIT_ASSERT(proto.GetBytes() == "transformed_bytes");
  463. }
  464. // Check that repeated bytes are transformed, repeated strings are left intact
  465. {
  466. TString modelStr(R"_({"String":["value_str", "str2"], "Bytes": ["value_bytes", "bytes2"]})_");
  467. TFlatRepeated proto;
  468. TJson2ProtoConfig config;
  469. config.AddStringTransform(new TBytesTransform);
  470. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatRepeated>(modelStr, config));
  471. UNIT_ASSERT(proto.StringSize() == 2);
  472. UNIT_ASSERT(proto.GetString(0) == "value_str");
  473. UNIT_ASSERT(proto.GetString(1) == "str2");
  474. UNIT_ASSERT(proto.BytesSize() == 2);
  475. UNIT_ASSERT(proto.GetBytes(0) == "transformed_bytes");
  476. UNIT_ASSERT(proto.GetBytes(1) == "transformed_bytes");
  477. }
  478. // Check that bytes are transformed, strings are left intact in composed messages
  479. {
  480. TString modelStr(R"_({"Part": {"String":"value_str", "Bytes": "value_bytes"}})_");
  481. TCompositeOptional proto;
  482. TJson2ProtoConfig config;
  483. config.AddStringTransform(new TBytesTransform);
  484. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TCompositeOptional>(modelStr, config));
  485. UNIT_ASSERT(proto.GetPart().GetString() == "value_str");
  486. UNIT_ASSERT(proto.GetPart().GetBytes() == "transformed_bytes");
  487. }
  488. } // TestStringTransforms
  489. Y_UNIT_TEST(TestCastFromString) {
  490. // single fields
  491. {
  492. NJson::TJsonValue json;
  493. #define DEFINE_FIELD(name, value) \
  494. json.InsertValue(#name, ConvertToString(value));
  495. #include <library/cpp/protobuf/json/ut/fields.incl>
  496. #undef DEFINE_FIELD
  497. TFlatOptional proto;
  498. UNIT_ASSERT_EXCEPTION_CONTAINS(Json2Proto(json, proto), yexception, "Invalid type");
  499. TJson2ProtoConfig config;
  500. config.SetCastFromString(true);
  501. Json2Proto(json, proto, config);
  502. TFlatOptional modelProto;
  503. FillFlatProto(&modelProto);
  504. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  505. }
  506. // repeated fields
  507. {
  508. NJson::TJsonValue json;
  509. #define DEFINE_REPEATED_FIELD(name, type, ...) \
  510. { \
  511. type values[] = {__VA_ARGS__}; \
  512. NJson::TJsonValue array(NJson::JSON_ARRAY); \
  513. for (size_t i = 0, end = Y_ARRAY_SIZE(values); i < end; ++i) { \
  514. array.AppendValue(ConvertToString(values[i])); \
  515. } \
  516. json.InsertValue(#name, array); \
  517. }
  518. #include <library/cpp/protobuf/json/ut/repeated_fields.incl>
  519. #undef DEFINE_REPEATED_FIELD
  520. TFlatRepeated proto;
  521. UNIT_ASSERT_EXCEPTION_CONTAINS(Json2Proto(json, proto), yexception, "Invalid type");
  522. TJson2ProtoConfig config;
  523. config.SetCastFromString(true);
  524. Json2Proto(json, proto, config);
  525. TFlatRepeated modelProto;
  526. FillRepeatedProto(&modelProto);
  527. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  528. }
  529. } // TestCastFromString
  530. Y_UNIT_TEST(TestMap) {
  531. TMapType modelProto;
  532. auto& items = *modelProto.MutableItems();
  533. items["key1"] = "value1";
  534. items["key2"] = "value2";
  535. items["key3"] = "value3";
  536. TString modelStr(R"_({"Items":[{"key":"key3","value":"value3"},{"key":"key2","value":"value2"},{"key":"key1","value":"value1"}]})_");
  537. TJson2ProtoConfig config;
  538. TMapType proto;
  539. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TMapType>(modelStr, config));
  540. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  541. } // TestMap
  542. Y_UNIT_TEST(TestCastRobust) {
  543. NJson::TJsonValue json;
  544. json["I32"] = "5";
  545. json["Bool"] = 1;
  546. json["String"] = 6;
  547. json["Double"] = 8;
  548. TFlatOptional proto;
  549. UNIT_ASSERT_EXCEPTION_CONTAINS(Json2Proto(json, proto), yexception, "Invalid type");
  550. TJson2ProtoConfig config;
  551. config.SetCastRobust(true);
  552. Json2Proto(json, proto, config);
  553. TFlatOptional expected;
  554. expected.SetI32(5);
  555. expected.SetBool(true);
  556. expected.SetString("6");
  557. expected.SetDouble(8);
  558. UNIT_ASSERT_PROTOS_EQUAL(proto, expected);
  559. }
  560. Y_UNIT_TEST(TestVectorizeScalars) {
  561. NJson::TJsonValue json;
  562. #define DEFINE_FIELD(name, value) \
  563. json.InsertValue(#name, value);
  564. #include <library/cpp/protobuf/json/ut/fields.incl>
  565. #undef DEFINE_FIELD
  566. TFlatRepeated proto;
  567. TJson2ProtoConfig config;
  568. config.SetVectorizeScalars(true);
  569. Json2Proto(json, proto, config);
  570. #define DEFINE_FIELD(name, value) \
  571. UNIT_ASSERT_VALUES_EQUAL(proto.Get ## name(0), value);
  572. #include <library/cpp/protobuf/json/ut/fields.incl>
  573. #undef DEFINE_FIELD
  574. }
  575. Y_UNIT_TEST(TestValueVectorizer) {
  576. {
  577. // No ValueVectorizer
  578. NJson::TJsonValue json;
  579. json["RepeatedString"] = "123";
  580. TJson2ProtoConfig config;
  581. TSingleRepeatedString expected;
  582. UNIT_ASSERT_EXCEPTION(Json2Proto(json, expected, config), yexception);
  583. }
  584. {
  585. // ValueVectorizer replace original value by array
  586. NJson::TJsonValue json;
  587. json["RepeatedString"] = "123";
  588. TJson2ProtoConfig config;
  589. TSingleRepeatedString expected;
  590. expected.AddRepeatedString("4");
  591. expected.AddRepeatedString("5");
  592. expected.AddRepeatedString("6");
  593. config.ValueVectorizer = [](const NJson::TJsonValue& val) -> NJson::TJsonValue::TArray {
  594. Y_UNUSED(val);
  595. return {NJson::TJsonValue("4"), NJson::TJsonValue("5"), NJson::TJsonValue("6")};
  596. };
  597. TSingleRepeatedString actual;
  598. Json2Proto(json, actual, config);
  599. UNIT_ASSERT_PROTOS_EQUAL(expected, actual);
  600. }
  601. {
  602. // ValueVectorizer replace original value by array and cast
  603. NJson::TJsonValue json;
  604. json["RepeatedInt"] = 123;
  605. TJson2ProtoConfig config;
  606. TSingleRepeatedInt expected;
  607. expected.AddRepeatedInt(4);
  608. expected.AddRepeatedInt(5);
  609. expected.AddRepeatedInt(6);
  610. config.ValueVectorizer = [](const NJson::TJsonValue& val) -> NJson::TJsonValue::TArray {
  611. Y_UNUSED(val);
  612. return {NJson::TJsonValue("4"), NJson::TJsonValue(5), NJson::TJsonValue("6")};
  613. };
  614. config.CastFromString = true;
  615. TSingleRepeatedInt actual;
  616. Json2Proto(json, actual, config);
  617. UNIT_ASSERT_PROTOS_EQUAL(expected, actual);
  618. }
  619. }
  620. Y_UNIT_TEST(TestMapAsObject) {
  621. TMapType modelProto;
  622. auto& items = *modelProto.MutableItems();
  623. items["key1"] = "value1";
  624. items["key2"] = "value2";
  625. items["key3"] = "value3";
  626. TString modelStr(R"_({"Items":{"key1":"value1","key2":"value2","key3":"value3"}})_");
  627. TJson2ProtoConfig config;
  628. config.MapAsObject = true;
  629. TMapType proto;
  630. UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TMapType>(modelStr, config));
  631. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  632. } // TestMapAsObject
  633. Y_UNIT_TEST(TestComplexMapAsObject_I32) {
  634. TestComplexMapAsObject(
  635. [](TComplexMapType& proto) {
  636. auto& items = *proto.MutableI32();
  637. items[1] = 1;
  638. items[-2] = -2;
  639. items[3] = 3;
  640. },
  641. R"_({"I32":{"1":1,"-2":-2,"3":3}})_");
  642. } // TestComplexMapAsObject_I32
  643. Y_UNIT_TEST(TestComplexMapAsObject_I64) {
  644. TestComplexMapAsObject(
  645. [](TComplexMapType& proto) {
  646. auto& items = *proto.MutableI64();
  647. items[2147483649L] = 2147483649L;
  648. items[-2147483650L] = -2147483650L;
  649. items[2147483651L] = 2147483651L;
  650. },
  651. R"_({"I64":{"2147483649":2147483649,"-2147483650":-2147483650,"2147483651":2147483651}})_");
  652. } // TestComplexMapAsObject_I64
  653. Y_UNIT_TEST(TestComplexMapAsObject_UI32) {
  654. TestComplexMapAsObject(
  655. [](TComplexMapType& proto) {
  656. auto& items = *proto.MutableUI32();
  657. items[1073741825U] = 1073741825U;
  658. items[1073741826U] = 1073741826U;
  659. items[1073741827U] = 1073741827U;
  660. },
  661. R"_({"UI32":{"1073741825":1073741825,"1073741826":1073741826,"1073741827":1073741827}})_");
  662. } // TestComplexMapAsObject_UI32
  663. Y_UNIT_TEST(TestComplexMapAsObject_UI64) {
  664. TestComplexMapAsObject(
  665. [](TComplexMapType& proto) {
  666. auto& items = *proto.MutableUI64();
  667. items[9223372036854775809UL] = 9223372036854775809UL;
  668. items[9223372036854775810UL] = 9223372036854775810UL;
  669. items[9223372036854775811UL] = 9223372036854775811UL;
  670. },
  671. R"_({"UI64":{"9223372036854775809":9223372036854775809,"9223372036854775810":9223372036854775810,"9223372036854775811":9223372036854775811}})_");
  672. } // TestComplexMapAsObject_UI64
  673. Y_UNIT_TEST(TestComplexMapAsObject_SI32) {
  674. TestComplexMapAsObject(
  675. [](TComplexMapType& proto) {
  676. auto& items = *proto.MutableSI32();
  677. items[1] = 1;
  678. items[-2] = -2;
  679. items[3] = 3;
  680. },
  681. R"_({"SI32":{"1":1,"-2":-2,"3":3}})_");
  682. } // TestComplexMapAsObject_SI32
  683. Y_UNIT_TEST(TestComplexMapAsObject_SI64) {
  684. TestComplexMapAsObject(
  685. [](TComplexMapType& proto) {
  686. auto& items = *proto.MutableSI64();
  687. items[2147483649L] = 2147483649L;
  688. items[-2147483650L] = -2147483650L;
  689. items[2147483651L] = 2147483651L;
  690. },
  691. R"_({"SI64":{"2147483649":2147483649,"-2147483650":-2147483650,"2147483651":2147483651}})_");
  692. } // TestComplexMapAsObject_SI64
  693. Y_UNIT_TEST(TestComplexMapAsObject_FI32) {
  694. TestComplexMapAsObject(
  695. [](TComplexMapType& proto) {
  696. auto& items = *proto.MutableFI32();
  697. items[1073741825U] = 1073741825U;
  698. items[1073741826U] = 1073741826U;
  699. items[1073741827U] = 1073741827U;
  700. },
  701. R"_({"FI32":{"1073741825":1073741825,"1073741826":1073741826,"1073741827":1073741827}})_");
  702. } // TestComplexMapAsObject_FI32
  703. Y_UNIT_TEST(TestComplexMapAsObject_FI64) {
  704. TestComplexMapAsObject(
  705. [](TComplexMapType& proto) {
  706. auto& items = *proto.MutableFI64();
  707. items[9223372036854775809UL] = 9223372036854775809UL;
  708. items[9223372036854775810UL] = 9223372036854775810UL;
  709. items[9223372036854775811UL] = 9223372036854775811UL;
  710. },
  711. R"_({"FI64":{"9223372036854775809":9223372036854775809,"9223372036854775810":9223372036854775810,"9223372036854775811":9223372036854775811}})_");
  712. } // TestComplexMapAsObject_FI64
  713. Y_UNIT_TEST(TestComplexMapAsObject_SFI32) {
  714. TestComplexMapAsObject(
  715. [](TComplexMapType& proto) {
  716. auto& items = *proto.MutableSFI32();
  717. items[1] = 1;
  718. items[-2] = -2;
  719. items[3] = 3;
  720. },
  721. R"_({"SFI32":{"1":1,"-2":-2,"3":3}})_");
  722. } // TestComplexMapAsObject_SFI32
  723. Y_UNIT_TEST(TestComplexMapAsObject_SFI64) {
  724. TestComplexMapAsObject(
  725. [](TComplexMapType& proto) {
  726. auto& items = *proto.MutableSFI64();
  727. items[2147483649L] = 2147483649L;
  728. items[-2147483650L] = -2147483650L;
  729. items[2147483651L] = 2147483651L;
  730. },
  731. R"_({"SFI64":{"2147483649":2147483649,"-2147483650":-2147483650,"2147483651":2147483651}})_");
  732. } // TestComplexMapAsObject_SFI64
  733. Y_UNIT_TEST(TestComplexMapAsObject_Bool) {
  734. TestComplexMapAsObject(
  735. [](TComplexMapType& proto) {
  736. auto& items = *proto.MutableBool();
  737. items[true] = true;
  738. items[false] = false;
  739. },
  740. R"_({"Bool":{"true":true,"false":false}})_");
  741. } // TestComplexMapAsObject_Bool
  742. Y_UNIT_TEST(TestComplexMapAsObject_String) {
  743. TestComplexMapAsObject(
  744. [](TComplexMapType& proto) {
  745. auto& items = *proto.MutableString();
  746. items["key1"] = "value1";
  747. items["key2"] = "value2";
  748. items["key3"] = "value3";
  749. items[""] = "value4";
  750. },
  751. R"_({"String":{"key1":"value1","key2":"value2","key3":"value3","":"value4"}})_");
  752. } // TestComplexMapAsObject_String
  753. Y_UNIT_TEST(TestComplexMapAsObject_Enum) {
  754. TestComplexMapAsObject(
  755. [](TComplexMapType& proto) {
  756. auto& items = *proto.MutableEnum();
  757. items["key1"] = EEnum::E_1;
  758. items["key2"] = EEnum::E_2;
  759. items["key3"] = EEnum::E_3;
  760. },
  761. R"_({"Enum":{"key1":1,"key2":2,"key3":3}})_");
  762. } // TestComplexMapAsObject_Enum
  763. Y_UNIT_TEST(TestComplexMapAsObject_EnumString) {
  764. TestComplexMapAsObject(
  765. [](TComplexMapType& proto) {
  766. auto& items = *proto.MutableEnum();
  767. items["key1"] = EEnum::E_1;
  768. items["key2"] = EEnum::E_2;
  769. items["key3"] = EEnum::E_3;
  770. },
  771. R"_({"Enum":{"key1":"E_1","key2":"E_2","key3":"E_3"}})_");
  772. } // TestComplexMapAsObject_EnumString
  773. Y_UNIT_TEST(TestComplexMapAsObject_EnumStringCaseInsensetive) {
  774. TestComplexMapAsObject(
  775. [](TComplexMapType& proto) {
  776. auto& items = *proto.MutableEnum();
  777. items["key1"] = EEnum::E_1;
  778. items["key2"] = EEnum::E_2;
  779. items["key3"] = EEnum::E_3;
  780. },
  781. R"_({"Enum":{"key1":"e_1","key2":"E_2","key3":"e_3"}})_",
  782. TJson2ProtoConfig()
  783. .SetMapAsObject(true)
  784. .SetEnumValueMode(NProtobufJson::TJson2ProtoConfig::EnumCaseInsensetive)
  785. );
  786. } // TestComplexMapAsObject_EnumStringCaseInsensetive
  787. Y_UNIT_TEST(TestComplexMapAsObject_EnumStringSnakeCaseInsensitive) {
  788. TestComplexMapAsObject(
  789. [](TComplexMapType& proto) {
  790. auto& items = *proto.MutableEnum();
  791. items["key1"] = EEnum::E_1;
  792. items["key2"] = EEnum::E_2;
  793. items["key3"] = EEnum::E_3;
  794. },
  795. R"_({"Enum":{"key1":"e1","key2":"_E_2_","key3":"e_3"}})_",
  796. TJson2ProtoConfig()
  797. .SetMapAsObject(true)
  798. .SetEnumValueMode(NProtobufJson::TJson2ProtoConfig::EnumSnakeCaseInsensitive)
  799. );
  800. } // TestComplexMapAsObject_EnumStringCaseInsensetive
  801. Y_UNIT_TEST(TestComplexMapAsObject_Float) {
  802. TestComplexMapAsObject(
  803. [](TComplexMapType& proto) {
  804. auto& items = *proto.MutableFloat();
  805. items["key1"] = 0.1f;
  806. items["key2"] = 0.2f;
  807. items["key3"] = 0.3f;
  808. },
  809. R"_({"Float":{"key1":0.1,"key2":0.2,"key3":0.3}})_");
  810. } // TestComplexMapAsObject_Float
  811. Y_UNIT_TEST(TestComplexMapAsObject_Double) {
  812. TestComplexMapAsObject(
  813. [](TComplexMapType& proto) {
  814. auto& items = *proto.MutableDouble();
  815. items["key1"] = 0.1L;
  816. items["key2"] = 0.2L;
  817. items["key3"] = 0.3L;
  818. },
  819. R"_({"Double":{"key1":0.1,"key2":0.2,"key3":0.3}})_");
  820. } // TestComplexMapAsObject_Double
  821. Y_UNIT_TEST(TestComplexMapAsObject_Nested) {
  822. TestComplexMapAsObject(
  823. [](TComplexMapType& proto) {
  824. TComplexMapType inner;
  825. auto& innerItems = *inner.MutableString();
  826. innerItems["key"] = "value";
  827. auto& items = *proto.MutableNested();
  828. items["key1"] = inner;
  829. items["key2"] = inner;
  830. items["key3"] = inner;
  831. },
  832. R"_({"Nested":{"key1":{"String":{"key":"value"}},"key2":{"String":{"key":"value"}},"key3":{"String":{"key":"value"}}}})_");
  833. } // TestComplexMapAsObject_Nested
  834. Y_UNIT_TEST(TestMapAsObjectConfigNotSet) {
  835. TString modelStr(R"_({"Items":{"key":"value"}})_");
  836. TJson2ProtoConfig config;
  837. UNIT_ASSERT_EXCEPTION_CONTAINS(
  838. Json2Proto<TMapType>(modelStr, config), yexception,
  839. "Map as object representation is not allowed");
  840. } // TestMapAsObjectNotSet
  841. Y_UNIT_TEST(TestMergeFlatOptional) {
  842. const NJson::TJsonValue& json = CreateFlatJson();
  843. NJson::TJsonValue patch;
  844. patch["I32"] = 5;
  845. patch["Bool"] = false;
  846. patch["String"] = "abacaba";
  847. patch["Double"] = 0.123;
  848. TFlatOptional proto;
  849. UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
  850. UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto));
  851. TFlatRequired modelProto;
  852. FillFlatProto(&modelProto);
  853. modelProto.SetI32(5);
  854. modelProto.SetBool(false);
  855. modelProto.SetString("abacaba");
  856. modelProto.SetDouble(0.123);
  857. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  858. } // TestMergeFlatOptional
  859. Y_UNIT_TEST(TestMergeFlatRequired) {
  860. const NJson::TJsonValue& json = CreateFlatJson();
  861. NJson::TJsonValue patch;
  862. patch["I32"] = 5;
  863. patch["Bool"] = false;
  864. patch["String"] = "abacaba";
  865. patch["Double"] = 0.123;
  866. TFlatRequired proto;
  867. UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
  868. UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto));
  869. TFlatRequired modelProto;
  870. FillFlatProto(&modelProto);
  871. modelProto.SetI32(5);
  872. modelProto.SetBool(false);
  873. modelProto.SetString("abacaba");
  874. modelProto.SetDouble(0.123);
  875. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  876. } // TestMergeFlatRequired
  877. Y_UNIT_TEST(TestMergeComposite) {
  878. const NJson::TJsonValue& json = CreateCompositeJson();
  879. NJson::TJsonValue patch;
  880. patch["Part"]["I32"] = 5;
  881. patch["Part"]["Bool"] = false;
  882. patch["Part"]["String"] = "abacaba";
  883. patch["Part"]["Double"] = 0.123;
  884. TCompositeOptional proto;
  885. UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
  886. UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto));
  887. TCompositeOptional modelProto;
  888. FillCompositeProto(&modelProto);
  889. modelProto.MutablePart()->SetI32(5);
  890. modelProto.MutablePart()->SetBool(false);
  891. modelProto.MutablePart()->SetString("abacaba");
  892. modelProto.MutablePart()->SetDouble(0.123);
  893. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  894. } // TestMergeComposite
  895. Y_UNIT_TEST(TestMergeRepeatedReplace) {
  896. const NJson::TJsonValue& json = CreateRepeatedFlatJson();
  897. NJson::TJsonValue patch;
  898. patch["I32"].AppendValue(5);
  899. patch["I32"].AppendValue(6);
  900. patch["String"].AppendValue("abacaba");
  901. TFlatRepeated proto;
  902. TJson2ProtoConfig config;
  903. config.ReplaceRepeatedFields = true;
  904. UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
  905. UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto, config));
  906. TFlatRepeated modelProto;
  907. FillRepeatedProto(&modelProto);
  908. modelProto.ClearI32();
  909. modelProto.AddI32(5);
  910. modelProto.AddI32(6);
  911. modelProto.ClearString();
  912. modelProto.AddString("abacaba");
  913. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  914. } // TestMergeRepeatedReplace
  915. Y_UNIT_TEST(TestMergeRepeatedAppend) {
  916. const NJson::TJsonValue& json = CreateRepeatedFlatJson();
  917. NJson::TJsonValue patch;
  918. patch["I32"].AppendValue(5);
  919. patch["I32"].AppendValue(6);
  920. patch["String"].AppendValue("abacaba");
  921. TFlatRepeated proto;
  922. UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
  923. UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto));
  924. TFlatRepeated modelProto;
  925. FillRepeatedProto(&modelProto);
  926. modelProto.AddI32(5);
  927. modelProto.AddI32(6);
  928. modelProto.AddString("abacaba");
  929. UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
  930. } // TestMergeRepeatedAppend
  931. Y_UNIT_TEST(TestEmptyStringForCastFromString) {
  932. NJson::TJsonValue json;
  933. json["I32"] = "";
  934. json["Bool"] = "";
  935. json["OneString"] = "";
  936. TJson2ProtoConfig config;
  937. config.SetCastFromString(true);
  938. config.SetDoNotCastEmptyStrings(true);
  939. TFlatOptional proto;
  940. UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto, config));
  941. UNIT_ASSERT(!proto.HasBool());
  942. UNIT_ASSERT(!proto.HasI32());
  943. UNIT_ASSERT(proto.HasOneString());
  944. UNIT_ASSERT_EQUAL("", proto.GetOneString());
  945. } // TestEmptyStringForCastFromString
  946. Y_UNIT_TEST(TestAllowComments) {
  947. constexpr TStringBuf json = R"(
  948. {
  949. "I32": 4, // comment1
  950. /*
  951. comment2
  952. {}
  953. qwer
  954. */
  955. "I64": 3423
  956. }
  957. )";
  958. TJson2ProtoConfig config;
  959. TFlatOptional proto;
  960. UNIT_ASSERT_EXCEPTION_CONTAINS(Json2Proto(json, proto, config), yexception, "Error: Missing a name for object member");
  961. config.SetAllowComments(true);
  962. UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto, config));
  963. UNIT_ASSERT_VALUES_EQUAL(proto.GetI32(), 4);
  964. UNIT_ASSERT_VALUES_EQUAL(proto.GetI64(), 3423);
  965. } // TestAllowComments
  966. } // TJson2ProtoTest