#include "simple_reflection.h" #include #include #include using namespace NProtoBuf; Y_UNIT_TEST_SUITE(ProtobufSimpleReflection) { static TSample GenSampleForMergeFrom() { TSample smf; smf.SetOneStr("one str"); smf.MutableOneMsg()->AddRepInt(1); smf.AddRepMsg()->AddRepInt(2); smf.AddRepMsg()->AddRepInt(3); smf.AddRepStr("one rep str"); smf.AddRepStr("two rep str"); smf.SetAnotherOneStr("another one str"); return smf; } Y_UNIT_TEST(MergeFromGeneric) { const TSample src(GenSampleForMergeFrom()); TSample dst; const Descriptor* descr = dst.GetDescriptor(); { TMutableField dstOneStr(dst, descr->FindFieldByName("OneStr")); TConstField srcOneStr(src, descr->FindFieldByName("OneStr")); dstOneStr.MergeFrom(srcOneStr); UNIT_ASSERT_VALUES_EQUAL(dst.GetOneStr(), src.GetOneStr()); } { // MergeFrom for single message fields acts like a Message::MergeFrom TMutableField dstOneMsg(dst, descr->FindFieldByName("OneMsg")); dstOneMsg.MergeFrom(TConstField(src, descr->FindFieldByName("OneMsg"))); UNIT_ASSERT_VALUES_EQUAL(dst.GetOneMsg().RepIntSize(), src.GetOneMsg().RepIntSize()); dstOneMsg.MergeFrom(TConstField(src, descr->FindFieldByName("OneMsg"))); UNIT_ASSERT_VALUES_EQUAL(dst.GetOneMsg().RepIntSize(), src.GetOneMsg().RepIntSize() * 2); } { // MergeFrom for repeated fields acts like append TMutableField dstRepMsg(dst, descr->FindFieldByName("RepMsg")); dstRepMsg.MergeFrom(TConstField(src, descr->FindFieldByName("RepMsg"))); UNIT_ASSERT_VALUES_EQUAL(dst.RepMsgSize(), src.RepMsgSize()); dstRepMsg.MergeFrom(TConstField(src, descr->FindFieldByName("RepMsg"))); UNIT_ASSERT_VALUES_EQUAL(dst.RepMsgSize(), src.RepMsgSize() * 2); for (size_t repMsgIndex = 0; repMsgIndex < dst.RepMsgSize(); ++repMsgIndex) { UNIT_ASSERT_VALUES_EQUAL(dst.GetRepMsg(repMsgIndex).RepIntSize(), src.GetRepMsg(0).RepIntSize()); } } } Y_UNIT_TEST(MergeFromSelf) { const TSample sample(GenSampleForMergeFrom()); TSample msg(sample); const Descriptor* descr = msg.GetDescriptor(); TMutableField oneStr(msg, descr->FindFieldByName("OneStr")); oneStr.MergeFrom(oneStr); UNIT_ASSERT_VALUES_EQUAL(msg.GetOneStr(), sample.GetOneStr()); TMutableField oneMsg(msg, descr->FindFieldByName("OneMsg")); oneMsg.MergeFrom(oneMsg); // nothing should change UNIT_ASSERT_VALUES_EQUAL(msg.GetOneMsg().RepIntSize(), sample.GetOneMsg().RepIntSize()); } Y_UNIT_TEST(MergeFromAnotherFD) { const TSample sample(GenSampleForMergeFrom()); TSample msg(GenSampleForMergeFrom()); const Descriptor* descr = msg.GetDescriptor(); { // string TMutableField oneStr(msg, descr->FindFieldByName("OneStr")); TMutableField repStr(msg, descr->FindFieldByName("RepStr")); TMutableField anotherOneStr(msg, descr->FindFieldByName("AnotherOneStr")); oneStr.MergeFrom(anotherOneStr); UNIT_ASSERT_VALUES_EQUAL(msg.GetOneStr(), sample.GetAnotherOneStr()); oneStr.MergeFrom(repStr); const size_t sampleRepStrSize = sample.RepStrSize(); UNIT_ASSERT_VALUES_EQUAL(msg.GetOneStr(), sample.GetRepStr(sampleRepStrSize - 1)); repStr.MergeFrom(anotherOneStr); UNIT_ASSERT_VALUES_EQUAL(msg.RepStrSize(), sampleRepStrSize + 1); UNIT_ASSERT_VALUES_EQUAL(msg.GetRepStr(sampleRepStrSize), msg.GetAnotherOneStr()); } { // Message TMutableField oneMsg(msg, descr->FindFieldByName("OneMsg")); TMutableField repMsg(msg, descr->FindFieldByName("RepMsg")); oneMsg.MergeFrom(repMsg); const size_t oneMsgRepIntSize = sample.GetOneMsg().RepIntSize(); const size_t sizeOfAllRepIntsInRepMsg = sample.RepMsgSize(); UNIT_ASSERT_VALUES_EQUAL(msg.GetOneMsg().RepIntSize(), oneMsgRepIntSize + sizeOfAllRepIntsInRepMsg); repMsg.MergeFrom(oneMsg); UNIT_ASSERT_VALUES_EQUAL(msg.RepMsgSize(), sample.RepMsgSize() + 1); } } Y_UNIT_TEST(RemoveByIndex) { TSample msg; const Descriptor* descr = msg.GetDescriptor(); { TMutableField fld(msg, descr->FindFieldByName("RepMsg")); msg.AddRepMsg()->AddRepInt(1); msg.AddRepMsg()->AddRepInt(2); msg.AddRepMsg()->AddRepInt(3); UNIT_ASSERT_VALUES_EQUAL(3, msg.RepMsgSize()); // 1, 2, 3 fld.Remove(1); // from middle UNIT_ASSERT_VALUES_EQUAL(2, msg.RepMsgSize()); UNIT_ASSERT_VALUES_EQUAL(1, msg.GetRepMsg(0).GetRepInt(0)); UNIT_ASSERT_VALUES_EQUAL(3, msg.GetRepMsg(1).GetRepInt(0)); msg.AddRepMsg()->AddRepInt(5); UNIT_ASSERT_VALUES_EQUAL(3, msg.RepMsgSize()); // 1, 3, 5 fld.Remove(2); // from end UNIT_ASSERT_VALUES_EQUAL(2, msg.RepMsgSize()); UNIT_ASSERT_VALUES_EQUAL(1, msg.GetRepMsg(0).GetRepInt(0)); UNIT_ASSERT_VALUES_EQUAL(3, msg.GetRepMsg(1).GetRepInt(0)); msg.ClearRepMsg(); } { TMutableField fld(msg, descr->FindFieldByName("RepStr")); msg.AddRepStr("1"); msg.AddRepStr("2"); msg.AddRepStr("3"); UNIT_ASSERT_VALUES_EQUAL(3, msg.RepStrSize()); // "1", "2", "3" fld.Remove(0); // from begin UNIT_ASSERT_VALUES_EQUAL(2, msg.RepStrSize()); UNIT_ASSERT_VALUES_EQUAL("2", msg.GetRepStr(0)); UNIT_ASSERT_VALUES_EQUAL("3", msg.GetRepStr(1)); } { TMutableField fld(msg, descr->FindFieldByName("OneStr")); msg.SetOneStr("1"); UNIT_ASSERT(msg.HasOneStr()); fld.Remove(0); // not repeated UNIT_ASSERT(!msg.HasOneStr()); } } Y_UNIT_TEST(GetFieldByPath) { // Simple get by path { TSample msg; msg.SetOneStr("1"); msg.MutableOneMsg()->AddRepInt(2); msg.MutableOneMsg()->AddRepInt(3); msg.AddRepMsg()->AddRepInt(4); msg.MutableRepMsg(0)->AddRepInt(5); msg.AddRepMsg()->AddRepInt(6); { TMaybe field = TConstField::ByPath(msg, "OneStr"); UNIT_ASSERT(field); UNIT_ASSERT(field->HasValue()); UNIT_ASSERT_VALUES_EQUAL("1", (field->Get())); } { TMaybe field = TConstField::ByPath(msg, "OneMsg"); UNIT_ASSERT(field); UNIT_ASSERT(field->HasValue()); UNIT_ASSERT(field->IsMessageInstance()); } { TMaybe field = TConstField::ByPath(msg, "/OneMsg/RepInt"); UNIT_ASSERT(field); UNIT_ASSERT(field->HasValue()); UNIT_ASSERT_VALUES_EQUAL(2, field->Size()); UNIT_ASSERT_VALUES_EQUAL(2, field->Get(0)); UNIT_ASSERT_VALUES_EQUAL(3, field->Get(1)); } { TMaybe field = TConstField::ByPath(msg, "RepMsg/RepInt"); UNIT_ASSERT(field); UNIT_ASSERT(field->HasValue()); UNIT_ASSERT_VALUES_EQUAL(2, field->Size()); UNIT_ASSERT_VALUES_EQUAL(4, field->Get(0)); UNIT_ASSERT_VALUES_EQUAL(5, field->Get(1)); } } // get of unset fields { TSample msg; msg.MutableOneMsg(); { TMaybe field = TConstField::ByPath(msg, "OneStr"); UNIT_ASSERT(field); UNIT_ASSERT(!field->HasValue()); } { TMaybe field = TConstField::ByPath(msg, "OneMsg/RepInt"); UNIT_ASSERT(field); UNIT_ASSERT(!field->HasValue()); } { TMaybe field = TConstField::ByPath(msg, "RepMsg/RepInt"); UNIT_ASSERT(!field); } } // mutable { TSample msg; msg.MutableOneMsg(); { TMaybe field = TMutableField::ByPath(msg, "OneStr"); UNIT_ASSERT(field); UNIT_ASSERT(!field->HasValue()); field->Set(TString("zz")); UNIT_ASSERT(field->HasValue()); UNIT_ASSERT_VALUES_EQUAL("zz", msg.GetOneStr()); } { TMaybe field = TMutableField::ByPath(msg, "OneStr"); UNIT_ASSERT(field); UNIT_ASSERT(field->HasValue()); field->Set(TString("dd")); UNIT_ASSERT(field->HasValue()); UNIT_ASSERT_VALUES_EQUAL("dd", msg.GetOneStr()); } { TMaybe field = TMutableField::ByPath(msg, "OneMsg/RepInt"); UNIT_ASSERT(field); UNIT_ASSERT(!field->HasValue()); field->Add(10); UNIT_ASSERT_VALUES_EQUAL(10, msg.GetOneMsg().GetRepInt(0)); } { TMaybe field = TMutableField::ByPath(msg, "RepMsg/RepInt"); UNIT_ASSERT(!field); } } // mutable with path creation { TSample msg; { TMaybe field = TMutableField::ByPath(msg, "OneStr", true); UNIT_ASSERT(field); UNIT_ASSERT(!field->HasValue()); } { TMaybe field = TMutableField::ByPath(msg, "OneMsg/RepInt", true); UNIT_ASSERT(field); UNIT_ASSERT(!field->HasValue()); UNIT_ASSERT(msg.HasOneMsg()); field->Add(10); UNIT_ASSERT_VALUES_EQUAL(10, msg.GetOneMsg().GetRepInt(0)); } { TMaybe field = TMutableField::ByPath(msg, "RepMsg/RepInt", true); TMaybe fieldCopy = TMutableField::ByPath(msg, "RepMsg/RepInt", true); Y_UNUSED(fieldCopy); UNIT_ASSERT(field); UNIT_ASSERT(!field->HasValue()); UNIT_ASSERT_VALUES_EQUAL(1, msg.RepMsgSize()); field->Add(12); UNIT_ASSERT_VALUES_EQUAL(12, field->Get()); } } // error { {TSample msg; UNIT_ASSERT(!TConstField::ByPath(msg, "SomeField")); } { TSample msg; UNIT_ASSERT(!TMutableField::ByPath(msg, "SomeField/FieldSome")); } { TSample msg; UNIT_ASSERT(!TMutableField::ByPath(msg, "SomeField/FieldSome", true)); } } // extension { TSample msg; msg.SetExtension(NExt::TTestExt::ExtField, "ext"); msg.SetExtension(NExt::ExtField, 2); msg.AddExtension(NExt::Ext2Field, 33); TInnerSample* subMsg = msg.MutableExtension(NExt::SubMsgExt); subMsg->AddRepInt(20); subMsg->SetExtension(NExt::Ext3Field, 54); { TMaybe field = TConstField::ByPath(msg, "NExt.TTestExt.ExtField"); UNIT_ASSERT(field); UNIT_ASSERT(field->HasValue()); UNIT_ASSERT_VALUES_EQUAL("ext", field->Get()); } { TMaybe field = TConstField::ByPath(msg, "NExt.ExtField"); UNIT_ASSERT(field); UNIT_ASSERT(field->HasValue()); UNIT_ASSERT_VALUES_EQUAL(2, field->Get()); } { TMaybe field = TConstField::ByPath(msg, "ExtField"); // ambiguity UNIT_ASSERT(!field); } { TMaybe field = TConstField::ByPath(msg, "NExt.Ext2Field"); UNIT_ASSERT(field); UNIT_ASSERT(field->HasValue()); UNIT_ASSERT_VALUES_EQUAL(33, field->Get()); } { TMaybe field = TConstField::ByPath(msg, "Ext2Field"); UNIT_ASSERT(field); UNIT_ASSERT(field->HasValue()); UNIT_ASSERT_VALUES_EQUAL(33, field->Get()); } { TMaybe field = TConstField::ByPath(msg, "SubMsgExt"); UNIT_ASSERT(field); UNIT_ASSERT(field->HasValue()); const TInnerSample* subMsg2 = field->GetAs(); UNIT_ASSERT(subMsg2); UNIT_ASSERT_VALUES_EQUAL(1, subMsg2->RepIntSize()); UNIT_ASSERT_VALUES_EQUAL(20, subMsg2->GetRepInt(0)); UNIT_ASSERT_VALUES_EQUAL(54, subMsg2->GetExtension(NExt::Ext3Field)); } { TMaybe field = TConstField::ByPath(msg, "SubMsgExt/Ext3Field"); UNIT_ASSERT(field); UNIT_ASSERT(field->HasValue()); UNIT_ASSERT_VALUES_EQUAL(54, field->Get()); } { TMaybe field = TConstField::ByPath(msg, "SubMsgExt/RepInt"); UNIT_ASSERT(field); UNIT_ASSERT(field->HasValue()); UNIT_ASSERT_VALUES_EQUAL(20, field->Get()); } } } }