@ -61,6 +61,7 @@
#include "absl/strings/substitute.h"
#include "google/protobuf/arena.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/dynamic_message.h"
#include "google/protobuf/generated_message_reflection.h"
#include "google/protobuf/generated_message_tctable_impl.h"
#include "google/protobuf/io/coded_stream.h"
@ -1310,18 +1311,62 @@ std::string EncodeOverlongEnum(int number, bool use_packed) {
}
}
std::string EncodeInt32Value(int number, int32_t value,
int non_canonical_bytes) {
uint8_t buf[100];
uint8_t* p = buf;
p = internal::WireFormatLite::WriteInt32ToArray(number, value, p);
p = AddNonCanonicalBytes(SkipTag(buf), p, non_canonical_bytes);
return std::string(buf, p);
}
std::string EncodeInt64Value(int number, int64_t value, int non_canonical_bytes,
bool use_packed = false) {
uint8_t buf[100];
uint8_t* p = buf;
if (use_packed) {
p = internal::WireFormatLite::WriteInt64NoTagToArray(value, p);
p = AddNonCanonicalBytes(buf, p, non_canonical_bytes);
std::string payload(buf, p);
p = buf;
p = internal::WireFormatLite::WriteStringToArray(number, payload, p);
return std::string(buf, p);
} else {
p = internal::WireFormatLite::WriteInt64ToArray(number, value, p);
p = AddNonCanonicalBytes(SkipTag(buf), p, non_canonical_bytes);
return std::string(buf, p);
}
}
std::string EncodeOtherField() {
UNITTEST::EnumParseTester obj;
obj.set_other_field(1);
return obj.SerializeAsString();
}
template < typename T >
static std::vector< const FieldDescriptor * > GetFields() {
auto* descriptor = T::descriptor();
std::vector< const FieldDescriptor * > fields;
for (int i = 0; i < descriptor- > field_count(); ++i) {
fields.push_back(descriptor->field(i));
}
for (int i = 0; i < descriptor- > extension_count(); ++i) {
fields.push_back(descriptor->extension(i));
}
return fields;
}
TEST(MESSAGE_TEST_NAME, TestEnumParsers) {
UNITTEST::EnumParseTester obj;
const auto other_field = EncodeOtherField();
// Encode a boolean field for many different cases and verify that it can be
// Encode an enum field for many different cases and verify that it can be
// parsed as expected.
// There are:
// - optional/repeated/packed fields
@ -1331,6 +1376,9 @@ TEST(MESSAGE_TEST_NAME, TestEnumParsers) {
// - label combinations to trigger different parsers: sequential, small
// sequential, non-validated.
const std::vector< const FieldDescriptor * > fields =
GetFields< UNITTEST::EnumParseTester > ();
constexpr int kInvalidValue = 0x900913;
auto* ref = obj.GetReflection();
auto* descriptor = obj.descriptor();
@ -1347,8 +1395,7 @@ TEST(MESSAGE_TEST_NAME, TestEnumParsers) {
continue;
}
SCOPED_TRACE(add_garbage_bits);
for (int i = 0; i < descriptor- > field_count(); ++i) {
const auto* field = descriptor->field(i);
for (auto field : fields) {
if (field->name() == "other_field") continue;
if (!field->is_repeated() & & use_packed) continue;
SCOPED_TRACE(field->full_name());
@ -1421,6 +1468,52 @@ TEST(MESSAGE_TEST_NAME, TestEnumParsers) {
}
}
TEST(MESSAGE_TEST_NAME, TestEnumParserForUnknownEnumValue) {
DynamicMessageFactory factory;
std::unique_ptr< Message > dynamic(
factory.GetPrototype(UNITTEST::EnumParseTester::descriptor())->New());
UNITTEST::EnumParseTester non_dynamic;
// For unknown enum values, for consistency we must include the
// int32_t enum value in the unknown field set, which might not be exactly the
// same as the input.
auto* descriptor = non_dynamic.descriptor();
const std::vector< const FieldDescriptor * > fields =
GetFields< UNITTEST::EnumParseTester > ();
for (bool use_dynamic : {false, true}) {
SCOPED_TRACE(use_dynamic);
for (auto field : fields) {
if (field->name() == "other_field") continue;
SCOPED_TRACE(field->full_name());
for (bool use_packed : {false, true}) {
SCOPED_TRACE(use_packed);
if (!field->is_repeated() & & use_packed) continue;
// -2 is an invalid enum value on all the tests here.
// We will encode -2 as a positive int64 that is equivalent to
// int32_t{-2} when truncated.
constexpr int64_t minus_2_non_canonical =
static_cast< int64_t > (static_cast< uint32_t > (int32_t{-2}));
static_assert(minus_2_non_canonical != -2, "");
std::string encoded = EncodeInt64Value(
field->number(), minus_2_non_canonical, 0, use_packed);
auto& obj = use_dynamic ? *dynamic : non_dynamic;
ASSERT_TRUE(obj.ParseFromString(encoded));
auto& unknown = obj.GetReflection()->GetUnknownFields(obj);
ASSERT_EQ(unknown.field_count(), 1);
EXPECT_EQ(unknown.field(0).number(), field->number());
EXPECT_EQ(unknown.field(0).type(), unknown.field(0).TYPE_VARINT);
EXPECT_EQ(unknown.field(0).varint(), int64_t{-2});
}
}
}
}
std::string EncodeBoolValue(int number, bool value, int non_canonical_bytes) {
uint8_t buf[100];
uint8_t* p = buf;
@ -1443,6 +1536,9 @@ TEST(MESSAGE_TEST_NAME, TestBoolParsers) {
// - canonical and non-canonical encodings of the varint
// - last vs not last field
const std::vector< const FieldDescriptor * > fields =
GetFields< UNITTEST::BoolParseTester > ();
auto* ref = obj.GetReflection();
auto* descriptor = obj.descriptor();
for (bool use_tail_field : {false, true}) {
@ -1456,8 +1552,7 @@ TEST(MESSAGE_TEST_NAME, TestBoolParsers) {
continue;
}
SCOPED_TRACE(add_garbage_bits);
for (int i = 0; i < descriptor- > field_count(); ++i) {
const auto* field = descriptor->field(i);
for (auto field : fields) {
if (field->name() == "other_field") continue;
SCOPED_TRACE(field->full_name());
for (bool value : {false, true}) {
@ -1492,16 +1587,6 @@ TEST(MESSAGE_TEST_NAME, TestBoolParsers) {
}
}
std::string EncodeInt32Value(int number, int32_t value,
int non_canonical_bytes) {
uint8_t buf[100];
uint8_t* p = buf;
p = internal::WireFormatLite::WriteInt32ToArray(number, value, p);
p = AddNonCanonicalBytes(SkipTag(buf), p, non_canonical_bytes);
return std::string(buf, p);
}
TEST(MESSAGE_TEST_NAME, TestInt32Parsers) {
UNITTEST::Int32ParseTester obj;
@ -1515,6 +1600,9 @@ TEST(MESSAGE_TEST_NAME, TestInt32Parsers) {
// - canonical and non-canonical encodings of the varint
// - last vs not last field
const std::vector< const FieldDescriptor * > fields =
GetFields< UNITTEST::Int32ParseTester > ();
auto* ref = obj.GetReflection();
auto* descriptor = obj.descriptor();
for (bool use_tail_field : {false, true}) {
@ -1528,8 +1616,7 @@ TEST(MESSAGE_TEST_NAME, TestInt32Parsers) {
continue;
}
SCOPED_TRACE(add_garbage_bits);
for (int i = 0; i < descriptor- > field_count(); ++i) {
const auto* field = descriptor->field(i);
for (auto field : fields) {
if (field->name() == "other_field") continue;
SCOPED_TRACE(field->full_name());
for (int32_t value : {1, 0, -1, (std::numeric_limits< int32_t > ::min)(),
@ -1565,16 +1652,6 @@ TEST(MESSAGE_TEST_NAME, TestInt32Parsers) {
}
}
std::string EncodeInt64Value(int number, int64_t value,
int non_canonical_bytes) {
uint8_t buf[100];
uint8_t* p = buf;
p = internal::WireFormatLite::WriteInt64ToArray(number, value, p);
p = AddNonCanonicalBytes(SkipTag(buf), p, non_canonical_bytes);
return std::string(buf, p);
}
TEST(MESSAGE_TEST_NAME, TestInt64Parsers) {
UNITTEST::Int64ParseTester obj;
@ -1588,6 +1665,9 @@ TEST(MESSAGE_TEST_NAME, TestInt64Parsers) {
// - canonical and non-canonical encodings of the varint
// - last vs not last field
const std::vector< const FieldDescriptor * > fields =
GetFields< UNITTEST::Int64ParseTester > ();
auto* ref = obj.GetReflection();
auto* descriptor = obj.descriptor();
for (bool use_tail_field : {false, true}) {
@ -1601,8 +1681,7 @@ TEST(MESSAGE_TEST_NAME, TestInt64Parsers) {
continue;
}
SCOPED_TRACE(add_garbage_bits);
for (int i = 0; i < descriptor- > field_count(); ++i) {
const auto* field = descriptor->field(i);
for (auto field : fields) {
if (field->name() == "other_field") continue;
SCOPED_TRACE(field->full_name());
for (int64_t value : {int64_t{1}, int64_t{0}, int64_t{-1},
@ -1748,6 +1827,9 @@ TEST(MESSAGE_TEST_NAME, TestRepeatedStringParsers) {
const auto* const descriptor = UNITTEST::StringParseTester::descriptor();
const std::vector< const FieldDescriptor * > fields =
GetFields< UNITTEST::StringParseTester > ();
static const size_t sso_capacity = std::string().capacity();
if (sso_capacity == 0) GTEST_SKIP();
// SSO, !SSO, and off-by-one just in case
@ -1755,8 +1837,7 @@ TEST(MESSAGE_TEST_NAME, TestRepeatedStringParsers) {
{sso_capacity - 1, sso_capacity, sso_capacity + 1, sso_capacity + 2}) {
SCOPED_TRACE(size);
const std::string value = sample.substr(0, size);
for (int i = 0; i < descriptor- > field_count(); ++i) {
const auto* field = descriptor->field(i);
for (auto field : fields) {
SCOPED_TRACE(field->full_name());
const auto encoded = EncodeStringValue(field->number(), sample) +
EncodeStringValue(field->number(), value);