| // 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 |