1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189 |
- #include "json.h"
- #include "proto.h"
- #include "proto2json.h"
- #include <library/cpp/protobuf/json/ut/test.pb.h>
- #include <library/cpp/json/json_value.h>
- #include <library/cpp/json/json_reader.h>
- #include <library/cpp/json/json_writer.h>
- #include <library/cpp/protobuf/interop/cast.h>
- #include <library/cpp/protobuf/json/json2proto.h>
- #include <library/cpp/testing/unittest/registar.h>
- #include <util/generic/hash_set.h>
- #include <util/generic/string.h>
- #include <util/generic/ylimits.h>
- #include <util/stream/str.h>
- #include <util/string/cast.h>
- #include <util/system/defaults.h>
- #include <util/system/yassert.h>
- using namespace NProtobufJson;
- using namespace NProtobufJsonTest;
- namespace google {
- namespace protobuf {
- namespace internal {
- void MapTestForceDeterministic() {
- google::protobuf::io::CodedOutputStream::SetDefaultSerializationDeterministic();
- }
- }
- } // namespace protobuf
- }
- namespace {
- class TInit {
- public:
- TInit() {
- ::google::protobuf::internal::MapTestForceDeterministic();
- }
- } Init;
- template <typename T>
- TString ConvertToString(T value) {
- return ToString(value);
- }
- // default ToString<double>() implementation loses precision
- TString ConvertToString(double value) {
- return FloatToString(value);
- }
- TString JsonValueToString(const NJson::TJsonValue& json) {
- NJsonWriter::TBuf buf(NJsonWriter::HEM_UNSAFE);
- return buf.WriteJsonValue(&json).Str();
- }
- void TestComplexMapAsObject(std::function<void(TComplexMapType&)>&& init, const TString& json, const TJson2ProtoConfig& config = TJson2ProtoConfig().SetMapAsObject(true)) {
- TComplexMapType modelProto;
- init(modelProto);
- TString modelStr(json);
- TComplexMapType proto;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TComplexMapType>(modelStr, config));
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- }
- }
- Y_UNIT_TEST_SUITE(TJson2ProtoTest) {
- Y_UNIT_TEST(TestFlatOptional){
- {const NJson::TJsonValue& json = CreateFlatJson();
- TFlatOptional proto;
- Json2Proto(json, proto);
- TFlatOptional modelProto;
- FillFlatProto(&modelProto);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- }
- // Try to skip each field
- #define DEFINE_FIELD(name, value) \
- { \
- THashSet<TString> skippedField; \
- skippedField.insert(#name); \
- const NJson::TJsonValue& json = CreateFlatJson(skippedField); \
- TFlatOptional proto; \
- Json2Proto(json, proto); \
- TFlatOptional modelProto; \
- FillFlatProto(&modelProto, skippedField); \
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto); \
- }
- #include <library/cpp/protobuf/json/ut/fields.incl>
- #undef DEFINE_FIELD
- } // TestFlatOptional
- Y_UNIT_TEST(TestFlatRequired){
- {const NJson::TJsonValue& json = CreateFlatJson();
- TFlatRequired proto;
- Json2Proto(json, proto);
- TFlatRequired modelProto;
- FillFlatProto(&modelProto);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- }
- // Try to skip each field
- #define DEFINE_FIELD(name, value) \
- { \
- THashSet<TString> skippedField; \
- skippedField.insert(#name); \
- const NJson::TJsonValue& json = CreateFlatJson(skippedField); \
- TFlatRequired proto; \
- UNIT_ASSERT_EXCEPTION(Json2Proto(json, proto), yexception); \
- }
- #include <library/cpp/protobuf/json/ut/fields.incl>
- #undef DEFINE_FIELD
- } // TestFlatRequired
- Y_UNIT_TEST(TestNameGenerator) {
- TJson2ProtoConfig cfg;
- cfg.SetNameGenerator([](const NProtoBuf::FieldDescriptor&) { return "42"; });
- TNameGeneratorType proto;
- Json2Proto(TStringBuf(R"({"42":42})"), proto, cfg);
- TNameGeneratorType expected;
- expected.SetField(42);
- UNIT_ASSERT_PROTOS_EQUAL(expected, proto);
- }
- Y_UNIT_TEST(TestFlatNoCheckRequired) {
- {
- const NJson::TJsonValue& json = CreateFlatJson();
- TFlatRequired proto;
- Json2Proto(json, proto);
- TFlatRequired modelProto;
- FillFlatProto(&modelProto);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- }
- TJson2ProtoConfig cfg;
- cfg.CheckRequiredFields = false;
- // Try to skip each field
- #define DEFINE_FIELD(name, value) \
- { \
- THashSet<TString> skippedField; \
- skippedField.insert(#name); \
- const NJson::TJsonValue& json = CreateFlatJson(skippedField); \
- TFlatRequired proto; \
- UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto, cfg)); \
- }
- #include <library/cpp/protobuf/json/ut/fields.incl>
- #undef DEFINE_FIELD
- } // TestFlatNoCheckRequired
- Y_UNIT_TEST(TestFlatRepeated){
- {const NJson::TJsonValue& json = CreateRepeatedFlatJson();
- TFlatRepeated proto;
- Json2Proto(json, proto);
- TFlatRepeated modelProto;
- FillRepeatedProto(&modelProto);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- }
- // Try to skip each field
- #define DEFINE_REPEATED_FIELD(name, ...) \
- { \
- THashSet<TString> skippedField; \
- skippedField.insert(#name); \
- const NJson::TJsonValue& json = CreateRepeatedFlatJson(skippedField); \
- TFlatRepeated proto; \
- Json2Proto(json, proto); \
- TFlatRepeated modelProto; \
- FillRepeatedProto(&modelProto, skippedField); \
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto); \
- }
- #include <library/cpp/protobuf/json/ut/repeated_fields.incl>
- #undef DEFINE_REPEATED_FIELD
- } // TestFlatRepeated
- Y_UNIT_TEST(TestCompositeOptional){
- {const NJson::TJsonValue& json = CreateCompositeJson();
- TCompositeOptional proto;
- Json2Proto(json, proto);
- TCompositeOptional modelProto;
- FillCompositeProto(&modelProto);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- }
- // Try to skip each field
- #define DEFINE_FIELD(name, value) \
- { \
- THashSet<TString> skippedField; \
- skippedField.insert(#name); \
- const NJson::TJsonValue& json = CreateCompositeJson(skippedField); \
- TCompositeOptional proto; \
- Json2Proto(json, proto); \
- TCompositeOptional modelProto; \
- FillCompositeProto(&modelProto, skippedField); \
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto); \
- }
- #include <library/cpp/protobuf/json/ut/fields.incl>
- #undef DEFINE_FIELD
- } // TestCompositeOptional
- Y_UNIT_TEST(TestCompositeOptionalStringBuf){
- {NJson::TJsonValue json = CreateCompositeJson();
- json["Part"]["Double"] = 42.5;
- TCompositeOptional proto;
- Json2Proto(JsonValueToString(json), proto);
- TCompositeOptional modelProto;
- FillCompositeProto(&modelProto);
- modelProto.MutablePart()->SetDouble(42.5);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- }
- // Try to skip each field
- #define DEFINE_FIELD(name, value) \
- { \
- THashSet<TString> skippedField; \
- skippedField.insert(#name); \
- NJson::TJsonValue json = CreateCompositeJson(skippedField); \
- if (json["Part"].Has("Double")) { \
- json["Part"]["Double"] = 42.5; \
- } \
- TCompositeOptional proto; \
- Json2Proto(JsonValueToString(json), proto); \
- TCompositeOptional modelProto; \
- FillCompositeProto(&modelProto, skippedField); \
- if (modelProto.GetPart().HasDouble()) { \
- modelProto.MutablePart()->SetDouble(42.5); \
- } \
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto); \
- }
- #include <library/cpp/protobuf/json/ut/fields.incl>
- #undef DEFINE_FIELD
- } // TestCompositeOptionalStringBuf
- Y_UNIT_TEST(TestCompositeRequired) {
- {
- const NJson::TJsonValue& json = CreateCompositeJson();
- TCompositeRequired proto;
- Json2Proto(json, proto);
- TCompositeRequired modelProto;
- FillCompositeProto(&modelProto);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- }
- {
- NJson::TJsonValue json;
- TCompositeRequired proto;
- UNIT_ASSERT_EXCEPTION(Json2Proto(json, proto), yexception);
- }
- } // TestCompositeRequired
- Y_UNIT_TEST(TestCompositeRepeated) {
- {
- NJson::TJsonValue json;
- NJson::TJsonValue array;
- array.AppendValue(CreateFlatJson());
- json.InsertValue("Part", array);
- TCompositeRepeated proto;
- Json2Proto(json, proto);
- TFlatOptional partModelProto;
- FillFlatProto(&partModelProto);
- TCompositeRepeated modelProto;
- modelProto.AddPart()->CopyFrom(partModelProto);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- }
- {
- // Array of messages with each field skipped
- TCompositeRepeated modelProto;
- NJson::TJsonValue array;
- #define DEFINE_REPEATED_FIELD(name, ...) \
- { \
- THashSet<TString> skippedField; \
- skippedField.insert(#name); \
- TFlatOptional partModelProto; \
- FillFlatProto(&partModelProto, skippedField); \
- modelProto.AddPart()->CopyFrom(partModelProto); \
- array.AppendValue(CreateFlatJson(skippedField)); \
- }
- #include <library/cpp/protobuf/json/ut/repeated_fields.incl>
- #undef DEFINE_REPEATED_FIELD
- NJson::TJsonValue json;
- json.InsertValue("Part", array);
- TCompositeRepeated proto;
- Json2Proto(json, proto);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- }
- } // TestCompositeRepeated
- Y_UNIT_TEST(TestInvalidEnum) {
- {
- NJson::TJsonValue json;
- json.InsertValue("Enum", "E_100");
- TFlatOptional proto;
- UNIT_ASSERT_EXCEPTION(Json2Proto(json, proto), yexception);
- }
- {
- NJson::TJsonValue json;
- json.InsertValue("Enum", 100);
- TFlatOptional proto;
- UNIT_ASSERT_EXCEPTION(Json2Proto(json, proto), yexception);
- }
- }
- Y_UNIT_TEST(TestFieldNameMode) {
- // Original case 1
- {
- TString modelStr(R"_({"String":"value"})_");
- TFlatOptional proto;
- TJson2ProtoConfig config;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
- UNIT_ASSERT(proto.GetString() == "value");
- }
- // Original case 2
- {
- TString modelStr(R"_({"String":"value"})_");
- TFlatOptional proto;
- TJson2ProtoConfig config;
- config.FieldNameMode = TJson2ProtoConfig::FieldNameOriginalCase;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
- UNIT_ASSERT(proto.GetString() == "value");
- }
- // Lowercase
- {
- TString modelStr(R"_({"string":"value"})_");
- TFlatOptional proto;
- TJson2ProtoConfig config;
- config.FieldNameMode = TJson2ProtoConfig::FieldNameLowerCase;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
- UNIT_ASSERT(proto.GetString() == "value");
- }
- // Uppercase
- {
- TString modelStr(R"_({"STRING":"value"})_");
- TFlatOptional proto;
- TJson2ProtoConfig config;
- config.FieldNameMode = TJson2ProtoConfig::FieldNameUpperCase;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
- UNIT_ASSERT(proto.GetString() == "value");
- }
- // Camelcase
- {
- TString modelStr(R"_({"string":"value"})_");
- TFlatOptional proto;
- TJson2ProtoConfig config;
- config.FieldNameMode = TJson2ProtoConfig::FieldNameCamelCase;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
- UNIT_ASSERT(proto.GetString() == "value");
- }
- {
- TString modelStr(R"_({"oneString":"value"})_");
- TFlatOptional proto;
- TJson2ProtoConfig config;
- config.FieldNameMode = TJson2ProtoConfig::FieldNameCamelCase;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
- UNIT_ASSERT(proto.GetOneString() == "value");
- }
- {
- TString modelStr(R"_({"oneTwoString":"value"})_");
- TFlatOptional proto;
- TJson2ProtoConfig config;
- config.FieldNameMode = TJson2ProtoConfig::FieldNameCamelCase;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
- UNIT_ASSERT(proto.GetOneTwoString() == "value");
- }
- // snake_case
- {
- TString modelStr(R"_({"string":"value"})_");
- TFlatOptional proto;
- TJson2ProtoConfig config;
- config.FieldNameMode = TJson2ProtoConfig::FieldNameSnakeCase;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
- UNIT_ASSERT(proto.GetString() == "value");
- }
- {
- TString modelStr(R"_({"one_string":"value"})_");
- TFlatOptional proto;
- TJson2ProtoConfig config;
- config.FieldNameMode = TJson2ProtoConfig::FieldNameSnakeCase;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
- UNIT_ASSERT(proto.GetOneString() == "value");
- }
- {
- TString modelStr(R"_({"one_two_string":"value"})_");
- TFlatOptional proto;
- TJson2ProtoConfig config;
- config.FieldNameMode = TJson2ProtoConfig::FieldNameSnakeCase;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
- UNIT_ASSERT(proto.GetOneTwoString() == "value");
- }
- // Original case, repeated
- {
- TString modelStr(R"_({"I32":[1,2]})_");
- TFlatRepeated proto;
- TJson2ProtoConfig config;
- config.FieldNameMode = TJson2ProtoConfig::FieldNameOriginalCase;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatRepeated>(modelStr, config));
- UNIT_ASSERT(proto.I32Size() == 2);
- UNIT_ASSERT(proto.GetI32(0) == 1);
- UNIT_ASSERT(proto.GetI32(1) == 2);
- }
- // Lower case, repeated
- {
- TString modelStr(R"_({"i32":[1,2]})_");
- TFlatRepeated proto;
- TJson2ProtoConfig config;
- config.FieldNameMode = TJson2ProtoConfig::FieldNameLowerCase;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatRepeated>(modelStr, config));
- UNIT_ASSERT(proto.I32Size() == 2);
- UNIT_ASSERT(proto.GetI32(0) == 1);
- UNIT_ASSERT(proto.GetI32(1) == 2);
- }
- // UseJsonName
- {
- // FIXME(CONTRIB-139): since protobuf 3.1, Def_upper json name is
- // "DefUpper", but until kernel/ugc/schema and yweb/yasap/pdb are
- // updated, library/cpp/protobuf/json preserves compatibility with
- // protobuf 3.0 by lowercasing default names, making it "defUpper".
- TString modelStr(R"_({"My-Upper":1,"my-lower":2,"defUpper":3,"defLower":4})_");
- TWithJsonName proto;
- TJson2ProtoConfig config;
- config.SetUseJsonName(true);
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TWithJsonName>(modelStr, config));
- UNIT_ASSERT_EQUAL(proto.Getmy_upper(), 1);
- UNIT_ASSERT_EQUAL(proto.GetMy_lower(), 2);
- UNIT_ASSERT_EQUAL(proto.GetDef_upper(), 3);
- UNIT_ASSERT_EQUAL(proto.Getdef_lower(), 4);
- }
- // UseJsonName with UseJsonEnumValue
- {
- TString modelStr(R"_({"json_enum" : "enum_1"})_");
- TCustomJsonEnumValue proto;
- TJson2ProtoConfig config;
- config.SetUseJsonName(true);
- config.SetUseJsonEnumValue(true);
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TCustomJsonEnumValue>(modelStr, config));
- UNIT_ASSERT_EQUAL(proto.GetJsonEnum(), EJsonEnum::J_1);
- }
- // FieldNameMode with UseJsonName
- {
- TJson2ProtoConfig config;
- config.SetFieldNameMode(TJson2ProtoConfig::FieldNameLowerCase);
- UNIT_ASSERT_EXCEPTION_CONTAINS(
- config.SetUseJsonName(true), yexception, "mutually exclusive");
- }
- {
- TJson2ProtoConfig config;
- config.SetUseJsonName(true);
- UNIT_ASSERT_EXCEPTION_CONTAINS(
- config.SetFieldNameMode(TJson2ProtoConfig::FieldNameLowerCase), yexception, "mutually exclusive");
- }
- } // TestFieldNameMode
- class TStringTransform: public IStringTransform {
- public:
- int GetType() const override {
- return 0;
- }
- void Transform(TString& str) const override {
- str = "transformed_any";
- }
- };
- class TBytesTransform: public IStringTransform {
- public:
- int GetType() const override {
- return 0;
- }
- void Transform(TString&) const override {
- }
- void TransformBytes(TString& str) const override {
- str = "transformed_bytes";
- }
- };
- Y_UNIT_TEST(TestInvalidJson) {
- NJson::TJsonValue val{"bad value"};
- TFlatOptional proto;
- UNIT_ASSERT_EXCEPTION(Json2Proto(val, proto), yexception);
- }
- Y_UNIT_TEST(TestInvalidRepeatedFieldWithMapAsObject) {
- TCompositeRepeated proto;
- TJson2ProtoConfig config;
- config.MapAsObject = true;
- UNIT_ASSERT_EXCEPTION(Json2Proto(TStringBuf(R"({"Part":{"Boo":{}}})"), proto, config), yexception);
- }
- Y_UNIT_TEST(TestStringTransforms) {
- // Check that strings and bytes are transformed
- {
- TString modelStr(R"_({"String":"value_str", "Bytes": "value_bytes"})_");
- TFlatOptional proto;
- TJson2ProtoConfig config;
- config.AddStringTransform(new TStringTransform);
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
- UNIT_ASSERT(proto.GetString() == "transformed_any");
- UNIT_ASSERT(proto.GetBytes() == "transformed_any");
- }
- // Check that bytes are transformed, strings are left intact
- {
- TString modelStr(R"_({"String":"value_str", "Bytes": "value_bytes"})_");
- TFlatOptional proto;
- TJson2ProtoConfig config;
- config.AddStringTransform(new TBytesTransform);
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
- UNIT_ASSERT(proto.GetString() == "value_str");
- UNIT_ASSERT(proto.GetBytes() == "transformed_bytes");
- }
- // Check that repeated bytes are transformed, repeated strings are left intact
- {
- TString modelStr(R"_({"String":["value_str", "str2"], "Bytes": ["value_bytes", "bytes2"]})_");
- TFlatRepeated proto;
- TJson2ProtoConfig config;
- config.AddStringTransform(new TBytesTransform);
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatRepeated>(modelStr, config));
- UNIT_ASSERT(proto.StringSize() == 2);
- UNIT_ASSERT(proto.GetString(0) == "value_str");
- UNIT_ASSERT(proto.GetString(1) == "str2");
- UNIT_ASSERT(proto.BytesSize() == 2);
- UNIT_ASSERT(proto.GetBytes(0) == "transformed_bytes");
- UNIT_ASSERT(proto.GetBytes(1) == "transformed_bytes");
- }
- // Check that bytes are transformed, strings are left intact in composed messages
- {
- TString modelStr(R"_({"Part": {"String":"value_str", "Bytes": "value_bytes"}})_");
- TCompositeOptional proto;
- TJson2ProtoConfig config;
- config.AddStringTransform(new TBytesTransform);
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TCompositeOptional>(modelStr, config));
- UNIT_ASSERT(proto.GetPart().GetString() == "value_str");
- UNIT_ASSERT(proto.GetPart().GetBytes() == "transformed_bytes");
- }
- } // TestStringTransforms
- Y_UNIT_TEST(TestCastFromString) {
- // single fields
- {
- NJson::TJsonValue json;
- #define DEFINE_FIELD(name, value) \
- json.InsertValue(#name, ConvertToString(value));
- #include <library/cpp/protobuf/json/ut/fields.incl>
- #undef DEFINE_FIELD
- TFlatOptional proto;
- UNIT_ASSERT_EXCEPTION_CONTAINS(Json2Proto(json, proto), yexception, "Invalid type");
- TJson2ProtoConfig config;
- config.SetCastFromString(true);
- Json2Proto(json, proto, config);
- TFlatOptional modelProto;
- FillFlatProto(&modelProto);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- }
- // repeated fields
- {
- NJson::TJsonValue json;
- #define DEFINE_REPEATED_FIELD(name, type, ...) \
- { \
- type values[] = {__VA_ARGS__}; \
- NJson::TJsonValue array(NJson::JSON_ARRAY); \
- for (size_t i = 0, end = Y_ARRAY_SIZE(values); i < end; ++i) { \
- array.AppendValue(ConvertToString(values[i])); \
- } \
- json.InsertValue(#name, array); \
- }
- #include <library/cpp/protobuf/json/ut/repeated_fields.incl>
- #undef DEFINE_REPEATED_FIELD
- TFlatRepeated proto;
- UNIT_ASSERT_EXCEPTION_CONTAINS(Json2Proto(json, proto), yexception, "Invalid type");
- TJson2ProtoConfig config;
- config.SetCastFromString(true);
- Json2Proto(json, proto, config);
- TFlatRepeated modelProto;
- FillRepeatedProto(&modelProto);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- }
- } // TestCastFromString
- Y_UNIT_TEST(TestMap) {
- TMapType modelProto;
- auto& items = *modelProto.MutableItems();
- items["key1"] = "value1";
- items["key2"] = "value2";
- items["key3"] = "value3";
- TString modelStr(R"_({"Items":[{"key":"key3","value":"value3"},{"key":"key2","value":"value2"},{"key":"key1","value":"value1"}]})_");
- TJson2ProtoConfig config;
- TMapType proto;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TMapType>(modelStr, config));
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- } // TestMap
- Y_UNIT_TEST(TestCastRobust) {
- NJson::TJsonValue json;
- json["I32"] = "5";
- json["Bool"] = 1;
- json["String"] = 6;
- json["Double"] = 8;
- TFlatOptional proto;
- UNIT_ASSERT_EXCEPTION_CONTAINS(Json2Proto(json, proto), yexception, "Invalid type");
- TJson2ProtoConfig config;
- config.SetCastRobust(true);
- Json2Proto(json, proto, config);
- TFlatOptional expected;
- expected.SetI32(5);
- expected.SetBool(true);
- expected.SetString("6");
- expected.SetDouble(8);
- UNIT_ASSERT_PROTOS_EQUAL(proto, expected);
- }
- Y_UNIT_TEST(TestVectorizeScalars) {
- NJson::TJsonValue json;
- #define DEFINE_FIELD(name, value) \
- json.InsertValue(#name, value);
- #include <library/cpp/protobuf/json/ut/fields.incl>
- #undef DEFINE_FIELD
- TFlatRepeated proto;
- TJson2ProtoConfig config;
- config.SetVectorizeScalars(true);
- Json2Proto(json, proto, config);
- #define DEFINE_FIELD(name, value) \
- UNIT_ASSERT_VALUES_EQUAL(proto.Get ## name(0), value);
- #include <library/cpp/protobuf/json/ut/fields.incl>
- #undef DEFINE_FIELD
- }
- Y_UNIT_TEST(TestValueVectorizer) {
- {
- // No ValueVectorizer
- NJson::TJsonValue json;
- json["RepeatedString"] = "123";
- TJson2ProtoConfig config;
- TSingleRepeatedString expected;
- UNIT_ASSERT_EXCEPTION(Json2Proto(json, expected, config), yexception);
- }
- {
- // ValueVectorizer replace original value by array
- NJson::TJsonValue json;
- json["RepeatedString"] = "123";
- TJson2ProtoConfig config;
- TSingleRepeatedString expected;
- expected.AddRepeatedString("4");
- expected.AddRepeatedString("5");
- expected.AddRepeatedString("6");
- config.ValueVectorizer = [](const NJson::TJsonValue& val) -> NJson::TJsonValue::TArray {
- Y_UNUSED(val);
- return {NJson::TJsonValue("4"), NJson::TJsonValue("5"), NJson::TJsonValue("6")};
- };
- TSingleRepeatedString actual;
- Json2Proto(json, actual, config);
- UNIT_ASSERT_PROTOS_EQUAL(expected, actual);
- }
- {
- // ValueVectorizer replace original value by array and cast
- NJson::TJsonValue json;
- json["RepeatedInt"] = 123;
- TJson2ProtoConfig config;
- TSingleRepeatedInt expected;
- expected.AddRepeatedInt(4);
- expected.AddRepeatedInt(5);
- expected.AddRepeatedInt(6);
- config.ValueVectorizer = [](const NJson::TJsonValue& val) -> NJson::TJsonValue::TArray {
- Y_UNUSED(val);
- return {NJson::TJsonValue("4"), NJson::TJsonValue(5), NJson::TJsonValue("6")};
- };
- config.CastFromString = true;
- TSingleRepeatedInt actual;
- Json2Proto(json, actual, config);
- UNIT_ASSERT_PROTOS_EQUAL(expected, actual);
- }
- }
- Y_UNIT_TEST(TestMapAsObject) {
- TMapType modelProto;
- auto& items = *modelProto.MutableItems();
- items["key1"] = "value1";
- items["key2"] = "value2";
- items["key3"] = "value3";
- TString modelStr(R"_({"Items":{"key1":"value1","key2":"value2","key3":"value3"}})_");
- TJson2ProtoConfig config;
- config.MapAsObject = true;
- TMapType proto;
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TMapType>(modelStr, config));
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- } // TestMapAsObject
- Y_UNIT_TEST(TestComplexMapAsObject_I32) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableI32();
- items[1] = 1;
- items[-2] = -2;
- items[3] = 3;
- },
- R"_({"I32":{"1":1,"-2":-2,"3":3}})_");
- } // TestComplexMapAsObject_I32
- Y_UNIT_TEST(TestComplexMapAsObject_I64) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableI64();
- items[2147483649L] = 2147483649L;
- items[-2147483650L] = -2147483650L;
- items[2147483651L] = 2147483651L;
- },
- R"_({"I64":{"2147483649":2147483649,"-2147483650":-2147483650,"2147483651":2147483651}})_");
- } // TestComplexMapAsObject_I64
- Y_UNIT_TEST(TestComplexMapAsObject_UI32) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableUI32();
- items[1073741825U] = 1073741825U;
- items[1073741826U] = 1073741826U;
- items[1073741827U] = 1073741827U;
- },
- R"_({"UI32":{"1073741825":1073741825,"1073741826":1073741826,"1073741827":1073741827}})_");
- } // TestComplexMapAsObject_UI32
- Y_UNIT_TEST(TestComplexMapAsObject_UI64) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableUI64();
- items[9223372036854775809UL] = 9223372036854775809UL;
- items[9223372036854775810UL] = 9223372036854775810UL;
- items[9223372036854775811UL] = 9223372036854775811UL;
- },
- R"_({"UI64":{"9223372036854775809":9223372036854775809,"9223372036854775810":9223372036854775810,"9223372036854775811":9223372036854775811}})_");
- } // TestComplexMapAsObject_UI64
- Y_UNIT_TEST(TestComplexMapAsObject_SI32) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableSI32();
- items[1] = 1;
- items[-2] = -2;
- items[3] = 3;
- },
- R"_({"SI32":{"1":1,"-2":-2,"3":3}})_");
- } // TestComplexMapAsObject_SI32
- Y_UNIT_TEST(TestComplexMapAsObject_SI64) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableSI64();
- items[2147483649L] = 2147483649L;
- items[-2147483650L] = -2147483650L;
- items[2147483651L] = 2147483651L;
- },
- R"_({"SI64":{"2147483649":2147483649,"-2147483650":-2147483650,"2147483651":2147483651}})_");
- } // TestComplexMapAsObject_SI64
- Y_UNIT_TEST(TestComplexMapAsObject_FI32) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableFI32();
- items[1073741825U] = 1073741825U;
- items[1073741826U] = 1073741826U;
- items[1073741827U] = 1073741827U;
- },
- R"_({"FI32":{"1073741825":1073741825,"1073741826":1073741826,"1073741827":1073741827}})_");
- } // TestComplexMapAsObject_FI32
- Y_UNIT_TEST(TestComplexMapAsObject_FI64) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableFI64();
- items[9223372036854775809UL] = 9223372036854775809UL;
- items[9223372036854775810UL] = 9223372036854775810UL;
- items[9223372036854775811UL] = 9223372036854775811UL;
- },
- R"_({"FI64":{"9223372036854775809":9223372036854775809,"9223372036854775810":9223372036854775810,"9223372036854775811":9223372036854775811}})_");
- } // TestComplexMapAsObject_FI64
- Y_UNIT_TEST(TestComplexMapAsObject_SFI32) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableSFI32();
- items[1] = 1;
- items[-2] = -2;
- items[3] = 3;
- },
- R"_({"SFI32":{"1":1,"-2":-2,"3":3}})_");
- } // TestComplexMapAsObject_SFI32
- Y_UNIT_TEST(TestComplexMapAsObject_SFI64) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableSFI64();
- items[2147483649L] = 2147483649L;
- items[-2147483650L] = -2147483650L;
- items[2147483651L] = 2147483651L;
- },
- R"_({"SFI64":{"2147483649":2147483649,"-2147483650":-2147483650,"2147483651":2147483651}})_");
- } // TestComplexMapAsObject_SFI64
- Y_UNIT_TEST(TestComplexMapAsObject_Bool) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableBool();
- items[true] = true;
- items[false] = false;
- },
- R"_({"Bool":{"true":true,"false":false}})_");
- } // TestComplexMapAsObject_Bool
- Y_UNIT_TEST(TestComplexMapAsObject_String) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableString();
- items["key1"] = "value1";
- items["key2"] = "value2";
- items["key3"] = "value3";
- items[""] = "value4";
- },
- R"_({"String":{"key1":"value1","key2":"value2","key3":"value3","":"value4"}})_");
- } // TestComplexMapAsObject_String
- Y_UNIT_TEST(TestComplexMapAsObject_Enum) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableEnum();
- items["key1"] = EEnum::E_1;
- items["key2"] = EEnum::E_2;
- items["key3"] = EEnum::E_3;
- },
- R"_({"Enum":{"key1":1,"key2":2,"key3":3}})_");
- } // TestComplexMapAsObject_Enum
- Y_UNIT_TEST(TestComplexMapAsObject_EnumString) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableEnum();
- items["key1"] = EEnum::E_1;
- items["key2"] = EEnum::E_2;
- items["key3"] = EEnum::E_3;
- },
- R"_({"Enum":{"key1":"E_1","key2":"E_2","key3":"E_3"}})_");
- } // TestComplexMapAsObject_EnumString
- Y_UNIT_TEST(TestComplexMapAsObject_EnumStringCaseInsensetive) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableEnum();
- items["key1"] = EEnum::E_1;
- items["key2"] = EEnum::E_2;
- items["key3"] = EEnum::E_3;
- },
- R"_({"Enum":{"key1":"e_1","key2":"E_2","key3":"e_3"}})_",
- TJson2ProtoConfig()
- .SetMapAsObject(true)
- .SetEnumValueMode(NProtobufJson::TJson2ProtoConfig::EnumCaseInsensetive)
- );
- } // TestComplexMapAsObject_EnumStringCaseInsensetive
- Y_UNIT_TEST(TestComplexMapAsObject_EnumStringSnakeCaseInsensitive) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableEnum();
- items["key1"] = EEnum::E_1;
- items["key2"] = EEnum::E_2;
- items["key3"] = EEnum::E_3;
- },
- R"_({"Enum":{"key1":"e1","key2":"_E_2_","key3":"e_3"}})_",
- TJson2ProtoConfig()
- .SetMapAsObject(true)
- .SetEnumValueMode(NProtobufJson::TJson2ProtoConfig::EnumSnakeCaseInsensitive)
- );
- } // TestComplexMapAsObject_EnumStringCaseInsensetive
- Y_UNIT_TEST(TestComplexMapAsObject_Float) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableFloat();
- items["key1"] = 0.1f;
- items["key2"] = 0.2f;
- items["key3"] = 0.3f;
- },
- R"_({"Float":{"key1":0.1,"key2":0.2,"key3":0.3}})_");
- } // TestComplexMapAsObject_Float
- Y_UNIT_TEST(TestComplexMapAsObject_Double) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- auto& items = *proto.MutableDouble();
- items["key1"] = 0.1L;
- items["key2"] = 0.2L;
- items["key3"] = 0.3L;
- },
- R"_({"Double":{"key1":0.1,"key2":0.2,"key3":0.3}})_");
- } // TestComplexMapAsObject_Double
- Y_UNIT_TEST(TestComplexMapAsObject_Nested) {
- TestComplexMapAsObject(
- [](TComplexMapType& proto) {
- TComplexMapType inner;
- auto& innerItems = *inner.MutableString();
- innerItems["key"] = "value";
- auto& items = *proto.MutableNested();
- items["key1"] = inner;
- items["key2"] = inner;
- items["key3"] = inner;
- },
- R"_({"Nested":{"key1":{"String":{"key":"value"}},"key2":{"String":{"key":"value"}},"key3":{"String":{"key":"value"}}}})_");
- } // TestComplexMapAsObject_Nested
- Y_UNIT_TEST(TestMapAsObjectConfigNotSet) {
- TString modelStr(R"_({"Items":{"key":"value"}})_");
- TJson2ProtoConfig config;
- UNIT_ASSERT_EXCEPTION_CONTAINS(
- Json2Proto<TMapType>(modelStr, config), yexception,
- "Map as object representation is not allowed");
- } // TestMapAsObjectNotSet
- Y_UNIT_TEST(TestMergeFlatOptional) {
- const NJson::TJsonValue& json = CreateFlatJson();
- NJson::TJsonValue patch;
- patch["I32"] = 5;
- patch["Bool"] = false;
- patch["String"] = "abacaba";
- patch["Double"] = 0.123;
- TFlatOptional proto;
- UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
- UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto));
- TFlatRequired modelProto;
- FillFlatProto(&modelProto);
- modelProto.SetI32(5);
- modelProto.SetBool(false);
- modelProto.SetString("abacaba");
- modelProto.SetDouble(0.123);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- } // TestMergeFlatOptional
- Y_UNIT_TEST(TestMergeFlatRequired) {
- const NJson::TJsonValue& json = CreateFlatJson();
- NJson::TJsonValue patch;
- patch["I32"] = 5;
- patch["Bool"] = false;
- patch["String"] = "abacaba";
- patch["Double"] = 0.123;
- TFlatRequired proto;
- UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
- UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto));
- TFlatRequired modelProto;
- FillFlatProto(&modelProto);
- modelProto.SetI32(5);
- modelProto.SetBool(false);
- modelProto.SetString("abacaba");
- modelProto.SetDouble(0.123);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- } // TestMergeFlatRequired
- Y_UNIT_TEST(TestMergeComposite) {
- const NJson::TJsonValue& json = CreateCompositeJson();
- NJson::TJsonValue patch;
- patch["Part"]["I32"] = 5;
- patch["Part"]["Bool"] = false;
- patch["Part"]["String"] = "abacaba";
- patch["Part"]["Double"] = 0.123;
- TCompositeOptional proto;
- UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
- UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto));
- TCompositeOptional modelProto;
- FillCompositeProto(&modelProto);
- modelProto.MutablePart()->SetI32(5);
- modelProto.MutablePart()->SetBool(false);
- modelProto.MutablePart()->SetString("abacaba");
- modelProto.MutablePart()->SetDouble(0.123);
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- } // TestMergeComposite
- Y_UNIT_TEST(TestMergeRepeatedReplace) {
- const NJson::TJsonValue& json = CreateRepeatedFlatJson();
- NJson::TJsonValue patch;
- patch["I32"].AppendValue(5);
- patch["I32"].AppendValue(6);
- patch["String"].AppendValue("abacaba");
- TFlatRepeated proto;
- TJson2ProtoConfig config;
- config.ReplaceRepeatedFields = true;
- UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
- UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto, config));
- TFlatRepeated modelProto;
- FillRepeatedProto(&modelProto);
- modelProto.ClearI32();
- modelProto.AddI32(5);
- modelProto.AddI32(6);
- modelProto.ClearString();
- modelProto.AddString("abacaba");
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- } // TestMergeRepeatedReplace
- Y_UNIT_TEST(TestMergeRepeatedAppend) {
- const NJson::TJsonValue& json = CreateRepeatedFlatJson();
- NJson::TJsonValue patch;
- patch["I32"].AppendValue(5);
- patch["I32"].AppendValue(6);
- patch["String"].AppendValue("abacaba");
- TFlatRepeated proto;
- UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
- UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto));
- TFlatRepeated modelProto;
- FillRepeatedProto(&modelProto);
- modelProto.AddI32(5);
- modelProto.AddI32(6);
- modelProto.AddString("abacaba");
- UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
- } // TestMergeRepeatedAppend
- Y_UNIT_TEST(TestEmptyStringForCastFromString) {
- NJson::TJsonValue json;
- json["I32"] = "";
- json["Bool"] = "";
- json["OneString"] = "";
- TJson2ProtoConfig config;
- config.SetCastFromString(true);
- config.SetDoNotCastEmptyStrings(true);
- TFlatOptional proto;
- UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto, config));
- UNIT_ASSERT(!proto.HasBool());
- UNIT_ASSERT(!proto.HasI32());
- UNIT_ASSERT(proto.HasOneString());
- UNIT_ASSERT_EQUAL("", proto.GetOneString());
- } // TestEmptyStringForCastFromString
- Y_UNIT_TEST(TestAllowComments) {
- constexpr TStringBuf json = R"(
- {
- "I32": 4, // comment1
- /*
- comment2
- {}
- qwer
- */
- "I64": 3423
- }
- )";
- TJson2ProtoConfig config;
- TFlatOptional proto;
- UNIT_ASSERT_EXCEPTION_CONTAINS(Json2Proto(json, proto, config), yexception, "Error: Missing a name for object member");
- config.SetAllowComments(true);
- UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto, config));
- UNIT_ASSERT_VALUES_EQUAL(proto.GetI32(), 4);
- UNIT_ASSERT_VALUES_EQUAL(proto.GetI64(), 3423);
- proto = TFlatOptional();
- UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(json, config));
- UNIT_ASSERT_VALUES_EQUAL(proto.GetI32(), 4);
- UNIT_ASSERT_VALUES_EQUAL(proto.GetI64(), 3423);
- } // TestAllowComments
- Y_UNIT_TEST(TestSimplifiedDuration) {
- NJson::TJsonValue json;
- TSingleDuration simpleDuration;
- json["Duration"] = "10.1s";
- NProtobufJson::Json2Proto(json, simpleDuration, NProtobufJson::TJson2ProtoConfig().SetAllowString2TimeConversion(true));
- UNIT_ASSERT_EQUAL(NProtoInterop::CastFromProto(simpleDuration.GetDuration()), TDuration::MilliSeconds(10100));
- } // TestSimplifiedDuration
- Y_UNIT_TEST(TestUnwrappedDuration) {
- NJson::TJsonValue json;
- TSingleDuration duration;
- json["Duration"]["seconds"] = 2;
- NProtobufJson::Json2Proto(json, duration, NProtobufJson::TJson2ProtoConfig());
- UNIT_ASSERT_EQUAL(NProtoInterop::CastFromProto(duration.GetDuration()), TDuration::MilliSeconds(2000));
- } // TestUnwrappedDuration
- Y_UNIT_TEST(TestSimplifiedTimestamp) {
- NJson::TJsonValue json;
- TSingleTimestamp simpleTimestamp;
- json["Timestamp"] = "2014-08-26T15:52:15Z";
- NProtobufJson::Json2Proto(json, simpleTimestamp, NProtobufJson::TJson2ProtoConfig().SetAllowString2TimeConversion(true));
- UNIT_ASSERT_EQUAL(NProtoInterop::CastFromProto(simpleTimestamp.GetTimestamp()), TInstant::ParseIso8601("2014-08-26T15:52:15Z"));
- } // TestSimplifiedTimestamp
- } // TJson2ProtoTest
|