json2proto_ut.cpp 40 KB

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