blob: b72fff084e1e5a0e9332d36005fdb845d4c1e972 [file] [log] [blame]
/*
* Copyright (C) 2021 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 "src/trace_processor/util/proto_to_args_parser.h"
#include "perfetto/ext/base/string_view.h"
#include "perfetto/protozero/packed_repeated_fields.h"
#include "perfetto/protozero/scattered_heap_buffer.h"
#include "perfetto/trace_processor/trace_blob.h"
#include "perfetto/trace_processor/trace_blob_view.h"
#include "protos/perfetto/common/descriptor.pbzero.h"
#include "protos/perfetto/trace/track_event/source_location.pbzero.h"
#include "src/protozero/test/example_proto/test_messages.pbzero.h"
#include "src/trace_processor/test_messages.descriptor.h"
#include "src/trace_processor/util/interned_message_view.h"
#include "test/gtest_and_gmock.h"
#include <cstdint>
#include <limits>
#include <sstream>
namespace perfetto {
namespace trace_processor {
namespace util {
namespace {
constexpr size_t kChunkSize = 42;
protozero::ConstChars ToChars(const char* str) {
return protozero::ConstChars{str, strlen(str)};
}
class ProtoToArgsParserTest : public ::testing::Test,
public ProtoToArgsParser::Delegate {
protected:
ProtoToArgsParserTest() {}
const std::vector<std::string>& args() const { return args_; }
void AddInternedSourceLocation(uint64_t iid, TraceBlobView data) {
interned_source_locations_[iid] = std::unique_ptr<InternedMessageView>(
new InternedMessageView(std::move(data)));
}
template <typename T, typename... Ts>
void CreatedPackedVarint(protozero::PackedVarInt& var, T p, Ts... ps) {
var.Reset();
std::array<T, sizeof...(ps) + 1> list = {p, ps...};
for (T v : list) {
var.Append(v);
}
}
private:
using Key = ProtoToArgsParser::Key;
void AddInteger(const Key& key, int64_t value) override {
std::stringstream ss;
ss << key.flat_key << " " << key.key << " " << value;
args_.push_back(ss.str());
}
void AddUnsignedInteger(const Key& key, uint64_t value) override {
std::stringstream ss;
ss << key.flat_key << " " << key.key << " " << value;
args_.push_back(ss.str());
}
void AddString(const Key& key, const protozero::ConstChars& value) override {
std::stringstream ss;
ss << key.flat_key << " " << key.key << " " << value.ToStdString();
args_.push_back(ss.str());
}
void AddString(const Key& key, const std::string& value) override {
std::stringstream ss;
ss << key.flat_key << " " << key.key << " " << value;
args_.push_back(ss.str());
}
void AddDouble(const Key& key, double value) override {
std::stringstream ss;
ss << key.flat_key << " " << key.key << " " << value;
args_.push_back(ss.str());
}
void AddPointer(const Key& key, const void* value) override {
std::stringstream ss;
ss << key.flat_key << " " << key.key << " " << std::hex
<< reinterpret_cast<uintptr_t>(value) << std::dec;
args_.push_back(ss.str());
}
void AddBoolean(const Key& key, bool value) override {
std::stringstream ss;
ss << key.flat_key << " " << key.key << " " << (value ? "true" : "false");
args_.push_back(ss.str());
}
bool AddJson(const Key& key, const protozero::ConstChars& value) override {
std::stringstream ss;
ss << key.flat_key << " " << key.key << " " << std::hex
<< value.ToStdString() << std::dec;
args_.push_back(ss.str());
return true;
}
void AddNull(const Key& key) override {
std::stringstream ss;
ss << key.flat_key << " " << key.key << " [NULL]";
args_.push_back(ss.str());
}
size_t GetArrayEntryIndex(const std::string&) final { return 0; }
size_t IncrementArrayEntryIndex(const std::string&) final { return 0; }
InternedMessageView* GetInternedMessageView(uint32_t field_id,
uint64_t iid) override {
if (field_id != protos::pbzero::InternedData::kSourceLocationsFieldNumber)
return nullptr;
return interned_source_locations_.at(iid).get();
}
PacketSequenceStateGeneration* seq_state() final { return nullptr; }
std::vector<std::string> args_;
std::map<uint64_t, std::unique_ptr<InternedMessageView>>
interned_source_locations_;
};
TEST_F(ProtoToArgsParserTest, EnsureTestMessageProtoParses) {
DescriptorPool pool;
auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
kTestMessagesDescriptor.size());
ProtoToArgsParser parser(pool);
EXPECT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
<< status.message();
}
TEST_F(ProtoToArgsParserTest, BasicSingleLayerProto) {
using namespace protozero::test::protos::pbzero;
protozero::HeapBuffered<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_double(0.5555);
msg->set_field_bool(true);
msg->set_small_enum(SmallEnum::TO_BE);
msg->set_signed_enum(SignedEnum::NEGATIVE);
msg->set_big_enum(BigEnum::BEGIN);
msg->set_nested_enum(EveryField::PONG);
msg->set_field_float(3.14f);
msg->set_field_string("FizzBuzz");
msg->add_repeated_int32(1);
msg->add_repeated_int32(-1);
msg->add_repeated_int32(100);
msg->add_repeated_int32(2000000);
auto binary_proto = msg.SerializeAsArray();
DescriptorPool pool;
auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
kTestMessagesDescriptor.size());
ProtoToArgsParser parser(pool);
ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
<< status.message();
status = parser.ParseMessage(
protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
".protozero.test.protos.EveryField", nullptr, *this);
EXPECT_TRUE(status.ok())
<< "InternProtoFieldsIntoArgsTable failed with error: "
<< status.message();
EXPECT_THAT(
args(),
testing::ElementsAre(
"field_int32 field_int32 -1", "field_int64 field_int64 -333123456789",
"field_uint32 field_uint32 600",
"field_uint64 field_uint64 333123456789",
"field_sint32 field_sint32 -5", "field_sint64 field_sint64 -9000",
"field_fixed32 field_fixed32 12345",
"field_fixed64 field_fixed64 444123450000",
"field_sfixed32 field_sfixed32 -69999",
"field_sfixed64 field_sfixed64 -200",
"field_double field_double 0.5555", "field_bool field_bool true",
"small_enum small_enum TO_BE", "signed_enum signed_enum NEGATIVE",
"big_enum big_enum BEGIN", "nested_enum nested_enum PONG",
"field_float field_float 3.14", "field_string field_string FizzBuzz",
"repeated_int32 repeated_int32[0] 1",
"repeated_int32 repeated_int32[1] -1",
"repeated_int32 repeated_int32[2] 100",
"repeated_int32 repeated_int32[3] 2000000"));
}
TEST_F(ProtoToArgsParserTest, NestedProto) {
using namespace protozero::test::protos::pbzero;
protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
msg->set_super_nested()->set_value_c(3);
auto binary_proto = msg.SerializeAsArray();
DescriptorPool pool;
auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
kTestMessagesDescriptor.size());
ProtoToArgsParser parser(pool);
ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
<< status.message();
status = parser.ParseMessage(
protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
".protozero.test.protos.NestedA", nullptr, *this);
EXPECT_TRUE(status.ok())
<< "InternProtoFieldsIntoArgsTable failed with error: "
<< status.message();
EXPECT_THAT(args(), testing::ElementsAre(
"super_nested.value_c super_nested.value_c 3"));
}
TEST_F(ProtoToArgsParserTest, CamelCaseFieldsProto) {
using namespace protozero::test::protos::pbzero;
protozero::HeapBuffered<CamelCaseFields> msg{kChunkSize, kChunkSize};
msg->set_barbaz(true);
msg->set_moomoo(true);
msg->set___bigbang(true);
auto binary_proto = msg.SerializeAsArray();
DescriptorPool pool;
auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
kTestMessagesDescriptor.size());
ProtoToArgsParser parser(pool);
ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
<< status.message();
status = parser.ParseMessage(
protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
".protozero.test.protos.CamelCaseFields", nullptr, *this);
EXPECT_TRUE(status.ok())
<< "InternProtoFieldsIntoArgsTable failed with error: "
<< status.message();
EXPECT_THAT(args(),
testing::ElementsAre("barBaz barBaz true", "MooMoo MooMoo true",
"__bigBang __bigBang true"));
}
TEST_F(ProtoToArgsParserTest, NestedProtoParsingOverrideHandled) {
using namespace protozero::test::protos::pbzero;
protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
msg->set_super_nested()->set_value_c(3);
auto binary_proto = msg.SerializeAsArray();
DescriptorPool pool;
auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
kTestMessagesDescriptor.size());
ProtoToArgsParser parser(pool);
ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
<< status.message();
parser.AddParsingOverrideForField(
"super_nested.value_c",
[](const protozero::Field& field, ProtoToArgsParser::Delegate& writer) {
EXPECT_EQ(field.type(), protozero::proto_utils::ProtoWireType::kVarInt);
std::string key = "super_nested.value_b.replaced";
writer.AddInteger({key, key}, field.as_int32());
// We've handled this field by adding the desired args.
return base::OkStatus();
});
status = parser.ParseMessage(
protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
".protozero.test.protos.NestedA", nullptr, *this);
EXPECT_TRUE(status.ok())
<< "InternProtoFieldsIntoArgsTable failed with error: "
<< status.message();
EXPECT_THAT(
args(),
testing::ElementsAre(
"super_nested.value_b.replaced super_nested.value_b.replaced 3"));
}
TEST_F(ProtoToArgsParserTest, NestedProtoParsingOverrideSkipped) {
using namespace protozero::test::protos::pbzero;
protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
msg->set_super_nested()->set_value_c(3);
auto binary_proto = msg.SerializeAsArray();
DescriptorPool pool;
auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
kTestMessagesDescriptor.size());
ProtoToArgsParser parser(pool);
ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
<< status.message();
parser.AddParsingOverrideForField(
"super_nested.value_c",
[](const protozero::Field& field, ProtoToArgsParser::Delegate&) {
static int val = 0;
++val;
EXPECT_EQ(1, val);
EXPECT_EQ(field.type(), protozero::proto_utils::ProtoWireType::kVarInt);
return std::nullopt;
});
status = parser.ParseMessage(
protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
".protozero.test.protos.NestedA", nullptr, *this);
EXPECT_TRUE(status.ok())
<< "InternProtoFieldsIntoArgsTable failed with error: "
<< status.message();
EXPECT_THAT(args(), testing::ElementsAre(
"super_nested.value_c super_nested.value_c 3"));
}
TEST_F(ProtoToArgsParserTest, LookingUpInternedStateParsingOverride) {
using namespace protozero::test::protos::pbzero;
// The test proto, we will use |value_c| as the source_location iid.
protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
msg->set_super_nested()->set_value_c(3);
auto binary_proto = msg.SerializeAsArray();
// The interned source location.
protozero::HeapBuffered<protos::pbzero::SourceLocation> src_loc{kChunkSize,
kChunkSize};
const uint64_t kIid = 3;
src_loc->set_iid(kIid);
src_loc->set_file_name("test_file_name");
// We need to update sequence_state to point to it.
auto binary_data = src_loc.SerializeAsArray();
std::unique_ptr<uint8_t[]> buffer(new uint8_t[binary_data.size()]);
for (size_t i = 0; i < binary_data.size(); ++i) {
buffer.get()[i] = binary_data[i];
}
TraceBlob blob =
TraceBlob::TakeOwnership(std::move(buffer), binary_data.size());
AddInternedSourceLocation(kIid, TraceBlobView(std::move(blob)));
DescriptorPool pool;
auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
kTestMessagesDescriptor.size());
ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
<< status.message();
ProtoToArgsParser parser(pool);
// Now we override the behaviour of |value_c| so we can expand the iid into
// multiple args rows.
parser.AddParsingOverrideForField(
"super_nested.value_c",
[](const protozero::Field& field,
ProtoToArgsParser::Delegate& delegate) -> std::optional<base::Status> {
auto* decoder = delegate.GetInternedMessage(
protos::pbzero::InternedData::kSourceLocations, field.as_uint64());
if (!decoder) {
// Lookup failed fall back on default behaviour.
return std::nullopt;
}
delegate.AddString(ProtoToArgsParser::Key("file_name"),
protozero::ConstChars{"file", 4});
delegate.AddInteger(ProtoToArgsParser::Key("line_number"), 2);
return base::OkStatus();
});
status = parser.ParseMessage(
protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
".protozero.test.protos.NestedA", nullptr, *this);
EXPECT_TRUE(status.ok())
<< "InternProtoFieldsIntoArgsTable failed with error: "
<< status.message();
EXPECT_THAT(args(), testing::ElementsAre("file_name file_name file",
"line_number line_number 2"));
}
TEST_F(ProtoToArgsParserTest, OverrideForType) {
using namespace protozero::test::protos::pbzero;
protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
msg->set_super_nested()->set_value_c(3);
auto binary_proto = msg.SerializeAsArray();
DescriptorPool pool;
auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
kTestMessagesDescriptor.size());
ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
<< status.message();
ProtoToArgsParser parser(pool);
parser.AddParsingOverrideForType(
".protozero.test.protos.NestedA.NestedB.NestedC",
[](ProtoToArgsParser::ScopedNestedKeyContext&,
const protozero::ConstBytes&, Delegate& delegate) {
delegate.AddInteger(ProtoToArgsParser::Key("arg"), 42);
return base::OkStatus();
});
status = parser.ParseMessage(
protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
".protozero.test.protos.NestedA", nullptr, *this);
EXPECT_TRUE(status.ok())
<< "InternProtoFieldsIntoArgsTable failed with error: "
<< status.message();
EXPECT_THAT(args(), testing::ElementsAre("arg arg 42"));
}
TEST_F(ProtoToArgsParserTest, FieldOverrideTakesPrecedence) {
using namespace protozero::test::protos::pbzero;
protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
msg->set_super_nested()->set_value_c(3);
auto binary_proto = msg.SerializeAsArray();
DescriptorPool pool;
auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
kTestMessagesDescriptor.size());
ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
<< status.message();
ProtoToArgsParser parser(pool);
parser.AddParsingOverrideForField(
"super_nested",
[](const protozero::Field&, ProtoToArgsParser::Delegate& writer) {
writer.AddString(ProtoToArgsParser::Key("arg"),
ToChars("override-for-field"));
return base::OkStatus();
});
parser.AddParsingOverrideForType(
".protozero.test.protos.NestedA.NestedB.NestedC",
[](ProtoToArgsParser::ScopedNestedKeyContext&,
const protozero::ConstBytes&, Delegate& delegate) {
delegate.AddString(ProtoToArgsParser::Key("arg"),
ToChars("override-for-type"));
return base::OkStatus();
});
status = parser.ParseMessage(
protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
".protozero.test.protos.NestedA", nullptr, *this);
EXPECT_TRUE(status.ok())
<< "InternProtoFieldsIntoArgsTable failed with error: "
<< status.message();
EXPECT_THAT(args(), testing::ElementsAre("arg arg override-for-field"));
}
TEST_F(ProtoToArgsParserTest, EmptyMessage) {
using namespace protozero::test::protos::pbzero;
protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
msg->set_super_nested();
auto binary_proto = msg.SerializeAsArray();
DescriptorPool pool;
auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
kTestMessagesDescriptor.size());
ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
<< status.message();
ProtoToArgsParser parser(pool);
status = parser.ParseMessage(
protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
".protozero.test.protos.NestedA", nullptr, *this);
EXPECT_TRUE(status.ok())
<< "InternProtoFieldsIntoArgsTable failed with error: "
<< status.message();
EXPECT_THAT(args(), testing::ElementsAre("super_nested super_nested [NULL]"));
}
TEST_F(ProtoToArgsParserTest, WidthAndSignednessOfScalars) {
using namespace protozero::test::protos::pbzero;
protozero::HeapBuffered<EveryField> msg{kChunkSize, kChunkSize};
// Set fields to values with the top bit set, and check that the parser
// retains the full value with the correct sign.
msg->set_field_int32(-0x80000000ll);
msg->set_field_sint32(-0x80000000ll);
msg->set_field_sfixed32(-0x80000000ll);
msg->set_field_uint32(0x80000000ull);
msg->set_field_fixed32(0x80000000ull);
msg->set_field_int64(-0x7FFFFFFFFFFFFFFFll - 1);
msg->set_field_sint64(-0x7FFFFFFFFFFFFFFFll - 1);
msg->set_field_sfixed64(-0x7FFFFFFFFFFFFFFFll - 1);
msg->set_field_uint64(0x8000000000000000ull);
msg->set_field_fixed64(0x8000000000000000ull);
auto binary_proto = msg.SerializeAsArray();
DescriptorPool pool;
auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
kTestMessagesDescriptor.size());
ProtoToArgsParser parser(pool);
ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
<< status.message();
status = parser.ParseMessage(
protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
".protozero.test.protos.EveryField", nullptr, *this);
EXPECT_TRUE(status.ok())
<< "InternProtoFieldsIntoArgsTable failed with error: "
<< status.message();
EXPECT_THAT(args(), testing::ElementsAre(
"field_int32 field_int32 -2147483648",
"field_sint32 field_sint32 -2147483648",
"field_sfixed32 field_sfixed32 -2147483648",
"field_uint32 field_uint32 2147483648",
"field_fixed32 field_fixed32 2147483648",
"field_int64 field_int64 -9223372036854775808",
"field_sint64 field_sint64 -9223372036854775808",
"field_sfixed64 field_sfixed64 -9223372036854775808",
"field_uint64 field_uint64 9223372036854775808",
"field_fixed64 field_fixed64 9223372036854775808"));
}
TEST_F(ProtoToArgsParserTest, PackedFields) {
using namespace protozero::test::protos::pbzero;
protozero::HeapBuffered<PackedRepeatedFields> msg{kChunkSize, kChunkSize};
protozero::PackedVarInt varint;
CreatedPackedVarint(varint, 0, std::numeric_limits<int32_t>::min(),
std::numeric_limits<int32_t>::max());
msg->set_field_int32(varint);
CreatedPackedVarint(varint, 0ll, std::numeric_limits<int64_t>::min(),
std::numeric_limits<int64_t>::max());
msg->set_field_int64(varint);
CreatedPackedVarint(varint, 0u, std::numeric_limits<uint32_t>::min(),
std::numeric_limits<uint32_t>::max());
msg->set_field_uint32(varint);
CreatedPackedVarint(varint, 0ull, std::numeric_limits<uint64_t>::min(),
std::numeric_limits<uint64_t>::max());
msg->set_field_uint64(varint);
CreatedPackedVarint(varint, BigEnum::BEGIN, BigEnum::END);
msg->set_big_enum(varint);
protozero::PackedFixedSizeInt<uint32_t> fixed32;
fixed32.Append(0);
fixed32.Append(std::numeric_limits<uint32_t>::min());
fixed32.Append(std::numeric_limits<uint32_t>::max());
msg->set_field_fixed32(fixed32);
protozero::PackedFixedSizeInt<int32_t> sfixed32;
sfixed32.Append(0);
sfixed32.Append(std::numeric_limits<int32_t>::min());
sfixed32.Append(std::numeric_limits<int32_t>::max());
msg->set_field_sfixed32(sfixed32);
protozero::PackedFixedSizeInt<float> pfloat;
pfloat.Append(0);
pfloat.Append(-4839.349f);
pfloat.Append(std::numeric_limits<float>::min());
pfloat.Append(std::numeric_limits<float>::max());
msg->set_field_float(pfloat);
protozero::PackedFixedSizeInt<uint64_t> fixed64;
fixed64.Append(0);
fixed64.Append(std::numeric_limits<uint64_t>::min());
fixed64.Append(std::numeric_limits<uint64_t>::max());
msg->set_field_fixed64(fixed64);
protozero::PackedFixedSizeInt<int64_t> sfixed64;
sfixed64.Append(0);
sfixed64.Append(std::numeric_limits<int64_t>::min());
sfixed64.Append(std::numeric_limits<int64_t>::max());
msg->set_field_sfixed64(sfixed64);
protozero::PackedFixedSizeInt<double> pdouble;
pdouble.Append(0);
pdouble.Append(-48948908.349);
pdouble.Append(std::numeric_limits<double>::min());
pdouble.Append(std::numeric_limits<double>::max());
msg->set_field_double(pdouble);
auto binary_proto = msg.SerializeAsArray();
DescriptorPool pool;
auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
kTestMessagesDescriptor.size());
ProtoToArgsParser parser(pool);
ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
<< status.message();
status = parser.ParseMessage(
protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
".protozero.test.protos.PackedRepeatedFields", nullptr, *this);
EXPECT_TRUE(status.ok()) << "ParseMessage failed with error: "
<< status.message();
EXPECT_THAT(
args(),
testing::ElementsAre(
"field_int32 field_int32[0] 0",
"field_int32 field_int32[1] -2147483648",
"field_int32 field_int32[2] 2147483647",
"field_int64 field_int64[0] 0",
"field_int64 field_int64[1] -9223372036854775808",
"field_int64 field_int64[2] 9223372036854775807",
"field_uint32 field_uint32[0] 0", "field_uint32 field_uint32[1] 0",
"field_uint32 field_uint32[2] 4294967295",
"field_uint64 field_uint64[0] 0", "field_uint64 field_uint64[1] 0",
"field_uint64 field_uint64[2] 18446744073709551615",
"big_enum big_enum[0] BEGIN", "big_enum big_enum[1] END",
"field_fixed32 field_fixed32[0] 0",
"field_fixed32 field_fixed32[1] 0",
"field_fixed32 field_fixed32[2] 4294967295",
"field_sfixed32 field_sfixed32[0] 0",
"field_sfixed32 field_sfixed32[1] -2147483648",
"field_sfixed32 field_sfixed32[2] 2147483647",
"field_float field_float[0] 0", "field_float field_float[1] -4839.35",
"field_float field_float[2] 1.17549e-38",
"field_float field_float[3] 3.40282e+38",
"field_fixed64 field_fixed64[0] 0",
"field_fixed64 field_fixed64[1] 0",
"field_fixed64 field_fixed64[2] 18446744073709551615",
"field_sfixed64 field_sfixed64[0] 0",
"field_sfixed64 field_sfixed64[1] -9223372036854775808",
"field_sfixed64 field_sfixed64[2] 9223372036854775807",
"field_double field_double[0] 0",
"field_double field_double[1] -4.89489e+07",
"field_double field_double[2] 2.22507e-308",
"field_double field_double[3] 1.79769e+308"));
}
} // namespace
} // namespace util
} // namespace trace_processor
} // namespace perfetto