blob: 868f87e8152d8f2047a02bfa1bae1399acc076c0 [file]
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////
#include "tink/internal/proto_parser_message.h"
#include <array>
#include <cstddef>
#include <cstdint>
#include <string>
#include <utility>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/nullability.h"
#include "absl/crc/crc32c.h"
#include "absl/log/absl_check.h"
#include "absl/status/status.h"
#include "absl/status/status_matchers.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "tink/internal/proto_parser_enum_field.h"
#include "tink/internal/proto_parser_fields.h"
#include "tink/internal/proto_parser_options.h"
#include "tink/internal/proto_parser_secret_data_field.h"
#include "tink/internal/proto_parser_state.h"
#include "tink/internal/proto_parsing_helpers.h"
#include "tink/internal/testing/field_with_number.h"
#include "tink/secret_data.h"
#include "tink/util/secret_data.h"
#include "tink/util/test_matchers.h"
#include "tink/util/test_util.h"
ABSL_POINTERS_DEFAULT_NONNULL
namespace crypto {
namespace tink {
namespace internal {
namespace proto_parsing {
namespace {
using ::absl_testing::IsOk;
using ::crypto::tink::internal::proto_testing::FieldWithNumber;
using ::crypto::tink::test::HexDecodeOrDie;
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::HasSubstr;
using ::testing::IsFalse;
using ::testing::IsTrue;
using ::testing::Not;
using ::testing::Test;
class InnerStruct final : public Message {
public:
InnerStruct() = default;
InnerStruct(uint32_t uint32_member_1, uint32_t uint32_member_2) {
uint32_member_1_.set_value(uint32_member_1);
uint32_member_2_.set_value(uint32_member_2);
}
uint32_t uint32_member_1() const { return uint32_member_1_.value(); }
void set_uint32_member_1(uint32_t value) {
uint32_member_1_.set_value(value);
}
uint32_t uint32_member_2() const { return uint32_member_2_.value(); }
void set_uint32_member_2(uint32_t value) {
uint32_member_2_.set_value(value);
}
bool operator==(const InnerStruct& other) const {
return uint32_member_1_.value() == other.uint32_member_1_.value() &&
uint32_member_2_.value() == other.uint32_member_2_.value();
}
private:
size_t num_fields() const override { return 2; }
const Field* field(int i) const override {
return std::array<const Field*, 2>{
{&uint32_member_1_, &uint32_member_2_}}[i];
}
Uint32Field uint32_member_1_{1};
Uint32Field uint32_member_2_{2};
};
class OuterStruct : public Message {
public:
const InnerStruct& inner_member() const { return inner_member_.value(); }
InnerStruct* mutable_inner_member() { return inner_member_.mutable_value(); }
using Message::SerializeAsString;
private:
size_t num_fields() const override { return 1; }
const Field* field(int i) const override {
return std::array<const Field*, 1>{{&inner_member_}}[i];
}
MessageField<InnerStruct> inner_member_{1};
};
class OneofTestMessageTP : public Message {
public:
enum MyOneof1Case {
MY_ONEOF_1_NOT_SET = 0,
kFieldA = 1,
kFieldB = 2,
};
enum MyOneof2Case {
MY_ONEOF_2_NOT_SET = 0,
kFieldC = 3,
kFieldD = 4,
};
OneofTestMessageTP() = default;
OneofTestMessageTP(const OneofTestMessageTP&) = default;
OneofTestMessageTP& operator=(const OneofTestMessageTP&) = default;
MyOneof1Case my_oneof_1_case() const { return my_oneof_1_case_; }
MyOneof2Case my_oneof_2_case() const { return my_oneof_2_case_; }
// Oneof 1
bool has_field_a() const { return field_a_.has_value(); }
const InnerStruct& field_a() const { return field_a_.value(); }
InnerStruct* mutable_field_a() {
BeforeFieldSet(&field_a_);
return field_a_.mutable_value();
}
bool has_field_b() const { return field_b_.has_value(); }
uint32_t field_b() const { return field_b_.value(); }
void set_field_b(uint32_t val) {
BeforeFieldSet(&field_b_);
field_b_.set_value(val);
}
// Oneof 2
bool has_field_c() const { return field_c_.has_value(); }
uint32_t field_c() const { return field_c_.value(); }
void set_field_c(uint32_t val) {
BeforeFieldSet(&field_c_);
field_c_.set_value(val);
}
bool has_field_d() const { return field_d_.has_value(); }
uint32_t field_d() const { return field_d_.value(); }
void set_field_d(uint32_t val) {
BeforeFieldSet(&field_d_);
field_d_.set_value(val);
}
void Clear() override {
Message::Clear();
my_oneof_1_case_ = MY_ONEOF_1_NOT_SET;
my_oneof_2_case_ = MY_ONEOF_2_NOT_SET;
}
protected:
void BeforeFieldSet(const Field* field) override {
if (field == &field_a_ || field == &field_b_) {
MyOneof1Case parsed_case =
static_cast<MyOneof1Case>(field->FieldNumber());
if (my_oneof_1_case_ == parsed_case) {
return;
}
if (my_oneof_1_case_ == kFieldA) {
field_a_.Clear();
} else if (my_oneof_1_case_ == kFieldB) {
field_b_.Clear();
}
my_oneof_1_case_ = parsed_case;
} else if (field == &field_c_ || field == &field_d_) {
MyOneof2Case parsed_case =
static_cast<MyOneof2Case>(field->FieldNumber());
if (my_oneof_2_case_ == parsed_case) {
return;
}
if (my_oneof_2_case_ == kFieldC) {
field_c_.Clear();
} else if (my_oneof_2_case_ == kFieldD) {
field_d_.Clear();
}
my_oneof_2_case_ = parsed_case;
}
}
private:
size_t num_fields() const override { return 4; }
const Field* field(int i) const override {
return std::array<const Field*, 4>{
{&field_a_, &field_b_, &field_c_, &field_d_}}[i];
}
MessageField<InnerStruct> field_a_{1, ProtoFieldOptions::kExplicit};
Uint32Field field_b_{2, ProtoFieldOptions::kExplicit};
Uint32Field field_c_{3, ProtoFieldOptions::kExplicit};
Uint32Field field_d_{4, ProtoFieldOptions::kExplicit};
MyOneof1Case my_oneof_1_case_ = MY_ONEOF_1_NOT_SET;
MyOneof2Case my_oneof_2_case_ = MY_ONEOF_2_NOT_SET;
};
TEST(MessageTest, Clear) {
OuterStruct s;
s.mutable_inner_member()->set_uint32_member_1(123);
s.mutable_inner_member()->set_uint32_member_2(456);
s.Clear();
EXPECT_THAT(s.inner_member().uint32_member_1(), Eq(0));
EXPECT_THAT(s.inner_member().uint32_member_2(), Eq(0));
}
TEST(MessageTest, MultipleOneofsSettersEnforceMutualExclusion) {
OneofTestMessageTP msg;
// Set field in oneof_1 (submessage)
msg.mutable_field_a()->set_uint32_member_1(10);
EXPECT_TRUE(msg.has_field_a());
EXPECT_EQ(msg.field_a().uint32_member_1(), 10);
EXPECT_FALSE(msg.has_field_b());
EXPECT_EQ(msg.my_oneof_1_case(), OneofTestMessageTP::kFieldA);
// Set field in oneof_2 (should be independent)
msg.set_field_c(30);
EXPECT_TRUE(msg.has_field_a()); // oneof_1 unaffected
EXPECT_TRUE(msg.has_field_c());
EXPECT_EQ(msg.field_c(), 30);
EXPECT_FALSE(msg.has_field_d());
EXPECT_EQ(msg.my_oneof_2_case(), OneofTestMessageTP::kFieldC);
// Mutually exclude within oneof_1
msg.set_field_b(20);
EXPECT_FALSE(msg.has_field_a()); // field_a cleared
EXPECT_TRUE(msg.has_field_b());
EXPECT_EQ(msg.field_b(), 20);
EXPECT_TRUE(msg.has_field_c()); // oneof_2 still unaffected
EXPECT_EQ(msg.my_oneof_1_case(), OneofTestMessageTP::kFieldB);
// Clear resets everything
msg.Clear();
EXPECT_FALSE(msg.has_field_a());
EXPECT_FALSE(msg.has_field_b());
EXPECT_FALSE(msg.has_field_c());
EXPECT_FALSE(msg.has_field_d());
EXPECT_EQ(msg.my_oneof_1_case(), OneofTestMessageTP::MY_ONEOF_1_NOT_SET);
EXPECT_EQ(msg.my_oneof_2_case(), OneofTestMessageTP::MY_ONEOF_2_NOT_SET);
}
TEST(MessageTest, MultipleOneofsParsingEnforcesMutualExclusionLastWins) {
// Serialized:
// oneof_1: field_a (submessage with member 1 = 10), then field_b (20) ->
// field_b wins oneof_2: field_c (30), then field_d (40) -> field_d wins
std::string bytes = absl::StrCat(
FieldWithNumber(1).IsSubMessage({FieldWithNumber(1).IsVarint(10)}),
FieldWithNumber(3).IsVarint(30), FieldWithNumber(2).IsVarint(20),
FieldWithNumber(4).IsVarint(40));
OneofTestMessageTP msg;
EXPECT_TRUE(msg.ParseFromString(bytes));
// Verify oneof_1 last-writer wins
EXPECT_FALSE(msg.has_field_a());
EXPECT_TRUE(msg.has_field_b());
EXPECT_EQ(msg.field_b(), 20);
EXPECT_EQ(msg.my_oneof_1_case(), OneofTestMessageTP::kFieldB);
// Verify oneof_2 last-writer wins
EXPECT_FALSE(msg.has_field_c());
EXPECT_TRUE(msg.has_field_d());
EXPECT_EQ(msg.field_d(), 40);
EXPECT_EQ(msg.my_oneof_2_case(), OneofTestMessageTP::kFieldD);
}
TEST(MessageTest, OneofParsingMergesSameField) {
// Serialized:
// oneof_1: field_a (member 1 = 10), then field_a again (member 2 = 20)
// Since it's the same field, they should merge!
std::string bytes = absl::StrCat(
FieldWithNumber(1).IsSubMessage({FieldWithNumber(1).IsVarint(10)}),
FieldWithNumber(1).IsSubMessage({FieldWithNumber(2).IsVarint(20)}));
OneofTestMessageTP msg;
EXPECT_TRUE(msg.ParseFromString(bytes));
EXPECT_TRUE(msg.has_field_a());
EXPECT_EQ(msg.field_a().uint32_member_1(), 10);
EXPECT_EQ(msg.field_a().uint32_member_2(), 20);
EXPECT_FALSE(msg.has_field_b());
EXPECT_EQ(msg.my_oneof_1_case(), OneofTestMessageTP::kFieldA);
}
TEST(MessageTest, OneofCopyConstructorWorks) {
OneofTestMessageTP msg1;
msg1.mutable_field_a()->set_uint32_member_1(10);
msg1.set_field_c(30);
// Copy construct
OneofTestMessageTP msg2 = msg1;
EXPECT_TRUE(msg2.has_field_a());
EXPECT_EQ(msg2.field_a().uint32_member_1(), 10);
EXPECT_TRUE(msg2.has_field_c());
EXPECT_EQ(msg2.field_c(), 30);
EXPECT_EQ(msg2.my_oneof_1_case(), OneofTestMessageTP::kFieldA);
EXPECT_EQ(msg2.my_oneof_2_case(), OneofTestMessageTP::kFieldC);
// Modify copy, original should be unaffected
msg2.set_field_b(20);
EXPECT_FALSE(msg2.has_field_a());
EXPECT_TRUE(msg2.has_field_b());
EXPECT_EQ(msg2.my_oneof_1_case(), OneofTestMessageTP::kFieldB);
EXPECT_TRUE(msg1.has_field_a()); // original still has field_a!
EXPECT_FALSE(msg1.has_field_b());
EXPECT_EQ(msg1.my_oneof_1_case(), OneofTestMessageTP::kFieldA);
}
#if !defined(TINK_CPP_SECRET_DATA_IS_STD_VECTOR)
// Serializes a varint using a wrong CRC.
absl::Status SerializeVarintWrongCrc(uint64_t value,
SerializationState& output) {
const int size = VarintLength(value);
ABSL_CHECK_GE(size, output.GetBuffer().size());
absl::Span<char> output_buffer = output.GetBuffer();
int i = 0;
while (value >= 0x80) {
output_buffer[i++] = (static_cast<char>(value) & 0x7f) | 0x80;
value >>= 7;
}
output_buffer[i++] = static_cast<char>(value);
output.AdvanceWithCrc(size, absl::crc32c_t{0xAAAA});
return absl::OkStatus();
}
// A proto message with a field that serializes a varint using a wrong CRC.
//
// This is used to test that the CRC accumulated during serialization is used
// for the returned SecretData.
class Uint32FieldWrongCrc : public Field {
public:
explicit Uint32FieldWrongCrc(
uint32_t field_number,
ProtoFieldOptions options = ProtoFieldOptions::kImplicit)
: Field(field_number, WireType::kVarint), field_(field_number, options) {}
// Copyable and movable.
Uint32FieldWrongCrc(const Uint32FieldWrongCrc&) = default;
Uint32FieldWrongCrc& operator=(const Uint32FieldWrongCrc&) = default;
Uint32FieldWrongCrc(Uint32FieldWrongCrc&&) noexcept = default;
Uint32FieldWrongCrc& operator=(Uint32FieldWrongCrc&&) noexcept = default;
void Clear() override { field_.Clear(); }
bool ConsumeIntoMember(ParsingState& serialized) override {
return field_.ConsumeIntoMember(serialized);
}
bool SerializeWithTagInto(SerializationState& out) const override {
// Skip check for requires serialization.
if (!SerializeWireTypeAndFieldNumber(GetWireType(), field_.FieldNumber(),
out)) {
return false;
}
return SerializeVarintWrongCrc(field_.value(), out).ok();
}
size_t GetSerializedSizeIncludingTag() const override {
return field_.GetSerializedSizeIncludingTag();
}
void set_value(uint32_t value) { field_.set_value(value); }
uint32_t value() const { return field_.value(); }
private:
Uint32Field field_;
};
class OuterProtoClassWithWrongCrc : public Message {
public:
const InnerStruct& inner_member() const { return inner_member_.value(); }
InnerStruct* mutable_inner_member() { return inner_member_.mutable_value(); }
uint32_t uint32_member() const { return uint32_member_.value(); }
void set_uint32_member(uint32_t value) { uint32_member_.set_value(value); }
using Message::SerializeAsString;
private:
size_t num_fields() const override { return 2; }
const Field* field(int i) const override {
return std::array<const Field*, 2>{{&inner_member_, &uint32_member_}}[i];
}
MessageField<InnerStruct> inner_member_{1};
Uint32FieldWrongCrc uint32_member_{2};
};
TEST(MessageTest, SerializeAsSecretDataFails) {
OuterProtoClassWithWrongCrc s;
s.mutable_inner_member()->set_uint32_member_1(0x23);
s.mutable_inner_member()->set_uint32_member_2(0x7a);
s.set_uint32_member(0x7a);
SecretData buffer = s.SerializeAsSecretData();
EXPECT_THAT(
util::SecretDataAsStringView(buffer),
Eq(absl::StrJoin(
{FieldWithNumber(1).IsSubMessage({FieldWithNumber(1).IsVarint(0x23),
FieldWithNumber(2).IsVarint(0x7a)}),
FieldWithNumber(2).IsVarint(0x7a)},
"")));
EXPECT_THAT(buffer.ValidateCrc32c(), Not(IsOk()));
}
#endif // !defined(TINK_CPP_SECRET_DATA_IS_STD_VECTOR)
TEST(MessageTest, SerializeAsSecretDataSuccess) {
OuterStruct s;
s.mutable_inner_member()->set_uint32_member_1(0x23);
s.mutable_inner_member()->set_uint32_member_2(0x7a);
SecretData buffer = s.SerializeAsSecretData();
EXPECT_THAT(
util::SecretDataAsStringView(buffer),
Eq(FieldWithNumber(1).IsSubMessage({FieldWithNumber(1).IsVarint(0x23),
FieldWithNumber(2).IsVarint(0x7a)})));
#if !defined(TINK_CPP_SECRET_DATA_IS_STD_VECTOR)
EXPECT_THAT(buffer.ValidateCrc32c(), IsOk());
EXPECT_THAT(buffer.GetCrc32c(),
Eq(absl::ComputeCrc32c(s.SerializeAsString())));
#endif // !defined(TINK_CPP_SECRET_DATA_IS_STD_VECTOR)
}
TEST(MessageTest, SerializeAsStringSuccess) {
OuterStruct s;
s.mutable_inner_member()->set_uint32_member_1(0x23);
s.mutable_inner_member()->set_uint32_member_2(0x7a);
std::string buffer = s.SerializeAsString();
EXPECT_THAT(
buffer,
Eq(FieldWithNumber(1).IsSubMessage({FieldWithNumber(1).IsVarint(0x23),
FieldWithNumber(2).IsVarint(0x7a)})));
}
TEST(MessageTest, ParseFromStringSuccess) {
std::string bytes =
absl::StrCat(/* Size and tag */ HexDecodeOrDie("0a04"),
/* Int field, tag 1, value 0x23 */ HexDecodeOrDie("0823"),
/* Int field, tag 2, value 0x7a */ HexDecodeOrDie("107a"));
OuterStruct s;
s.Clear();
EXPECT_TRUE(s.ParseFromString(bytes));
EXPECT_THAT(s.inner_member().uint32_member_1(), Eq(0x23));
EXPECT_THAT(s.inner_member().uint32_member_2(), Eq(0x7a));
}
struct OuterMessageWithSecretData : public Message {
private:
size_t num_fields() const override { return 2; }
const Field* field(int i) const override {
return std::array<const Field*, 2>{
{&inner_member_field, &secret_data_field}}[i];
}
public:
MessageField<InnerStruct> inner_member_field{1};
SecretDataField secret_data_field{2};
};
TEST(MessageTest, ParseFromStringWithCrcSuccess) {
std::string bytes = absl::StrCat(
FieldWithNumber(1).IsSubMessage({FieldWithNumber(1).IsVarint(0x23),
FieldWithNumber(2).IsVarint(0x7a)}),
FieldWithNumber(2).IsString("secret_data"));
OuterMessageWithSecretData s;
absl::StatusOr<util::SecretValue<absl::crc32c_t>> result_crc =
s.ParseFromStringWithCrc(bytes);
ASSERT_THAT(result_crc, IsOk());
EXPECT_THAT(result_crc->value(), Eq(absl::ComputeCrc32c(bytes)));
EXPECT_THAT(s.inner_member_field.value().uint32_member_1(), Eq(0x23));
EXPECT_THAT(s.inner_member_field.value().uint32_member_2(), Eq(0x7a));
EXPECT_THAT(util::SecretDataAsStringView(s.secret_data_field.value()),
Eq("secret_data"));
#if !defined(TINK_CPP_SECRET_DATA_IS_STD_VECTOR)
EXPECT_THAT(s.secret_data_field.value().ValidateCrc32c(), IsOk());
EXPECT_THAT(s.secret_data_field.value().GetCrc32c(),
Eq(absl::ComputeCrc32c("secret_data")));
#endif // !defined(TINK_CPP_SECRET_DATA_IS_STD_VECTOR)
}
TEST(MessageTest, SerializeAndParse) {
OuterStruct s;
s.mutable_inner_member()->set_uint32_member_1(0x23);
s.mutable_inner_member()->set_uint32_member_2(0x7a);
SecretData bytes = s.SerializeAsSecretData();
#if !defined(TINK_CPP_SECRET_DATA_IS_STD_VECTOR)
EXPECT_THAT(bytes.ValidateCrc32c(), IsOk());
EXPECT_THAT(bytes.GetCrc32c(),
Eq(absl::ComputeCrc32c(s.SerializeAsString())));
#endif // !defined(TINK_CPP_SECRET_DATA_IS_STD_VECTOR)
s.Clear();
EXPECT_THAT(s.inner_member().uint32_member_1(), Eq(0));
EXPECT_THAT(s.inner_member().uint32_member_2(), Eq(0));
EXPECT_TRUE(s.ParseFromString(util::SecretDataAsStringView(bytes)));
EXPECT_THAT(s.inner_member().uint32_member_1(), Eq(0x23));
EXPECT_THAT(s.inner_member().uint32_member_2(), Eq(0x7a));
}
TEST(MessageTest, ParseFromStringFails) {
std::string bytes =
absl::StrCat(/* 4 bytes */ HexDecodeOrDie("04"),
/* Int field, tag 1, value 0x23 */ HexDecodeOrDie("0823"),
/* Int field, tag 2, value 0x7a */ HexDecodeOrDie("107a"));
bytes.resize(bytes.size() - 1); // One byte too short.
OuterStruct s;
s.Clear();
EXPECT_FALSE(s.ParseFromString(bytes));
}
// -----------------------------------------------------------------------------
// RepeatedMessageField tests.
TEST(RepeatedMessageField, ConsumeIntoMemberSuccessCases) {
RepeatedMessageField<InnerStruct> field{1};
std::string bytes = absl::StrCat(
/* 4 bytes */ HexDecodeOrDie("04"),
/* Int field, tag 1, value 0x23 */ HexDecodeOrDie("0823"),
/* Int field, tag 2, value 0x7a */ HexDecodeOrDie("107a"),
/* 2 bytes */ HexDecodeOrDie("02"),
/* Int field, tag 1, value 0x01 */ HexDecodeOrDie("0801"),
"remaining_data");
ParsingState parsing_state = ParsingState(bytes);
EXPECT_THAT(field.ConsumeIntoMember(parsing_state), IsTrue());
EXPECT_THAT(field.ConsumeIntoMember(parsing_state), IsTrue());
EXPECT_THAT(parsing_state.RemainingData(), Eq("remaining_data"));
EXPECT_THAT(field.values(),
ElementsAre(InnerStruct(0x23, 0x7a), InnerStruct(0x01, 0)));
}
TEST(RepeatedMessageField, ConsumeIntoMemberWithCrcSuccessCases) {
RepeatedMessageField<InnerStruct> field{1};
std::string bytes = absl::StrCat(
/* 4 bytes */ HexDecodeOrDie("04"),
/* Int field, tag 1, value 0x23 */ HexDecodeOrDie("0823"),
/* Int field, tag 2, value 0x7a */ HexDecodeOrDie("107a"),
/* 2 bytes */ HexDecodeOrDie("02"),
/* Int field, tag 1, value 0x01 */ HexDecodeOrDie("0801"),
"remaining_data");
absl::crc32c_t crc{};
ParsingState parsing_state = ParsingState(bytes, &crc);
EXPECT_THAT(field.ConsumeIntoMember(parsing_state), IsTrue());
EXPECT_THAT(field.ConsumeIntoMember(parsing_state), IsTrue());
EXPECT_THAT(parsing_state.RemainingData(), Eq("remaining_data"));
EXPECT_THAT(crc, Eq(absl::ComputeCrc32c(bytes.substr(0, 8))));
EXPECT_THAT(field.values(),
ElementsAre(InnerStruct(0x23, 0x7a), InnerStruct(0x01, 0)));
}
TEST(RepeatedMessageField, ConsumeIntoMemberEmptyString) {
RepeatedMessageField<InnerStruct> field{1};
std::string bytes = HexDecodeOrDie("00");
ParsingState parsing_state = ParsingState(bytes);
EXPECT_THAT(field.ConsumeIntoMember(parsing_state), IsTrue());
EXPECT_THAT(field.values(), ElementsAre(InnerStruct()));
}
TEST(RepeatedMessageField, ConsumeIntoMemberAppends) {
RepeatedMessageField<InnerStruct> field{1};
field.mutable_values()->push_back(InnerStruct(123, 456));
std::string bytes = absl::StrCat(
/* 4 bytes */ HexDecodeOrDie("04"),
/* Int field, tag 1, value 0x23 */ HexDecodeOrDie("0823"),
/* Int field, tag 2, value 0x7a */ HexDecodeOrDie("107a"),
"remaining_data");
ParsingState parsing_state = ParsingState(bytes);
EXPECT_THAT(field.ConsumeIntoMember(parsing_state), IsTrue());
EXPECT_THAT(parsing_state.RemainingData(), Eq("remaining_data"));
EXPECT_THAT(field.values(),
ElementsAre(InnerStruct(123, 456), InnerStruct(0x23, 0x7a)));
}
TEST(RepeatedMessageField, ConsumeIntoMemberVarintTooLong) {
RepeatedMessageField<InnerStruct> field{1};
std::string bytes = /* LengthDelimetedLength: */ HexDecodeOrDie("01");
ParsingState parsing_state = ParsingState(bytes);
EXPECT_THAT(field.ConsumeIntoMember(parsing_state), IsFalse());
}
TEST(RepeatedMessageField, EmptyWithoutVarint) {
RepeatedMessageField<InnerStruct> field{1};
std::string bytes = "";
ParsingState parsing_state = ParsingState(bytes);
EXPECT_THAT(field.ConsumeIntoMember(parsing_state), IsFalse());
}
TEST(RepeatedMessageField, InvalidVarint) {
RepeatedMessageField<InnerStruct> field{1};
std::string bytes = absl::StrCat(HexDecodeOrDie("808080808000"), "abcde");
ParsingState parsing_state = ParsingState(bytes);
EXPECT_THAT(field.ConsumeIntoMember(parsing_state), IsFalse());
}
TEST(RepeatedMessageField, SerializeEmpty) {
RepeatedMessageField<InnerStruct> field{1};
std::string buffer = "abc";
SerializationState state = SerializationState(absl::MakeSpan(buffer));
EXPECT_THAT(field.GetSerializedSizeIncludingTag(), Eq(0));
EXPECT_THAT(field.SerializeWithTagInto(state), IsTrue());
EXPECT_THAT(state.GetBuffer().size(), Eq(3));
EXPECT_THAT(buffer, Eq("abc"));
}
TEST(RepeatedMessageField, SerializeNonEmpty) {
RepeatedMessageField<InnerStruct> field{1};
field.mutable_values()->push_back(InnerStruct(0x23, 0x7a));
field.mutable_values()->push_back(InnerStruct());
field.mutable_values()->back().set_uint32_member_1((0x01));
std::string buffer = "BUFFERBUFFERBUFFERBUFFERBUFFERBUFFER";
SerializationState state = SerializationState(absl::MakeSpan(buffer));
EXPECT_THAT(field.GetSerializedSizeIncludingTag(), Eq(10));
EXPECT_THAT(field.SerializeWithTagInto(state), IsTrue());
EXPECT_THAT(state.GetBuffer().size(), Eq(buffer.size() - 10));
EXPECT_THAT(&(state.GetBuffer())[0], Eq(&buffer[10]));
EXPECT_THAT(buffer.substr(0, 10),
Eq(absl::StrCat(FieldWithNumber(1).IsSubMessage(
{FieldWithNumber(1).IsVarint(0x23),
FieldWithNumber(2).IsVarint(0x7a)}),
FieldWithNumber(1).IsSubMessage(
{FieldWithNumber(1).IsVarint(0x01)}))));
// Rest is untouched
EXPECT_THAT(buffer.substr(10), Eq("ERBUFFERBUFFERBUFFERBUFFER"));
}
TEST(RepeatedMessageField, SerializeNonEmptyWithEmptyInnerStruct) {
RepeatedMessageField<InnerStruct> field{1};
field.mutable_values()->push_back(InnerStruct());
std::string buffer = "BUFFER";
SerializationState state = SerializationState(absl::MakeSpan(buffer));
// Tag (1 << 3 | 2) = 0x0a, Length = 0x00. Total 2 bytes.
EXPECT_THAT(field.GetSerializedSizeIncludingTag(), Eq(2));
EXPECT_THAT(field.SerializeWithTagInto(state), IsTrue());
EXPECT_THAT(state.GetBuffer().size(), Eq(buffer.size() - 2));
EXPECT_THAT(&(state.GetBuffer())[0], Eq(&buffer[2]));
EXPECT_THAT(buffer.substr(0, 2), Eq(HexDecodeOrDie("0a00")));
// Rest is untouched
EXPECT_THAT(buffer.substr(2), Eq("FFER"));
}
TEST(RepeatedMessageField, SerializeTooSmallBuffer) {
RepeatedMessageField<InnerStruct> field{1};
field.mutable_values()->push_back(InnerStruct(0x23, 0x7a));
std::string buffer = "BUFFE";
SerializationState state = SerializationState(absl::MakeSpan(buffer));
EXPECT_THAT(field.SerializeWithTagInto(state), IsFalse());
}
TEST(RepeatedMessageField, SerializeSmallerBuffer) {
RepeatedMessageField<InnerStruct> field{1};
field.mutable_values()->push_back(InnerStruct(0x23, 0x7a));
std::string buffer = "B";
SerializationState state = SerializationState(absl::MakeSpan(buffer));
EXPECT_THAT(field.SerializeWithTagInto(state), IsFalse());
}
TEST(RepeatedMessageField, SerializeVerySmallBuffer) {
RepeatedMessageField<InnerStruct> field{1};
field.mutable_values()->push_back(InnerStruct(0x23, 0x7a));
std::string buffer;
SerializationState state = SerializationState(absl::MakeSpan(buffer));
EXPECT_THAT(field.SerializeWithTagInto(state), IsFalse());
}
TEST(RepeatedMessageField, Accessors) {
RepeatedMessageField<InnerStruct> field{1};
EXPECT_EQ(field.values_size(), 0);
InnerStruct* v1 = field.add_values();
v1->set_uint32_member_1(1);
EXPECT_EQ(field.values_size(), 1);
EXPECT_EQ(field.values(0).uint32_member_1(), 1);
EXPECT_EQ(v1, field.mutable_values(0));
field.mutable_values(0)->set_uint32_member_1(2);
EXPECT_EQ(field.values(0).uint32_member_1(), 2);
InnerStruct* v2 = field.add_values();
v2->set_uint32_member_1(3);
v2->set_uint32_member_2(4);
EXPECT_EQ(field.values_size(), 2);
EXPECT_EQ(field.values(1).uint32_member_1(), 3);
EXPECT_EQ(field.values(1).uint32_member_2(), 4);
EXPECT_EQ(field.values().size(), 2);
EXPECT_EQ(field.mutable_values()->size(), 2);
field.mutable_values()->back().set_uint32_member_1(5);
EXPECT_EQ(field.values(1).uint32_member_1(), 5);
EXPECT_EQ(field.values(1).uint32_member_2(), 4);
}
// -----------------------------------------------------------------------------
// MessageField tests.
class Submessage : public Message {
public:
Submessage() = default;
uint32_t uint32_field() const { return uint32_field_.value(); }
void set_uint32_field(uint32_t value) { uint32_field_.set_value(value); }
const std::string& bytes_field() const { return bytes_field_.value(); }
void set_bytes_field(absl::string_view value) {
bytes_field_.set_value(value);
}
bool operator==(const Submessage& other) const {
return uint32_field_.value() == other.uint32_field_.value() &&
bytes_field_.value() == other.bytes_field_.value();
}
private:
size_t num_fields() const override { return 2; }
const Field* field(int i) const override {
return std::array<const Field*, 2>{{&uint32_field_, &bytes_field_}}[i];
}
Uint32Field uint32_field_{1};
// Arbitrary padding to make sure pasing/serializing doesn't rely on
// fields being contiguous in memory.
[[maybe_unused]] uint8_t padding_[20] = {};
BytesField bytes_field_{2};
};
enum class TestEnum : uint32_t {
kZero = 0,
kOne = 1,
kTwo = 2,
};
bool TestEnum_IsValid(uint32_t value) {
return value == static_cast<uint32_t>(TestEnum::kZero) ||
value == static_cast<uint32_t>(TestEnum::kOne) ||
value == static_cast<uint32_t>(TestEnum::kTwo);
}
class TestMessage : public Message {
public:
TestMessage() = default;
uint32_t uint32_field() const { return uint32_field_.value(); }
void set_uint32_field(uint32_t value) { uint32_field_.set_value(value); }
const std::string& bytes_field() const { return bytes_field_.value(); }
void set_bytes_field(const std::string& value) {
bytes_field_.set_value(value);
}
const Submessage& sub_message_field() const {
return sub_message_field_.value();
}
Submessage* mutable_sub_message_field() {
return sub_message_field_.mutable_value();
}
TestEnum enum_field() const { return enum_field_.value(); }
void set_enum_field(TestEnum value) { enum_field_.set_value(value); }
bool operator==(const TestMessage& other) const {
return uint32_field_.value() == other.uint32_field_.value() &&
bytes_field_.value() == other.bytes_field_.value() &&
sub_message_field_.value() == other.sub_message_field_.value() &&
enum_field_.value() == other.enum_field_.value();
}
private:
size_t num_fields() const override { return 4; }
const Field* field(int i) const override {
return std::array<const Field*, 4>{
{&uint32_field_, &bytes_field_, &sub_message_field_, &enum_field_}}[i];
}
Uint32Field uint32_field_{1};
BytesField bytes_field_{2};
MessageField<Submessage> sub_message_field_{3};
EnumField<TestEnum> enum_field_{4, &TestEnum_IsValid, TestEnum::kZero};
};
TEST(MessageFieldDeathTest, CannotCreateWithImplicitOption) {
EXPECT_DEATH(MessageField<TestMessage> field(
1, crypto::tink::internal::ProtoFieldOptions::kImplicit),
"MessageField does not support kImplicit option.");
}
TEST(MessageFieldTest, CopyConstructor) {
MessageField<TestMessage> field(1);
field.mutable_value()->set_uint32_field(123);
field.mutable_value()->set_bytes_field("test");
field.mutable_value()->mutable_sub_message_field()->set_uint32_field(456);
field.mutable_value()->mutable_sub_message_field()->set_bytes_field("field");
field.mutable_value()->set_enum_field(TestEnum::kOne);
MessageField<TestMessage> field2 = field;
EXPECT_THAT(field2.value(), Eq(field.value()));
// Make changes to field to verify that field2 is not changed.
field.mutable_value()->set_uint32_field(1234);
field.mutable_value()->set_bytes_field("test2");
field.mutable_value()->mutable_sub_message_field()->set_uint32_field(4567);
field.mutable_value()->mutable_sub_message_field()->set_bytes_field("field2");
field.mutable_value()->set_enum_field(TestEnum::kTwo);
EXPECT_THAT(field2.value(), Not(Eq(field.value())));
}
TEST(MessageFieldTest, CopyAssignment) {
MessageField<TestMessage> field(1);
field.mutable_value()->set_uint32_field(123);
field.mutable_value()->set_bytes_field("test");
field.mutable_value()->mutable_sub_message_field()->set_uint32_field(456);
field.mutable_value()->mutable_sub_message_field()->set_bytes_field("field");
field.mutable_value()->set_enum_field(TestEnum::kOne);
MessageField<TestMessage> field2(2);
field2.mutable_value()->set_uint32_field(999);
field2 = field;
EXPECT_THAT(field2.value(), Eq(field.value()));
// Make changes to field to verify that field2 is not changed.
field.mutable_value()->set_uint32_field(1234);
field.mutable_value()->set_bytes_field("test2");
field.mutable_value()->mutable_sub_message_field()->set_uint32_field(4567);
field.mutable_value()->mutable_sub_message_field()->set_bytes_field("field2");
field.mutable_value()->set_enum_field(TestEnum::kTwo);
EXPECT_THAT(field2.value(), Not(Eq(field.value())));
}
TEST(MessageFieldTest, MoveConstructor) {
MessageField<TestMessage> field(1);
field.mutable_value()->set_uint32_field(123);
field.mutable_value()->set_bytes_field("test");
field.mutable_value()->mutable_sub_message_field()->set_uint32_field(456);
field.mutable_value()->mutable_sub_message_field()->set_bytes_field("field");
field.mutable_value()->set_enum_field(TestEnum::kTwo);
MessageField<TestMessage> field2 = std::move(field);
// Verify field2 has the correct values.
EXPECT_THAT(field2.value().uint32_field(), Eq(123));
EXPECT_THAT(field2.value().bytes_field(), Eq("test"));
EXPECT_THAT(field2.value().sub_message_field().uint32_field(), Eq(456));
EXPECT_THAT(field2.value().sub_message_field().bytes_field(), Eq("field"));
}
TEST(MessageFieldTest, MoveAssignment) {
MessageField<TestMessage> field(1);
field.mutable_value()->set_uint32_field(123);
field.mutable_value()->set_bytes_field("test");
field.mutable_value()->mutable_sub_message_field()->set_uint32_field(456);
field.mutable_value()->mutable_sub_message_field()->set_bytes_field("field");
field.mutable_value()->set_enum_field(TestEnum::kTwo);
MessageField<TestMessage> field2(2);
field2.mutable_value()->set_uint32_field(999);
field2 = std::move(field);
// Verify field2 has the correct values.
EXPECT_THAT(field2.value().uint32_field(), Eq(123));
EXPECT_THAT(field2.value().bytes_field(), Eq("test"));
EXPECT_THAT(field2.value().sub_message_field().uint32_field(), Eq(456));
EXPECT_THAT(field2.value().sub_message_field().bytes_field(), Eq("field"));
}
TEST(MessageFieldTest, ClearMemberWorks) {
MessageField<InnerStruct> field{1};
*field.mutable_value() = InnerStruct(123, 456);
field.Clear();
EXPECT_THAT(field.has_value(), IsFalse());
}
TEST(MessageFieldTest, ConsumeIntoMemberSuccessCases) {
MessageField<InnerStruct> field{1};
std::string bytes =
absl::StrCat(/* 4 bytes */ HexDecodeOrDie("04"),
/* Int field, tag 1, value 0x23 */ HexDecodeOrDie("0823"),
/* Int field, tag 2, value 0x7a */ HexDecodeOrDie("107a"),
"remaining_data");
ParsingState parsing_state = ParsingState(bytes);
ASSERT_THAT(field.ConsumeIntoMember(parsing_state), IsTrue());
EXPECT_THAT(parsing_state.RemainingData(), Eq("remaining_data"));
ASSERT_THAT(field.has_value(), IsTrue());
EXPECT_THAT(field.value().uint32_member_1(), Eq(0x23));
EXPECT_THAT(field.value().uint32_member_2(), Eq(0x7a));
}
TEST(MessageFieldTest, ConsumeIntoMemberWithCrcSuccessCases) {
MessageField<InnerStruct> field{1};
std::string bytes =
absl::StrCat(/* 4 bytes */ HexDecodeOrDie("04"),
/* Int field, tag 1, value 0x23 */ HexDecodeOrDie("0823"),
/* Int field, tag 2, value 0x7a */ HexDecodeOrDie("107a"),
"remaining_data");
absl::crc32c_t crc{};
ParsingState parsing_state = ParsingState(bytes, &crc);
EXPECT_THAT(field.ConsumeIntoMember(parsing_state), IsTrue());
EXPECT_THAT(parsing_state.RemainingData(), Eq("remaining_data"));
EXPECT_THAT(crc, Eq(absl::ComputeCrc32c(bytes.substr(0, 5))));
ASSERT_THAT(field.has_value(), IsTrue());
EXPECT_THAT(field.value().uint32_member_1(), Eq(0x23));
EXPECT_THAT(field.value().uint32_member_2(), Eq(0x7a));
}
TEST(MessageFieldTest, ConsumeIntoMemberEmptyStringNullopt) {
MessageField<InnerStruct> field{1};
std::string bytes = HexDecodeOrDie("00");
ParsingState parsing_state = ParsingState(bytes);
ASSERT_THAT(field.ConsumeIntoMember(parsing_state), IsTrue());
ASSERT_THAT(field.has_value(), IsTrue());
EXPECT_THAT(field.value().uint32_member_1(), Eq(0));
EXPECT_THAT(field.value().uint32_member_2(), Eq(0));
}
TEST(MessageFieldTest, ConsumeIntoMemberEmptyString) {
MessageField<InnerStruct> field{1};
*field.mutable_value() = InnerStruct(10, 0);
std::string bytes = HexDecodeOrDie("00");
ParsingState parsing_state = ParsingState(bytes);
// This does not clear the fields because if there are multiple blocks
// for the same field we merge them.
ASSERT_THAT(field.ConsumeIntoMember(parsing_state), IsTrue());
ASSERT_THAT(field.has_value(), IsTrue());
EXPECT_THAT(field.value().uint32_member_1(), Eq(10));
EXPECT_THAT(field.value().uint32_member_2(), Eq(0));
}
TEST(MessageFieldTest, ConsumeIntoMemberDoesNotClear) {
MessageField<InnerStruct> field{1};
*field.mutable_value() = InnerStruct(10, 0);
std::string bytes = absl::StrCat(/* 4 bytes */ HexDecodeOrDie("02"),
/* Int field, tag 2, value 0x7a */
HexDecodeOrDie("107a"));
ParsingState parsing_state = ParsingState(bytes);
// This does not clear uint32_member_1 because if there are multiple blocks
// for the same field we merge them.
ASSERT_THAT(field.ConsumeIntoMember(parsing_state), IsTrue());
ASSERT_THAT(field.has_value(), IsTrue());
EXPECT_THAT(field.value().uint32_member_1(), Eq(10));
EXPECT_THAT(field.value().uint32_member_2(), Eq(0x7a));
}
TEST(MessageFieldTest, ConsumeIntoMemberWithInnerStructNullopt) {
MessageField<InnerStruct> field{1};
std::string bytes = absl::StrCat(/* 4 bytes */ HexDecodeOrDie("02"),
/* Int field, tag 2, value 0x7a */
HexDecodeOrDie("107a"));
ParsingState parsing_state = ParsingState(bytes);
// This does not clear uint32_member_1 because if there are multiple blocks
// for the same field we merge them.
ASSERT_THAT(field.ConsumeIntoMember(parsing_state), IsTrue());
ASSERT_THAT(field.has_value(), IsTrue());
EXPECT_THAT(field.value().uint32_member_1(), Eq(0)); // Default value.
EXPECT_THAT(field.value().uint32_member_2(), Eq(0x7a));
}
TEST(MessageFieldTest, ConsumeIntoMemberVarintTooLong) {
MessageField<InnerStruct> field{1};
std::string bytes = /* LengthDelimetedLength: */ HexDecodeOrDie("01");
ParsingState parsing_state = ParsingState(bytes);
EXPECT_THAT(field.ConsumeIntoMember(parsing_state), IsFalse());
}
TEST(MessageFieldTest, EmptyWithoutVarint) {
MessageField<InnerStruct> field{1};
std::string bytes = "";
ParsingState parsing_state = ParsingState(bytes);
EXPECT_THAT(field.ConsumeIntoMember(parsing_state), IsFalse());
}
TEST(MessageFieldTest, InvalidVarint) {
MessageField<InnerStruct> field{1};
std::string bytes = absl::StrCat(HexDecodeOrDie("808080808000"), "abcde");
ParsingState parsing_state = ParsingState(bytes);
EXPECT_THAT(field.ConsumeIntoMember(parsing_state), IsFalse());
}
// When the optional struct is not set, we produce an empty serialization.
TEST(MessageFieldTest, SerializeNulloptProducesEmptySerialization) {
MessageField<InnerStruct> field{1};
std::string buffer = "abc";
EXPECT_THAT(field.GetSerializedSizeIncludingTag(), Eq(0));
SerializationState state = SerializationState(absl::MakeSpan(buffer));
EXPECT_THAT(field.SerializeWithTagInto(state), IsTrue());
EXPECT_THAT(state.GetBuffer().size(), Eq(3));
EXPECT_THAT(buffer, Eq("abc"));
}
// When the options are set to kAlwaysPresent, we produce a non-empty
// serialization.
TEST(MessageFieldTest, SerializekAlwaysPresentProducesNonEmptySerialization) {
MessageField<InnerStruct> field(1, ProtoFieldOptions::kAlwaysPresent);
std::string buffer = "abcabc";
EXPECT_THAT(field.GetSerializedSizeIncludingTag(), Eq(2));
SerializationState state = SerializationState(absl::MakeSpan(buffer));
EXPECT_THAT(field.SerializeWithTagInto(state), IsTrue());
EXPECT_THAT(state.GetBuffer().size(), Eq(4));
EXPECT_THAT(buffer, absl::StrCat(test::HexDecodeOrDie("0a00"), "cabc"));
}
TEST(MessageFieldTest, HasValueAlwaysTrueIfkAlwaysPresent) {
MessageField<InnerStruct> field(1, ProtoFieldOptions::kAlwaysPresent);
EXPECT_THAT(field.has_value(), IsTrue());
*field.mutable_value() = InnerStruct{};
EXPECT_THAT(field.has_value(), IsTrue());
}
TEST(MessageFieldTest, HasValueIsFalseIfkExplicit) {
MessageField<InnerStruct> field(1, ProtoFieldOptions::kExplicit);
EXPECT_THAT(field.has_value(), IsFalse());
*field.mutable_value() = InnerStruct{};
EXPECT_THAT(field.has_value(), IsTrue());
// The value is serialized.
std::string buffer = "abcabc";
EXPECT_THAT(field.GetSerializedSizeIncludingTag(), Eq(2));
SerializationState state = SerializationState(absl::MakeSpan(buffer));
EXPECT_THAT(field.SerializeWithTagInto(state), IsTrue());
EXPECT_THAT(state.GetBuffer().size(), Eq(4));
EXPECT_THAT(buffer, absl::StrCat(test::HexDecodeOrDie("0a00"), "cabc"));
}
// When the optional struct is set to the default value, we produce a
// serialization of the empty submessage.
TEST(MessageFieldTest,
SerializeInnerStructWithDefaultValuesProducesEmptySubmessage) {
MessageField<InnerStruct> field{1};
*field.mutable_value() = InnerStruct{};
std::string buffer = "abc";
SerializationState state = SerializationState(absl::MakeSpan(buffer));
EXPECT_THAT(field.GetSerializedSizeIncludingTag(), Eq(2));
EXPECT_THAT(field.SerializeWithTagInto(state), IsTrue());
EXPECT_THAT(state.GetBuffer().size(), Eq(1));
// Serialized as empty submessage.
EXPECT_THAT(buffer.substr(0, 2), Eq(FieldWithNumber(1).IsSubMessage({})));
}
TEST(MessageFieldTest, SerializeNonEmpty) {
MessageField<InnerStruct> field{1};
*field.mutable_value() = InnerStruct(0x23, 0x7a);
std::string buffer = "BUFFERBUFFERBUFFERBUFFER";
SerializationState state = SerializationState(absl::MakeSpan(buffer));
EXPECT_THAT(field.GetSerializedSizeIncludingTag(), Eq(6));
EXPECT_THAT(field.SerializeWithTagInto(state), IsTrue());
EXPECT_THAT(state.GetBuffer().size(), Eq(buffer.size() - 6));
EXPECT_THAT(&(state.GetBuffer())[0], Eq(&buffer[6]));
EXPECT_THAT(
buffer.substr(0, 6),
Eq(FieldWithNumber(1).IsSubMessage({FieldWithNumber(1).IsVarint(0x23),
FieldWithNumber(2).IsVarint(0x7a)})));
// Rest is untouched
EXPECT_THAT(buffer.substr(6), Eq("BUFFERBUFFERBUFFER"));
}
TEST(MessageFieldTest, SerializeTooSmallBuffer) {
MessageField<InnerStruct> field{1};
*field.mutable_value() = InnerStruct(0x23, 0x7a);
std::string buffer = "BUFFE";
SerializationState state = SerializationState(absl::MakeSpan(buffer));
EXPECT_THAT(field.SerializeWithTagInto(state), IsFalse());
}
// The buffer can hold the tag, but not the varint of the length.
TEST(MessageFieldTest, SerializeSmallerBuffer) {
MessageField<InnerStruct> field{1};
*field.mutable_value() = InnerStruct(0x23, 0x7a);
std::string buffer = "B";
SerializationState state = SerializationState(absl::MakeSpan(buffer));
EXPECT_THAT(field.SerializeWithTagInto(state), IsFalse());
}
// The buffer won't even hold the varint.
TEST(MessageFieldTest, SerializeVerySmallBuffer) {
MessageField<InnerStruct> field{1};
*field.mutable_value() = InnerStruct(0x23, 0x7a);
std::string buffer;
SerializationState state = SerializationState(absl::MakeSpan(buffer));
EXPECT_THAT(field.SerializeWithTagInto(state), IsFalse());
}
class MessageWithBrokenFieldOrder : public Message {
public:
MessageWithBrokenFieldOrder() = default;
using Message::ParseFromString;
private:
size_t num_fields() const override { return 2; }
const Field* field(int i) const override {
return std::array<const Field*, 2>{
{&uint32_member_2_, &uint32_member_1_}}[i];
}
Uint32Field uint32_member_1_{1};
Uint32Field uint32_member_2_{2};
};
TEST(MessageFieldDeathTest, DiesOnParse) {
MessageWithBrokenFieldOrder message;
EXPECT_DEBUG_DEATH(
{ message.ParseFromString(HexDecodeOrDie("0800")); },
HasSubstr("Fields returned by field() must be sorted"));
}
} // namespace
} // namespace proto_parsing
} // namespace internal
} // namespace tink
} // namespace crypto