blob: 3a4b7cfaab0193e023a2ed5517af21d75b8cd515 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* 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 <limits>
#include <memory>
#include <vector>
#include "perfetto/protozero/message_handle.h"
#include "perfetto/protozero/packed_repeated_fields.h"
#include "perfetto/protozero/scattered_heap_buffer.h"
#include "test/gtest_and_gmock.h"
// Autogenerated headers in out/*/gen/
#include "src/protozero/test/example_proto/extensions.pb.h"
#include "src/protozero/test/example_proto/extensions.pbzero.h"
#include "src/protozero/test/example_proto/library.pbzero.h"
#include "src/protozero/test/example_proto/other_package/test_messages.pbzero.h"
#include "src/protozero/test/example_proto/subpackage/test_messages.pbzero.h"
#include "src/protozero/test/example_proto/test_messages.pb.h"
#include "src/protozero/test/example_proto/test_messages.pbzero.h"
// Generated by the protozero plugin.
namespace pbtest = protozero::test::protos::pbzero;
namespace pbtest_subpackage = protozero::test::protos::subpackage::pbzero;
namespace pbtest_otherpackage = other_package::pbzero;
// Generated by the official protobuf compiler.
namespace pbgold = protozero::test::protos;
namespace pbgold_subpackage = protozero::test::protos::subpackage;
namespace pbgold_other_package = other_package;
namespace protozero {
namespace {
constexpr size_t kChunkSize = 42;
TEST(ProtoZeroConformanceTest, SimpleFieldsNoNesting) {
HeapBuffered<pbtest::EveryField> msg{kChunkSize, kChunkSize};
msg->set_field_int32(-1);
msg->set_field_int64(-333123456789ll);
msg->set_field_uint32(600);
msg->set_field_uint64(333123456789ll);
msg->set_field_sint32(-5);
msg->set_field_sint64(-9000);
msg->set_field_fixed32(12345);
msg->set_field_fixed64(444123450000ll);
msg->set_field_sfixed32(-69999);
msg->set_field_sfixed64(-200);
msg->set_field_float(3.14f);
msg->set_field_double(0.5555);
msg->set_field_bool(true);
msg->set_small_enum(pbtest::SmallEnum::TO_BE);
msg->set_signed_enum(pbtest::SignedEnum::NEGATIVE);
msg->set_big_enum(pbtest::BigEnum::BEGIN);
msg->set_field_string("FizzBuzz");
msg->set_field_bytes(reinterpret_cast<const uint8_t*>("\x11\x00\xBE\xEF"), 4);
msg->add_repeated_int32(1);
msg->add_repeated_int32(-1);
msg->add_repeated_int32(100);
msg->add_repeated_int32(2000000);
std::string serialized = msg.SerializeAsString();
pbgold::EveryField gold_msg;
gold_msg.ParseFromString(serialized);
EXPECT_EQ(-1, gold_msg.field_int32());
EXPECT_EQ(-333123456789ll, gold_msg.field_int64());
EXPECT_EQ(600u, gold_msg.field_uint32());
EXPECT_EQ(333123456789ull, gold_msg.field_uint64());
EXPECT_EQ(-5, gold_msg.field_sint32());
EXPECT_EQ(-9000, gold_msg.field_sint64());
EXPECT_EQ(12345u, gold_msg.field_fixed32());
EXPECT_EQ(444123450000ull, gold_msg.field_fixed64());
EXPECT_EQ(-69999, gold_msg.field_sfixed32());
EXPECT_EQ(-200, gold_msg.field_sfixed64());
EXPECT_FLOAT_EQ(3.14f, gold_msg.field_float());
EXPECT_DOUBLE_EQ(0.5555, gold_msg.field_double());
EXPECT_EQ(true, gold_msg.field_bool());
EXPECT_EQ(pbgold::SmallEnum::TO_BE, gold_msg.small_enum());
EXPECT_EQ(pbgold::SignedEnum::NEGATIVE, gold_msg.signed_enum());
EXPECT_EQ(pbgold::BigEnum::BEGIN, gold_msg.big_enum());
EXPECT_EQ("FizzBuzz", gold_msg.field_string());
EXPECT_EQ(std::string("\x11\x00\xBE\xEF", 4), gold_msg.field_bytes());
EXPECT_EQ(4, gold_msg.repeated_int32_size());
EXPECT_EQ(1, gold_msg.repeated_int32(0));
EXPECT_EQ(-1, gold_msg.repeated_int32(1));
EXPECT_EQ(100, gold_msg.repeated_int32(2));
EXPECT_EQ(2000000, gold_msg.repeated_int32(3));
EXPECT_EQ(serialized.size(), static_cast<size_t>(gold_msg.ByteSizeLong()));
}
TEST(ProtoZeroConformanceTest, NestedMessages) {
HeapBuffered<pbtest::NestedA> msg_a{kChunkSize, kChunkSize};
pbtest::NestedA::NestedB* msg_b = msg_a->add_repeated_a();
pbtest::NestedA::NestedB::NestedC* msg_c = msg_b->set_value_b();
msg_c->set_value_c(321);
msg_b = msg_a->add_repeated_a();
msg_c = msg_a->set_super_nested();
msg_c->set_value_c(1000);
std::string serialized = msg_a.SerializeAsString();
EXPECT_EQ(serialized.size(), 14u);
pbgold::NestedA gold_msg_a;
gold_msg_a.ParseFromString(serialized);
EXPECT_EQ(2, gold_msg_a.repeated_a_size());
EXPECT_EQ(321, gold_msg_a.repeated_a(0).value_b().value_c());
EXPECT_FALSE(gold_msg_a.repeated_a(1).has_value_b());
EXPECT_EQ(1000, gold_msg_a.super_nested().value_c());
}
TEST(ProtoZeroConformanceTest, Extensions) {
HeapBuffered<pbtest::BrowserExtension> msg_a{kChunkSize, kChunkSize};
msg_a->set_base_int(4);
pbtest::SystemA* msg_b = msg_a->set_extension_a();
msg_b->set_int_a(3);
msg_b->set_string_a("string a");
pbtest::SystemB* msg_c = msg_a->set_extension_b();
msg_c->set_int_b(10);
msg_c->set_string_b("string b");
msg_a->set_base_string("base string");
std::string serialized = msg_a.SerializeAsString();
pbgold::RealFakeEvent gold_msg_a;
gold_msg_a.ParseFromString(serialized);
EXPECT_EQ(gold_msg_a.base_int(), 4u);
EXPECT_EQ(gold_msg_a.base_string(), "base string");
pbgold::SystemA gold_msg_b =
gold_msg_a.GetExtension(pbgold::BrowserExtension::extension_a);
EXPECT_EQ(gold_msg_b.int_a(), 3u);
EXPECT_EQ(gold_msg_b.string_a(), "string a");
pbgold::SystemB gold_msg_c =
gold_msg_a.GetExtension(pbgold::BrowserExtension::extension_b);
EXPECT_EQ(gold_msg_c.int_b(), 10u);
EXPECT_EQ(gold_msg_c.string_b(), "string b");
}
TEST(ProtoZeroConformanceTest, Import) {
// Test the includes for indirect public import: library.pbzero.h ->
// library_internals/galaxies.pbzero.h -> upper_import.pbzero.h .
EXPECT_LE(0u, sizeof(pbtest::TrickyPublicImport));
}
TEST(ProtoZeroConformanceTest, FieldNumbers) {
EXPECT_EQ(1, pbtest::CamelCaseFields::kFooBarBazFieldNumber);
EXPECT_EQ(2, pbtest::CamelCaseFields::kBarBazFieldNumber);
EXPECT_EQ(3, pbtest::CamelCaseFields::kMooMooFieldNumber);
EXPECT_EQ(4, pbtest::CamelCaseFields::kURLEncoderFieldNumber);
EXPECT_EQ(5, pbtest::CamelCaseFields::kXMapFieldNumber);
EXPECT_EQ(6, pbtest::CamelCaseFields::kUrLENcoDerFieldNumber);
EXPECT_EQ(7, pbtest::CamelCaseFields::kBigBangFieldNumber);
EXPECT_EQ(8, pbtest::CamelCaseFields::kU2FieldNumber);
EXPECT_EQ(9, pbtest::CamelCaseFields::kBangBigFieldNumber);
}
TEST(ProtoZeroConformanceTest, PackedRepeatedVarint) {
int values[] = {42, 255, -1};
HeapBuffered<pbtest::PackedRepeatedFields> msg{kChunkSize, kChunkSize};
PackedVarInt buf;
for (auto v : values)
buf.Append(v);
msg->set_field_int32(buf);
std::string serialized = msg.SerializeAsString();
// Serialized as a length-delimited field with a payload of
// concatenated varints. So the size should be:
// varint(42) -> 1 byte
// varint(255) -> 2 bytes
// varint(-1) -> 10 bytes
// varint(payload length) -> 1 byte
// field type & id(1) -> 1 byte
// total: 6 bytes
EXPECT_EQ(15u, serialized.size());
EXPECT_EQ(proto_utils::MakeTagLengthDelimited(
pbtest::PackedRepeatedFields::kFieldInt32FieldNumber),
static_cast<uint32_t>(serialized[0]));
// Correctly parsed by the protobuf library.
pbgold::PackedRepeatedFields parsed_gold_msg;
parsed_gold_msg.ParseFromString(serialized);
ASSERT_THAT(parsed_gold_msg.field_int32(), testing::ElementsAreArray(values));
// Encoded identically by the protobuf library.
pbgold::PackedRepeatedFields gold_msg;
for (auto v : values)
gold_msg.add_field_int32(v);
ASSERT_EQ(gold_msg.SerializeAsString(), serialized);
}
TEST(ProtoZeroConformanceTest, PackedRepeatedFixed32) {
uint32_t values[] = {1, 2, 4, 8};
HeapBuffered<pbtest::PackedRepeatedFields> msg{kChunkSize, kChunkSize};
PackedFixedSizeInt<uint32_t> buf;
for (auto v : values)
buf.Append(v);
msg->set_field_fixed32(buf);
std::string serialized = msg.SerializeAsString();
// 4x4 bytes payload + 1 byte length + 1 byte tag & field
EXPECT_EQ(18u, serialized.size());
EXPECT_EQ(proto_utils::MakeTagLengthDelimited(
pbtest::PackedRepeatedFields::kFieldFixed32FieldNumber),
static_cast<uint32_t>(serialized[0]));
// Correctly parsed by the protobuf library.
pbgold::PackedRepeatedFields parsed_gold_msg;
parsed_gold_msg.ParseFromString(serialized);
ASSERT_THAT(parsed_gold_msg.field_fixed32(),
testing::ElementsAreArray(values));
// Encoded identically by the protobuf library.
pbgold::PackedRepeatedFields gold_msg;
for (auto v : values)
gold_msg.add_field_fixed32(v);
ASSERT_EQ(gold_msg.SerializeAsString(), serialized);
}
TEST(ProtoZeroConformanceTest, PackedRepeatedFixed64) {
int64_t values[] = {1, -2, 4, -8};
HeapBuffered<pbtest::PackedRepeatedFields> msg{kChunkSize, kChunkSize};
PackedFixedSizeInt<int64_t> buf;
for (auto v : values)
buf.Append(v);
msg->set_field_sfixed64(buf);
std::string serialized = msg.SerializeAsString();
// 4x8 bytes payload + 1 byte length + 1 byte tag & field
EXPECT_EQ(34u, serialized.size());
EXPECT_EQ(proto_utils::MakeTagLengthDelimited(
pbtest::PackedRepeatedFields::kFieldSfixed64FieldNumber),
static_cast<uint32_t>(serialized[0]));
// Correctly parsed by the protobuf library.
pbgold::PackedRepeatedFields parsed_gold_msg;
parsed_gold_msg.ParseFromString(serialized);
ASSERT_THAT(parsed_gold_msg.field_sfixed64(),
testing::ElementsAreArray(values));
// Encoded identically by the protobuf library.
pbgold::PackedRepeatedFields gold_msg;
for (auto v : values)
gold_msg.add_field_sfixed64(v);
ASSERT_EQ(gold_msg.SerializeAsString(), serialized);
}
TEST(ProtoZeroConformanceTest, EmptyPackedRepeatedField) {
HeapBuffered<pbtest::PackedRepeatedFields> msg;
PackedVarInt buf;
msg->set_field_int32(buf);
std::string serialized = msg.SerializeAsString();
// Encoded as 2 bytes: tag/field, and a length of zero.
EXPECT_EQ(2u, serialized.size());
EXPECT_EQ(proto_utils::MakeTagLengthDelimited(
pbtest::PackedRepeatedFields::kFieldInt32FieldNumber),
static_cast<uint32_t>(serialized[0]));
EXPECT_EQ(0, serialized[1]);
// Correctly parsed by the protobuf library.
pbgold::PackedRepeatedFields parsed_gold_msg;
parsed_gold_msg.ParseFromString(serialized);
EXPECT_EQ(0, parsed_gold_msg.field_int32_size());
}
// Tests that the stack -> heap expansion dosn't lose data.
TEST(ProtoZeroConformanceTest, PackedRepeatedResize) {
const int kNumValues = 32768;
const int64_t kMultiplier = 10000000;
HeapBuffered<pbtest::PackedRepeatedFields> msg{kChunkSize, kChunkSize};
PackedFixedSizeInt<int64_t> buf;
for (int i = 0; i < kNumValues; i++)
buf.Append(i * kMultiplier);
msg->set_field_sfixed64(buf);
std::string serialized = msg.SerializeAsString();
// Correctly parsed by the protobuf library.
pbgold::PackedRepeatedFields parsed_gold_msg;
parsed_gold_msg.ParseFromString(serialized);
ASSERT_EQ(parsed_gold_msg.field_sfixed64().size(), kNumValues);
for (int i = 0; i < kNumValues; i++) {
ASSERT_EQ(parsed_gold_msg.field_sfixed64(i), i * kMultiplier);
}
}
TEST(ProtoZeroConformanceTest, EnumToString) {
EXPECT_STREQ(protozero::test::protos::pbzero::SmallEnum_Name(
protozero::test::protos::pbzero::SmallEnum::TO_BE),
"TO_BE");
EXPECT_STREQ(protozero::test::protos::pbzero::EveryField::NestedEnum_Name(
protozero::test::protos::pbzero::EveryField::PING),
"PING");
}
TEST(ProtoZeroConformanceTest, DifferentPackages) {
HeapBuffered<pbtest::DifferentPackages> msg{kChunkSize, kChunkSize};
// Pupulate fields defined in "protozero.test.protos.subpackage"
pbtest_subpackage::Message* msgSubpackage = msg->set_subpackage_message();
msgSubpackage->set_field_int32(1);
msgSubpackage->set_field_enum(pbtest_subpackage::Enum::A);
msgSubpackage->set_field_nested_enum(
pbtest_subpackage::Message::NestedEnum::C);
msg->set_subpackage_nested_message()->set_field_int32(2);
msg->set_subpackage_enum(pbtest_subpackage::Enum::B);
msg->set_subpackage_nested_enum(pbtest_subpackage::Message_NestedEnum::D);
// Pupulate fields defined in "other_package"
pbtest_otherpackage::Message* msgOtherPackage =
msg->set_otherpackage_message();
msgOtherPackage->set_field_int32(11);
msgOtherPackage->set_field_enum(pbtest_otherpackage::Enum::A);
msgOtherPackage->set_field_nested_enum(
pbtest_otherpackage::Message::NestedEnum::C);
msg->set_otherpackage_nested_message()->set_field_int32(12);
msg->set_otherpackage_enum(pbtest_otherpackage::Enum::B);
msg->set_otherpackage_nested_enum(pbtest_otherpackage::Message_NestedEnum::D);
// Deserialize into golden proto
std::string serialized = msg.SerializeAsString();
pbgold::DifferentPackages gold_msg;
gold_msg.ParseFromString(serialized);
EXPECT_EQ(serialized.size(), static_cast<size_t>(gold_msg.ByteSizeLong()));
// Check fields defined in "protozero.test.protos.subpackage"
EXPECT_EQ(1, gold_msg.subpackage_message().field_int32());
EXPECT_EQ(pbgold_subpackage::Enum::A,
gold_msg.subpackage_message().field_enum());
EXPECT_EQ(pbgold_subpackage::Message_NestedEnum_C,
gold_msg.subpackage_message().field_nested_enum());
EXPECT_EQ(2, gold_msg.subpackage_nested_message().field_int32());
EXPECT_EQ(pbgold_subpackage::Enum::B, gold_msg.subpackage_enum());
EXPECT_EQ(pbgold_subpackage::Message_NestedEnum_D,
gold_msg.subpackage_nested_enum());
// Check fields defined in "other_package"
EXPECT_EQ(11, gold_msg.otherpackage_message().field_int32());
EXPECT_EQ(pbgold_other_package::Enum::A,
gold_msg.otherpackage_message().field_enum());
EXPECT_EQ(pbgold_other_package::Message_NestedEnum_C,
gold_msg.otherpackage_message().field_nested_enum());
EXPECT_EQ(12, gold_msg.otherpackage_nested_message().field_int32());
EXPECT_EQ(pbgold_other_package::Enum::B, gold_msg.otherpackage_enum());
EXPECT_EQ(pbgold_other_package::Message_NestedEnum_D,
gold_msg.otherpackage_nested_enum());
}
} // namespace
} // namespace protozero