Add Cord based Parse and Serialize logic to MessageLite

PiperOrigin-RevId: 494887062
pull/11169/head
Martijn Vels 2 years ago committed by Copybara-Service
parent 5e2a4a73ed
commit ddde013bd8
  1. 363
      src/google/protobuf/lite_unittest.cc
  2. 115
      src/google/protobuf/message_lite.cc
  3. 31
      src/google/protobuf/message_lite.h

@ -32,6 +32,7 @@
#include <climits>
#include <iostream>
#include <limits>
#include <string>
#include <utility>
@ -56,6 +57,7 @@
namespace google {
namespace protobuf {
namespace {
// Helper methods to test parsing merge behavior.
void ExpectMessageMerged(const unittest::TestAllTypesLite& message) {
@ -73,13 +75,39 @@ void AssignParsingMergeMessages(unittest::TestAllTypesLite* msg1,
msg3->set_optional_string("hello");
}
// Declare and define the template `T SerializeAs()` function which we
// specialize for the typed tests serializing to a string or Cord.
template <typename T>
T SerializeAs(const MessageLite& msg);
template <>
std::string SerializeAs<std::string>(const MessageLite& msg) {
return msg.SerializeAsString();
}
template <>
absl::Cord SerializeAs<absl::Cord>(const MessageLite& msg) {
return msg.SerializeAsCord();
}
// `ParseFrom()` is overloaded for string and Cord and used in the
// typed tests parsing from string and Cord values.
bool ParseFrom(const std::string& data, MessageLite& msg) {
return msg.ParseFromString(data);
}
bool ParseFrom(const absl::Cord& data, MessageLite& msg) {
return msg.ParseFromCord(data);
}
template <typename T>
void SetAllTypesInEmptyMessageUnknownFields(
unittest::TestEmptyMessageLite* empty_message) {
protobuf_unittest::TestAllTypesLite message;
TestUtilLite::ExpectClear(message);
TestUtilLite::SetAllFields(&message);
std::string data = message.SerializeAsString();
empty_message->ParseFromString(data);
T data = SerializeAs<T>(message);
ParseFrom(data, *empty_message);
}
void SetSomeTypesInEmptyMessageUnknownFields(
@ -149,16 +177,27 @@ TEST(ParseVarintTest, Varint64) {
test_value(std::numeric_limits<uint64_t>::max(), 10);
}
TEST(Lite, AllLite1) {
std::string data;
template <typename T>
class LiteTest : public ::testing::Test {};
struct TypedTestName {
template <typename T>
static std::string GetName(int /*i*/) {
return std::is_same<T, absl::Cord>::value ? "Cord" : "String";
}
};
using SerializedDataTypes = ::testing::Types<std::string, absl::Cord>;
TYPED_TEST_SUITE(LiteTest, SerializedDataTypes, TypedTestName);
TYPED_TEST(LiteTest, AllLite1) {
{
protobuf_unittest::TestAllTypesLite message, message2, message3;
TestUtilLite::ExpectClear(message);
TestUtilLite::SetAllFields(&message);
message2.CopyFrom(message);
data = message.SerializeAsString();
message3.ParseFromString(data);
message2 = message;
TypeParam data = SerializeAs<TypeParam>(message2);
ParseFrom(data, message3);
TestUtilLite::ExpectAllFieldsSet(message);
TestUtilLite::ExpectAllFieldsSet(message2);
TestUtilLite::ExpectAllFieldsSet(message3);
@ -169,15 +208,14 @@ TEST(Lite, AllLite1) {
}
}
TEST(Lite, AllLite2) {
std::string data;
TYPED_TEST(LiteTest, AllLite2) {
{
protobuf_unittest::TestAllExtensionsLite message, message2, message3;
TestUtilLite::ExpectExtensionsClear(message);
TestUtilLite::SetAllExtensions(&message);
message2.CopyFrom(message);
std::string extensions_data = message.SerializeAsString();
message3.ParseFromString(extensions_data);
message2 = message;
TypeParam extensions_data = SerializeAs<TypeParam>(message);
ParseFrom(extensions_data, message3);
TestUtilLite::ExpectAllExtensionsSet(message);
TestUtilLite::ExpectAllExtensionsSet(message2);
TestUtilLite::ExpectAllExtensionsSet(message3);
@ -188,16 +226,16 @@ TEST(Lite, AllLite2) {
}
}
TEST(Lite, AllLite3) {
std::string data, packed_data;
TYPED_TEST(LiteTest, AllLite3) {
TypeParam data, packed_data;
{
protobuf_unittest::TestPackedTypesLite message, message2, message3;
TestUtilLite::ExpectPackedClear(message);
TestUtilLite::SetPackedFields(&message);
message2.CopyFrom(message);
packed_data = message.SerializeAsString();
message3.ParseFromString(packed_data);
message2 = message;
packed_data = SerializeAs<TypeParam>(message);
ParseFrom(packed_data, message3);
TestUtilLite::ExpectPackedFieldsSet(message);
TestUtilLite::ExpectPackedFieldsSet(message2);
TestUtilLite::ExpectPackedFieldsSet(message3);
@ -211,10 +249,10 @@ TEST(Lite, AllLite3) {
protobuf_unittest::TestPackedExtensionsLite message, message2, message3;
TestUtilLite::ExpectPackedExtensionsClear(message);
TestUtilLite::SetPackedExtensions(&message);
message2.CopyFrom(message);
std::string packed_extensions_data = message.SerializeAsString();
message2 = message;
TypeParam packed_extensions_data = SerializeAs<TypeParam>(message);
EXPECT_EQ(packed_extensions_data, packed_data);
message3.ParseFromString(packed_extensions_data);
ParseFrom(packed_extensions_data, message3);
TestUtilLite::ExpectPackedExtensionsSet(message);
TestUtilLite::ExpectPackedExtensionsSet(message2);
TestUtilLite::ExpectPackedExtensionsSet(message3);
@ -225,8 +263,8 @@ TEST(Lite, AllLite3) {
}
}
TEST(Lite, AllLite5) {
std::string data;
TYPED_TEST(LiteTest, AllLite5) {
TypeParam data;
{
// Test that if an optional or required message/group field appears multiple
@ -260,10 +298,11 @@ TEST(Lite, AllLite5) {
#undef ASSIGN_REPEATED_GROUP
std::string buffer;
generator.SerializeToString(&buffer);
TypeParam buffer;
buffer = SerializeAs<TypeParam>(generator);
// generator.SerializeToString(&buffer);
unittest::TestParsingMergeLite parsing_merge;
parsing_merge.ParseFromString(buffer);
ParseFrom(buffer, parsing_merge);
// Required and optional fields should be merged.
ExpectMessageMerged(parsing_merge.required_all_types());
@ -282,8 +321,8 @@ TEST(Lite, AllLite5) {
}
}
TEST(Lite, AllLite6) {
std::string data;
TYPED_TEST(LiteTest, AllLite6) {
TypeParam data;
// Test unknown fields support for lite messages.
{
@ -291,51 +330,48 @@ TEST(Lite, AllLite6) {
protobuf_unittest::TestEmptyMessageLite empty_message;
TestUtilLite::ExpectClear(message);
TestUtilLite::SetAllFields(&message);
data = message.SerializeAsString();
ASSERT_TRUE(empty_message.ParseFromString(data));
data.clear();
data = empty_message.SerializeAsString();
EXPECT_TRUE(message2.ParseFromString(data));
data = message2.SerializeAsString();
data = SerializeAs<TypeParam>(message);
ASSERT_TRUE(ParseFrom(data, empty_message));
data = SerializeAs<TypeParam>(empty_message);
EXPECT_TRUE(ParseFrom(data, message2));
data = SerializeAs<TypeParam>(message2);
TestUtilLite::ExpectAllFieldsSet(message2);
message.Clear();
TestUtilLite::ExpectClear(message);
}
}
TEST(Lite, AllLite7) {
std::string data;
TYPED_TEST(LiteTest, AllLite7) {
TypeParam data;
{
protobuf_unittest::TestAllExtensionsLite message, message2;
protobuf_unittest::TestEmptyMessageLite empty_message;
TestUtilLite::ExpectExtensionsClear(message);
TestUtilLite::SetAllExtensions(&message);
data = message.SerializeAsString();
empty_message.ParseFromString(data);
data.clear();
data = SerializeAs<TypeParam>(message);
ParseFrom(data, empty_message);
data = empty_message.SerializeAsString();
message2.ParseFromString(data);
data = message2.SerializeAsString();
ParseFrom(data, message2);
data = SerializeAs<TypeParam>(message2);
TestUtilLite::ExpectAllExtensionsSet(message2);
message.Clear();
TestUtilLite::ExpectExtensionsClear(message);
}
}
TEST(Lite, AllLite8) {
std::string data;
TYPED_TEST(LiteTest, AllLite8) {
TypeParam data;
{
protobuf_unittest::TestPackedTypesLite message, message2;
protobuf_unittest::TestEmptyMessageLite empty_message;
TestUtilLite::ExpectPackedClear(message);
TestUtilLite::SetPackedFields(&message);
data = message.SerializeAsString();
empty_message.ParseFromString(data);
data.clear();
data = empty_message.SerializeAsString();
message2.ParseFromString(data);
data = SerializeAs<TypeParam>(message);
ParseFrom(data, empty_message);
data = SerializeAs<TypeParam>(empty_message);
ParseFrom(data, message2);
data = message2.SerializeAsString();
TestUtilLite::ExpectPackedFieldsSet(message2);
message.Clear();
@ -343,57 +379,56 @@ TEST(Lite, AllLite8) {
}
}
TEST(Lite, AllLite9) {
std::string data;
TYPED_TEST(LiteTest, AllLite9) {
TypeParam data;
{
protobuf_unittest::TestPackedExtensionsLite message, message2;
protobuf_unittest::TestEmptyMessageLite empty_message;
TestUtilLite::ExpectPackedExtensionsClear(message);
TestUtilLite::SetPackedExtensions(&message);
data = message.SerializeAsString();
empty_message.ParseFromString(data);
data.clear();
data = empty_message.SerializeAsString();
message2.ParseFromString(data);
data = message2.SerializeAsString();
data = SerializeAs<TypeParam>(message);
ParseFrom(data, empty_message);
data = SerializeAs<TypeParam>(empty_message);
ParseFrom(data, message2);
data = SerializeAs<TypeParam>(message2);
TestUtilLite::ExpectPackedExtensionsSet(message2);
message.Clear();
TestUtilLite::ExpectPackedExtensionsClear(message);
}
}
TEST(Lite, AllLite10) {
std::string data;
TYPED_TEST(LiteTest, AllLite10) {
TypeParam data;
{
// Test Unknown fields swap
protobuf_unittest::TestEmptyMessageLite empty_message, empty_message2;
SetAllTypesInEmptyMessageUnknownFields(&empty_message);
SetAllTypesInEmptyMessageUnknownFields<TypeParam>(&empty_message);
SetSomeTypesInEmptyMessageUnknownFields(&empty_message2);
data = empty_message.SerializeAsString();
std::string data2 = empty_message2.SerializeAsString();
data = SerializeAs<TypeParam>(empty_message);
auto data2 = SerializeAs<TypeParam>(empty_message2);
empty_message.Swap(&empty_message2);
EXPECT_EQ(data, empty_message2.SerializeAsString());
EXPECT_EQ(data2, empty_message.SerializeAsString());
EXPECT_EQ(data, SerializeAs<TypeParam>(empty_message2));
EXPECT_EQ(data2, SerializeAs<TypeParam>(empty_message));
}
}
TEST(Lite, AllLite11) {
std::string data;
TYPED_TEST(LiteTest, AllLite11) {
TypeParam data;
{
// Test unknown fields swap with self
protobuf_unittest::TestEmptyMessageLite empty_message;
SetAllTypesInEmptyMessageUnknownFields(&empty_message);
data = empty_message.SerializeAsString();
SetAllTypesInEmptyMessageUnknownFields<TypeParam>(&empty_message);
data = SerializeAs<TypeParam>(empty_message);
empty_message.Swap(&empty_message);
EXPECT_EQ(data, empty_message.SerializeAsString());
}
}
TEST(Lite, AllLite12) {
std::string data;
TYPED_TEST(LiteTest, AllLite12) {
TypeParam data;
{
// Test MergeFrom with unknown fields
@ -406,24 +441,25 @@ TEST(Lite, AllLite12) {
message2.add_repeated_int64(202);
message2.set_optional_foreign_enum(unittest::FOREIGN_LITE_BAZ);
data = message.SerializeAsString();
empty_message.ParseFromString(data);
data = SerializeAs<TypeParam>(message);
ParseFrom(data, empty_message);
data = message2.SerializeAsString();
empty_message2.ParseFromString(data);
ParseFrom(data, empty_message2);
message.MergeFrom(message2);
empty_message.MergeFrom(empty_message2);
data = empty_message.SerializeAsString();
message2.ParseFromString(data);
data = SerializeAs<TypeParam>(empty_message);
ParseFrom(data, message2);
// We do not compare the serialized output of a normal message and a lite
// message because the order of fields do not match. We convert lite message
// back into normal message, then compare.
EXPECT_EQ(message.SerializeAsString(), message2.SerializeAsString());
EXPECT_EQ(SerializeAs<TypeParam>(message),
SerializeAs<TypeParam>(message2));
}
}
TEST(Lite, AllLite13) {
std::string data;
TYPED_TEST(LiteTest, AllLite13StringStream) {
TypeParam data;
{
// Test unknown enum value
@ -442,18 +478,41 @@ TEST(Lite, AllLite13) {
coded_output.WriteVarint32(20);
}
message.ParseFromString(buffer);
data = message.SerializeAsString();
data = SerializeAs<TypeParam>(message);
EXPECT_EQ(data, buffer);
}
}
TEST(Lite, AllLite14) {
std::string data;
TYPED_TEST(LiteTest, AllLite13CordStream) {
TypeParam data;
{
// Test unknown enum value
protobuf_unittest::TestAllTypesLite message;
io::CordOutputStream output_stream;
{
io::CodedOutputStream coded_output(&output_stream);
internal::WireFormatLite::WriteTag(
protobuf_unittest::TestAllTypesLite::kOptionalNestedEnumFieldNumber,
internal::WireFormatLite::WIRETYPE_VARINT, &coded_output);
coded_output.WriteVarint32(10);
internal::WireFormatLite::WriteTag(
protobuf_unittest::TestAllTypesLite::kRepeatedNestedEnumFieldNumber,
internal::WireFormatLite::WIRETYPE_VARINT, &coded_output);
coded_output.WriteVarint32(20);
}
absl::Cord buffer = output_stream.Consume();
message.ParseFromCord(buffer);
data = SerializeAs<TypeParam>(message);
EXPECT_EQ(data, buffer);
}
}
TYPED_TEST(LiteTest, AllLite14) {
{
// Test Clear with unknown fields
protobuf_unittest::TestEmptyMessageLite empty_message;
SetAllTypesInEmptyMessageUnknownFields(&empty_message);
SetAllTypesInEmptyMessageUnknownFields<TypeParam>(&empty_message);
empty_message.Clear();
EXPECT_EQ(0, empty_message.unknown_fields().size());
}
@ -461,9 +520,7 @@ TEST(Lite, AllLite14) {
// Tests for map lite =============================================
TEST(Lite, AllLite15) {
std::string data;
TEST(LiteBasicTest, AllLite15) {
{
// Accessors
protobuf_unittest::TestMapLite message;
@ -476,9 +533,7 @@ TEST(Lite, AllLite15) {
}
}
TEST(Lite, AllLite16) {
std::string data;
TYPED_TEST(LiteTest, AllLite16) {
{
// SetMapFieldsInitialized
protobuf_unittest::TestMapLite message;
@ -488,9 +543,7 @@ TEST(Lite, AllLite16) {
}
}
TEST(Lite, AllLite17) {
std::string data;
TEST(LiteBasicTest, AllLite17) {
{
// Clear
protobuf_unittest::TestMapLite message;
@ -501,9 +554,7 @@ TEST(Lite, AllLite17) {
}
}
TEST(Lite, AllLite18) {
std::string data;
TEST(LiteBasicTest, AllLite18) {
{
// ClearMessageMap
protobuf_unittest::TestMessageMapLite message;
@ -513,26 +564,22 @@ TEST(Lite, AllLite18) {
}
}
TEST(Lite, AllLite19) {
std::string data;
TEST(LiteBasicTest, AllLite19) {
{
// CopyFrom
protobuf_unittest::TestMapLite message1, message2;
MapLiteTestUtil::SetMapFields(&message1);
message2.CopyFrom(message1);
message2.CopyFrom(message1); // NOLINT
MapLiteTestUtil::ExpectMapFieldsSet(message2);
// Copying from self should be a no-op.
message2.CopyFrom(message2);
message2.CopyFrom(message2); // NOLINT
MapLiteTestUtil::ExpectMapFieldsSet(message2);
}
}
TEST(Lite, AllLite20) {
std::string data;
TEST(LiteBasicTest, AllLite20) {
{
// CopyFromMessageMap
protobuf_unittest::TestMessageMapLite message1, message2;
@ -540,7 +587,7 @@ TEST(Lite, AllLite20) {
(*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
(*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
message1.CopyFrom(message2);
message1.CopyFrom(message2); // NOLINT
// Checks repeated field is overwritten.
EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
@ -548,9 +595,7 @@ TEST(Lite, AllLite20) {
}
}
TEST(Lite, AllLite21) {
std::string data;
TEST(LiteBasicTest, AllLite21) {
{
// SwapWithEmpty
protobuf_unittest::TestMapLite message1, message2;
@ -565,9 +610,7 @@ TEST(Lite, AllLite21) {
}
}
TEST(Lite, AllLite22) {
std::string data;
TEST(LiteBasicTest, AllLite22) {
{
// SwapWithSelf
protobuf_unittest::TestMapLite message;
@ -580,9 +623,7 @@ TEST(Lite, AllLite22) {
}
}
TEST(Lite, AllLite23) {
std::string data;
TEST(LiteBasicTest, AllLite23) {
{
// SwapWithOther
protobuf_unittest::TestMapLite message1, message2;
@ -597,9 +638,7 @@ TEST(Lite, AllLite23) {
}
}
TEST(Lite, AllLite24) {
std::string data;
TEST(LiteBasicTest, AllLite24) {
{
// CopyConstructor
protobuf_unittest::TestMapLite message1;
@ -610,9 +649,7 @@ TEST(Lite, AllLite24) {
}
}
TEST(Lite, AllLite25) {
std::string data;
TEST(LiteBasicTest, AllLite25) {
{
// CopyAssignmentOperator
protobuf_unittest::TestMapLite message1;
@ -628,9 +665,7 @@ TEST(Lite, AllLite25) {
}
}
TEST(Lite, AllLite26) {
std::string data;
TEST(LiteBasicTest, AllLite26) {
{
// NonEmptyMergeFrom
protobuf_unittest::TestMapLite message1, message2;
@ -650,9 +685,7 @@ TEST(Lite, AllLite26) {
}
}
TEST(Lite, AllLite27) {
std::string data;
TYPED_TEST(LiteTest, AllLite27) {
{
// MergeFromMessageMap
protobuf_unittest::TestMessageMapLite message1, message2;
@ -668,9 +701,7 @@ TEST(Lite, AllLite27) {
}
}
TEST(Lite, AllLite28) {
std::string data;
TEST(LiteStringTest, AllLite28) {
{
// Test the generated SerializeWithCachedSizesToArray()
protobuf_unittest::TestMapLite message1, message2;
@ -686,9 +717,7 @@ TEST(Lite, AllLite28) {
}
}
TEST(Lite, AllLite29) {
std::string data;
TEST(LiteStreamTest, AllLite29) {
{
// Test the generated SerializeWithCachedSizes()
protobuf_unittest::TestMapLite message1, message2;
@ -710,9 +739,7 @@ TEST(Lite, AllLite29) {
}
TEST(Lite, AllLite32) {
std::string data;
TYPED_TEST(LiteTest, AllLite32) {
{
// Proto2UnknownEnum
protobuf_unittest::TestEnumMapPlusExtraLite from;
@ -720,21 +747,20 @@ TEST(Lite, AllLite32) {
protobuf_unittest::E_PROTO2_MAP_ENUM_FOO_LITE;
(*from.mutable_unknown_map_field())[0] =
protobuf_unittest::E_PROTO2_MAP_ENUM_EXTRA_LITE;
std::string data;
from.SerializeToString(&data);
TypeParam data;
data = SerializeAs<TypeParam>(from);
protobuf_unittest::TestEnumMapLite to;
EXPECT_TRUE(to.ParseFromString(data));
EXPECT_TRUE(ParseFrom(data, to));
EXPECT_EQ(0, to.unknown_map_field().size());
EXPECT_FALSE(to.mutable_unknown_fields()->empty());
ASSERT_EQ(1, to.known_map_field().size());
EXPECT_EQ(protobuf_unittest::PROTO2_MAP_ENUM_FOO_LITE,
to.known_map_field().at(0));
data.clear();
from.Clear();
to.SerializeToString(&data);
EXPECT_TRUE(from.ParseFromString(data));
data = SerializeAs<TypeParam>(to);
EXPECT_TRUE(ParseFrom(data, from));
ASSERT_EQ(1, from.known_map_field().size());
EXPECT_EQ(protobuf_unittest::E_PROTO2_MAP_ENUM_FOO_LITE,
from.known_map_field().at(0));
@ -744,9 +770,7 @@ TEST(Lite, AllLite32) {
}
}
TEST(Lite, AllLite33) {
std::string data;
TYPED_TEST(LiteTest, AllLite33) {
{
// StandardWireFormat
protobuf_unittest::TestMapLite message;
@ -758,9 +782,7 @@ TEST(Lite, AllLite33) {
}
}
TEST(Lite, AllLite34) {
std::string data;
TYPED_TEST(LiteTest, AllLite34) {
{
// UnorderedWireFormat
protobuf_unittest::TestMapLite message;
@ -776,7 +798,7 @@ TEST(Lite, AllLite34) {
}
}
TEST(Lite, AllLite35) {
TYPED_TEST(LiteTest, AllLite35) {
std::string data;
{
@ -792,7 +814,7 @@ TEST(Lite, AllLite35) {
}
}
TEST(Lite, AllLite36) {
TYPED_TEST(LiteTest, AllLite36) {
std::string data;
{
@ -808,9 +830,7 @@ TEST(Lite, AllLite36) {
}
}
TEST(Lite, AllLite37) {
std::string data;
TYPED_TEST(LiteTest, AllLite37) {
{
// MissedKeyWireFormat
protobuf_unittest::TestMapLite message;
@ -826,7 +846,7 @@ TEST(Lite, AllLite37) {
}
}
TEST(Lite, AllLite38) {
TYPED_TEST(LiteTest, AllLite38) {
std::string data;
{
@ -844,9 +864,7 @@ TEST(Lite, AllLite38) {
}
}
TEST(Lite, AllLite39) {
std::string data;
TYPED_TEST(LiteTest, AllLite39) {
{
// UnknownFieldWireFormat
protobuf_unittest::TestMapLite message;
@ -860,9 +878,7 @@ TEST(Lite, AllLite39) {
}
}
TEST(Lite, AllLite40) {
std::string data;
TYPED_TEST(LiteTest, AllLite40) {
{
// CorruptedWireFormat
protobuf_unittest::TestMapLite message;
@ -874,9 +890,7 @@ TEST(Lite, AllLite40) {
}
}
TEST(Lite, AllLite41) {
std::string data;
TYPED_TEST(LiteTest, AllLite41) {
{
// IsInitialized
protobuf_unittest::TestRequiredMessageMapLite map_message;
@ -893,9 +907,7 @@ TEST(Lite, AllLite41) {
}
}
TEST(Lite, AllLite42) {
std::string data;
TYPED_TEST(LiteTest, AllLite42) {
{
// Check that adding more values to enum does not corrupt message
// when passed through an old client.
@ -926,7 +938,7 @@ TEST(Lite, AllLite42) {
// Test that when parsing a oneof, we can successfully clear whatever already
// happened to be stored in the oneof.
TEST(Lite, AllLite43) {
TYPED_TEST(LiteTest, AllLite43) {
protobuf_unittest::TestOneofParsingLite message1;
message1.set_oneof_int32(17);
@ -970,7 +982,7 @@ TEST(Lite, AllLite43) {
// Verify that we can successfully parse fields of various types within oneof
// fields. We also verify that we can parse the same data twice into the same
// message.
TEST(Lite, AllLite44) {
TYPED_TEST(LiteTest, AllLite44) {
// Int32
{
protobuf_unittest::TestOneofParsingLite original;
@ -1054,7 +1066,7 @@ TEST(Lite, AllLite44) {
std::cout << "PASS" << std::endl;
}
TEST(Lite, AllLite45) {
TYPED_TEST(LiteTest, AllLite45) {
// Test unknown fields are not discarded upon parsing.
std::string data = "\20\1"; // varint 1 with field number 2
@ -1076,7 +1088,7 @@ TEST(Lite, AllLite45) {
// unpacked) state we expect. These tests specifically check for that issue by
// making sure we can parse repeated fields when the tag is higher than we would
// expect.
TEST(Lite, AllLite46) {
TYPED_TEST(LiteTest, AllLite46) {
protobuf_unittest::PackedInt32 packed;
packed.add_repeated_int32(42);
std::string serialized;
@ -1088,7 +1100,7 @@ TEST(Lite, AllLite46) {
EXPECT_EQ(42, non_packed.repeated_int32(0));
}
TEST(Lite, AllLite47) {
TYPED_TEST(LiteTest, AllLite47) {
protobuf_unittest::NonPackedFixed32 non_packed;
non_packed.add_repeated_fixed32(42);
std::string serialized;
@ -1100,7 +1112,7 @@ TEST(Lite, AllLite47) {
EXPECT_EQ(42, packed.repeated_fixed32(0));
}
TEST(Lite, MapCrash) {
TYPED_TEST(LiteTest, MapCrash) {
// See b/113635730
Arena arena;
auto msg = Arena::CreateMessage<protobuf_unittest::TestMapLite>(&arena);
@ -1114,7 +1126,7 @@ TEST(Lite, MapCrash) {
"\202\1\15\10\1\200\200\200\200\200\200\200\200\200\200\1"));
}
TEST(Lite, CorrectEnding) {
TYPED_TEST(LiteTest, CorrectEnding) {
protobuf_unittest::TestAllTypesLite msg;
{
// All proto wireformat parsers should act the same on parsing data in as
@ -1144,7 +1156,7 @@ TEST(Lite, CorrectEnding) {
}
}
TEST(Lite, DebugString) {
TYPED_TEST(LiteTest, DebugString) {
protobuf_unittest::TestAllTypesLite message1, message2;
EXPECT_TRUE(absl::StartsWith(message1.DebugString(), "MessageLite at 0x"));
EXPECT_TRUE(absl::StartsWith(message2.DebugString(), "MessageLite at 0x"));
@ -1159,7 +1171,7 @@ TEST(Lite, DebugString) {
EXPECT_NE(message1.DebugString(), message2.DebugString());
}
TEST(Lite, EnumValueToName) {
TYPED_TEST(LiteTest, EnumValueToName) {
EXPECT_EQ("FOREIGN_LITE_FOO", protobuf_unittest::ForeignEnumLite_Name(
protobuf_unittest::FOREIGN_LITE_FOO));
EXPECT_EQ("FOREIGN_LITE_BAR", protobuf_unittest::ForeignEnumLite_Name(
@ -1170,7 +1182,7 @@ TEST(Lite, EnumValueToName) {
EXPECT_EQ("", protobuf_unittest::ForeignEnumLite_Name(999));
}
TEST(Lite, NestedEnumValueToName) {
TYPED_TEST(LiteTest, NestedEnumValueToName) {
EXPECT_EQ("FOO", protobuf_unittest::TestAllTypesLite::NestedEnum_Name(
protobuf_unittest::TestAllTypesLite::FOO));
EXPECT_EQ("BAR", protobuf_unittest::TestAllTypesLite::NestedEnum_Name(
@ -1181,7 +1193,7 @@ TEST(Lite, NestedEnumValueToName) {
EXPECT_EQ("", protobuf_unittest::TestAllTypesLite::NestedEnum_Name(999));
}
TEST(Lite, EnumNameToValue) {
TYPED_TEST(LiteTest, EnumNameToValue) {
protobuf_unittest::ForeignEnumLite value;
ASSERT_TRUE(
@ -1203,7 +1215,7 @@ TEST(Lite, EnumNameToValue) {
EXPECT_FALSE(protobuf_unittest::ForeignEnumLite_Parse("G", &value));
}
TEST(Lite, NestedEnumNameToValue) {
TYPED_TEST(LiteTest, NestedEnumNameToValue) {
protobuf_unittest::TestAllTypesLite::NestedEnum value;
ASSERT_TRUE(
@ -1227,7 +1239,7 @@ TEST(Lite, NestedEnumNameToValue) {
protobuf_unittest::TestAllTypesLite::NestedEnum_Parse("G", &value));
}
TEST(Lite, AliasedEnum) {
TYPED_TEST(LiteTest, AliasedEnum) {
// Enums with allow_alias = true can have multiple entries with the same
// value.
EXPECT_EQ("FOO1", protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Name(
@ -1254,7 +1266,7 @@ TEST(Lite, AliasedEnum) {
}
TEST(Lite, CodedInputStreamRollback) {
TEST(LiteBasicTest, CodedInputStreamRollback) {
{
protobuf_unittest::TestAllTypesLite m;
m.set_optional_bytes(std::string(30, 'a'));
@ -1332,5 +1344,6 @@ TEST(Lite, CodedInputStreamRollback) {
}
}
} // namespace
} // namespace protobuf
} // namespace google

@ -36,6 +36,7 @@
#include "google/protobuf/message_lite.h"
#include <climits>
#include <cstddef>
#include <cstdint>
#include <istream>
#include <ostream>
@ -47,10 +48,12 @@
#include "google/protobuf/stubs/logging.h"
#include "google/protobuf/stubs/logging.h"
#include "absl/strings/cord.h"
#include "absl/strings/cord_buffer.h"
#include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/types/optional.h"
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
@ -200,6 +203,9 @@ class ZeroCopyCodedInputStream : public io::ZeroCopyInputStream {
bool aliasing_enabled() { return cis_->aliasing_enabled_; }
bool ReadCord(absl::Cord* cord, int count) final {
return cis_->ReadCord(cord, count);
}
private:
io::CodedInputStream* cis_;
};
@ -317,6 +323,43 @@ bool MessageLite::MergeFromString(absl::string_view data) {
}
namespace internal {
template <>
struct SourceWrapper<absl::Cord> {
explicit SourceWrapper(const absl::Cord* c) : cord(c) {}
template <bool alias>
bool MergeInto(MessageLite* msg, MessageLite::ParseFlags parse_flags) const {
absl::optional<absl::string_view> flat = cord->TryFlat();
if (flat && flat->size() <= ParseContext::kMaxCordBytesToCopy) {
return MergeFromImpl<alias>(*flat, msg, parse_flags);
} else {
io::CordInputStream input(cord);
return MergeFromImpl<alias>(&input, msg, parse_flags);
}
}
const absl::Cord* const cord;
};
} // namespace internal
bool MessageLite::MergeFromCord(const absl::Cord& cord) {
return ParseFrom<kMerge>(internal::SourceWrapper<absl::Cord>(&cord));
}
bool MessageLite::MergePartialFromCord(const absl::Cord& cord) {
return ParseFrom<kMergePartial>(internal::SourceWrapper<absl::Cord>(&cord));
}
bool MessageLite::ParseFromCord(const absl::Cord& cord) {
return ParseFrom<kParse>(internal::SourceWrapper<absl::Cord>(&cord));
}
bool MessageLite::ParsePartialFromCord(const absl::Cord& cord) {
return ParseFrom<kParsePartial>(internal::SourceWrapper<absl::Cord>(&cord));
}
// ===================================================================
inline uint8_t* SerializeToArrayImpl(const MessageLite& msg, uint8_t* target,
@ -498,6 +541,78 @@ std::string MessageLite::SerializePartialAsString() const {
return output;
}
bool MessageLite::AppendToCord(absl::Cord* output) const {
GOOGLE_ABSL_DCHECK(IsInitialized())
<< InitializationErrorMessage("serialize", *this);
return AppendPartialToCord(output);
}
bool MessageLite::AppendPartialToCord(absl::Cord* output) const {
// For efficiency, we'd like to pass a size hint to CordOutputStream with
// the exact total size expected.
const size_t size = ByteSizeLong();
const size_t total_size = size + output->size();
if (size > INT_MAX) {
GOOGLE_ABSL_LOG(ERROR) << "Exceeded maximum protobuf size of 2GB.";
return false;
}
// Allocate a CordBuffer (which may utilize private capacity in 'output').
absl::CordBuffer buffer = output->GetAppendBuffer(size);
absl::Span<char> available = buffer.available();
auto target = reinterpret_cast<uint8_t*>(available.data());
if (available.size() >= size) {
// Use EpsCopyOutputStream with full available capacity, as serialization
// may in the future use the extra slop bytes if available.
io::EpsCopyOutputStream out(
target, static_cast<int>(available.size()),
io::CodedOutputStream::IsDefaultSerializationDeterministic());
auto res = _InternalSerialize(target, &out);
GOOGLE_ABSL_DCHECK_EQ(res, target + size);
buffer.IncreaseLengthBy(size);
output->Append(std::move(buffer));
GOOGLE_ABSL_DCHECK_EQ(output->size(), total_size);
return true;
}
// Donate the buffer to the CordOutputStream with length := capacity.
// This follows the eager `EpsCopyOutputStream` initialization logic.
buffer.SetLength(buffer.capacity());
io::CordOutputStream output_stream(std::move(*output), std::move(buffer),
total_size);
io::EpsCopyOutputStream out(
target, static_cast<int>(available.size()), &output_stream,
io::CodedOutputStream::IsDefaultSerializationDeterministic(), &target);
target = _InternalSerialize(target, &out);
out.Trim(target);
if (out.HadError()) return false;
*output = output_stream.Consume();
GOOGLE_ABSL_DCHECK_EQ(output->size(), total_size);
return true;
}
bool MessageLite::SerializeToCord(absl::Cord* output) const {
output->Clear();
return AppendToCord(output);
}
bool MessageLite::SerializePartialToCord(absl::Cord* output) const {
output->Clear();
return AppendPartialToCord(output);
}
absl::Cord MessageLite::SerializeAsCord() const {
absl::Cord output;
if (!AppendToCord(&output)) output.Clear();
return output;
}
absl::Cord MessageLite::SerializePartialAsCord() const {
absl::Cord output;
if (!AppendPartialToCord(&output)) output.Clear();
return output;
}
namespace internal {

@ -49,6 +49,7 @@
#include "google/protobuf/port.h"
#include "absl/base/call_once.h"
#include "google/protobuf/stubs/logging.h"
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/explicitly_constructed.h"
#include "google/protobuf/io/coded_stream.h"
@ -371,6 +372,36 @@ class PROTOBUF_EXPORT MessageLite {
// Like AppendToString(), but allows missing required fields.
bool AppendPartialToString(std::string* output) const;
// Reads a protocol buffer from a Cord and merges it into this message.
bool MergeFromCord(const absl::Cord& cord);
// Like MergeFromCord(), but accepts messages that are missing
// required fields.
bool MergePartialFromCord(const absl::Cord& cord);
// Parse a protocol buffer contained in a Cord.
PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromCord(const absl::Cord& cord);
// Like ParseFromCord(), but accepts messages that are missing
// required fields.
PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromCord(
const absl::Cord& cord);
// Serialize the message and store it in the given Cord. All required
// fields must be set.
bool SerializeToCord(absl::Cord* output) const;
// Like SerializeToCord(), but allows missing required fields.
bool SerializePartialToCord(absl::Cord* output) const;
// Make a Cord encoding the message. Is equivalent to calling
// SerializeToCord() on a Cord and using that. Returns an empty
// Cord if SerializeToCord() would have returned an error.
absl::Cord SerializeAsCord() const;
// Like SerializeAsCord(), but allows missing required fields.
absl::Cord SerializePartialAsCord() const;
// Like SerializeToCord(), but appends to the data to the Cord's existing
// contents. All required fields must be set.
bool AppendToCord(absl::Cord* output) const;
// Like AppendToCord(), but allows missing required fields.
bool AppendPartialToCord(absl::Cord* output) const;
// Computes the serialized size of the message. This recursively calls
// ByteSizeLong() on all embedded messages.

Loading…
Cancel
Save