• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/util/proto_to_args_parser.h"
18 
19 #include "perfetto/ext/base/string_view.h"
20 #include "perfetto/protozero/packed_repeated_fields.h"
21 #include "perfetto/protozero/scattered_heap_buffer.h"
22 #include "perfetto/trace_processor/trace_blob.h"
23 #include "perfetto/trace_processor/trace_blob_view.h"
24 #include "protos/perfetto/common/descriptor.pbzero.h"
25 #include "protos/perfetto/trace/track_event/source_location.pbzero.h"
26 #include "src/protozero/test/example_proto/test_messages.pbzero.h"
27 #include "src/trace_processor/test_messages.descriptor.h"
28 #include "src/trace_processor/util/interned_message_view.h"
29 #include "test/gtest_and_gmock.h"
30 
31 #include <cstdint>
32 #include <limits>
33 #include <sstream>
34 
35 namespace perfetto {
36 namespace trace_processor {
37 namespace util {
38 namespace {
39 
40 constexpr size_t kChunkSize = 42;
41 
ToChars(const char * str)42 protozero::ConstChars ToChars(const char* str) {
43   return protozero::ConstChars{str, strlen(str)};
44 }
45 
46 class ProtoToArgsParserTest : public ::testing::Test,
47                               public ProtoToArgsParser::Delegate {
48  protected:
ProtoToArgsParserTest()49   ProtoToArgsParserTest() {}
50 
args() const51   const std::vector<std::string>& args() const { return args_; }
52 
AddInternedSourceLocation(uint64_t iid,TraceBlobView data)53   void AddInternedSourceLocation(uint64_t iid, TraceBlobView data) {
54     interned_source_locations_[iid] = std::unique_ptr<InternedMessageView>(
55         new InternedMessageView(std::move(data)));
56   }
57 
58   template <typename T, typename... Ts>
CreatedPackedVarint(protozero::PackedVarInt & var,T p,Ts...ps)59   void CreatedPackedVarint(protozero::PackedVarInt& var, T p, Ts... ps) {
60     var.Reset();
61     std::array<T, sizeof...(ps) + 1> list = {p, ps...};
62     for (T v : list) {
63       var.Append(v);
64     }
65   }
66 
67  private:
68   using Key = ProtoToArgsParser::Key;
69 
AddInteger(const Key & key,int64_t value)70   void AddInteger(const Key& key, int64_t value) override {
71     std::stringstream ss;
72     ss << key.flat_key << " " << key.key << " " << value;
73     args_.push_back(ss.str());
74   }
75 
AddUnsignedInteger(const Key & key,uint64_t value)76   void AddUnsignedInteger(const Key& key, uint64_t value) override {
77     std::stringstream ss;
78     ss << key.flat_key << " " << key.key << " " << value;
79     args_.push_back(ss.str());
80   }
81 
AddString(const Key & key,const protozero::ConstChars & value)82   void AddString(const Key& key, const protozero::ConstChars& value) override {
83     std::stringstream ss;
84     ss << key.flat_key << " " << key.key << " " << value.ToStdString();
85     args_.push_back(ss.str());
86   }
87 
AddString(const Key & key,const std::string & value)88   void AddString(const Key& key, const std::string& value) override {
89     std::stringstream ss;
90     ss << key.flat_key << " " << key.key << " " << value;
91     args_.push_back(ss.str());
92   }
93 
AddDouble(const Key & key,double value)94   void AddDouble(const Key& key, double value) override {
95     std::stringstream ss;
96     ss << key.flat_key << " " << key.key << " " << value;
97     args_.push_back(ss.str());
98   }
99 
AddPointer(const Key & key,const void * value)100   void AddPointer(const Key& key, const void* value) override {
101     std::stringstream ss;
102     ss << key.flat_key << " " << key.key << " " << std::hex
103        << reinterpret_cast<uintptr_t>(value) << std::dec;
104     args_.push_back(ss.str());
105   }
106 
AddBoolean(const Key & key,bool value)107   void AddBoolean(const Key& key, bool value) override {
108     std::stringstream ss;
109     ss << key.flat_key << " " << key.key << " " << (value ? "true" : "false");
110     args_.push_back(ss.str());
111   }
112 
AddJson(const Key & key,const protozero::ConstChars & value)113   bool AddJson(const Key& key, const protozero::ConstChars& value) override {
114     std::stringstream ss;
115     ss << key.flat_key << " " << key.key << " " << std::hex
116        << value.ToStdString() << std::dec;
117     args_.push_back(ss.str());
118     return true;
119   }
120 
AddNull(const Key & key)121   void AddNull(const Key& key) override {
122     std::stringstream ss;
123     ss << key.flat_key << " " << key.key << " [NULL]";
124     args_.push_back(ss.str());
125   }
126 
GetArrayEntryIndex(const std::string &)127   size_t GetArrayEntryIndex(const std::string&) final { return 0; }
128 
IncrementArrayEntryIndex(const std::string &)129   size_t IncrementArrayEntryIndex(const std::string&) final { return 0; }
130 
GetInternedMessageView(uint32_t field_id,uint64_t iid)131   InternedMessageView* GetInternedMessageView(uint32_t field_id,
132                                               uint64_t iid) override {
133     if (field_id != protos::pbzero::InternedData::kSourceLocationsFieldNumber)
134       return nullptr;
135     return interned_source_locations_.at(iid).get();
136   }
137 
seq_state()138   PacketSequenceStateGeneration* seq_state() final { return nullptr; }
139 
140   std::vector<std::string> args_;
141   std::map<uint64_t, std::unique_ptr<InternedMessageView>>
142       interned_source_locations_;
143 };
144 
TEST_F(ProtoToArgsParserTest,EnsureTestMessageProtoParses)145 TEST_F(ProtoToArgsParserTest, EnsureTestMessageProtoParses) {
146   DescriptorPool pool;
147   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
148                                               kTestMessagesDescriptor.size());
149   ProtoToArgsParser parser(pool);
150   EXPECT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
151                            << status.message();
152 }
153 
TEST_F(ProtoToArgsParserTest,BasicSingleLayerProto)154 TEST_F(ProtoToArgsParserTest, BasicSingleLayerProto) {
155   using namespace protozero::test::protos::pbzero;
156   protozero::HeapBuffered<EveryField> msg{kChunkSize, kChunkSize};
157   msg->set_field_int32(-1);
158   msg->set_field_int64(-333123456789ll);
159   msg->set_field_uint32(600);
160   msg->set_field_uint64(333123456789ll);
161   msg->set_field_sint32(-5);
162   msg->set_field_sint64(-9000);
163   msg->set_field_fixed32(12345);
164   msg->set_field_fixed64(444123450000ll);
165   msg->set_field_sfixed32(-69999);
166   msg->set_field_sfixed64(-200);
167   msg->set_field_double(0.5555);
168   msg->set_field_bool(true);
169   msg->set_small_enum(SmallEnum::TO_BE);
170   msg->set_signed_enum(SignedEnum::NEGATIVE);
171   msg->set_big_enum(BigEnum::BEGIN);
172   msg->set_nested_enum(EveryField::PONG);
173   msg->set_field_float(3.14f);
174   msg->set_field_string("FizzBuzz");
175   msg->add_repeated_int32(1);
176   msg->add_repeated_int32(-1);
177   msg->add_repeated_int32(100);
178   msg->add_repeated_int32(2000000);
179 
180   auto binary_proto = msg.SerializeAsArray();
181 
182   DescriptorPool pool;
183   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
184                                               kTestMessagesDescriptor.size());
185   ProtoToArgsParser parser(pool);
186   ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
187                            << status.message();
188 
189   status = parser.ParseMessage(
190       protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
191       ".protozero.test.protos.EveryField", nullptr, *this);
192 
193   EXPECT_TRUE(status.ok())
194       << "InternProtoFieldsIntoArgsTable failed with error: "
195       << status.message();
196 
197   EXPECT_THAT(
198       args(),
199       testing::ElementsAre(
200           "field_int32 field_int32 -1", "field_int64 field_int64 -333123456789",
201           "field_uint32 field_uint32 600",
202           "field_uint64 field_uint64 333123456789",
203           "field_sint32 field_sint32 -5", "field_sint64 field_sint64 -9000",
204           "field_fixed32 field_fixed32 12345",
205           "field_fixed64 field_fixed64 444123450000",
206           "field_sfixed32 field_sfixed32 -69999",
207           "field_sfixed64 field_sfixed64 -200",
208           "field_double field_double 0.5555", "field_bool field_bool true",
209           "small_enum small_enum TO_BE", "signed_enum signed_enum NEGATIVE",
210           "big_enum big_enum BEGIN", "nested_enum nested_enum PONG",
211           "field_float field_float 3.14", "field_string field_string FizzBuzz",
212           "repeated_int32 repeated_int32[0] 1",
213           "repeated_int32 repeated_int32[1] -1",
214           "repeated_int32 repeated_int32[2] 100",
215           "repeated_int32 repeated_int32[3] 2000000"));
216 }
217 
TEST_F(ProtoToArgsParserTest,NestedProto)218 TEST_F(ProtoToArgsParserTest, NestedProto) {
219   using namespace protozero::test::protos::pbzero;
220   protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
221   msg->set_super_nested()->set_value_c(3);
222 
223   auto binary_proto = msg.SerializeAsArray();
224 
225   DescriptorPool pool;
226   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
227                                               kTestMessagesDescriptor.size());
228   ProtoToArgsParser parser(pool);
229   ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
230                            << status.message();
231 
232   status = parser.ParseMessage(
233       protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
234       ".protozero.test.protos.NestedA", nullptr, *this);
235   EXPECT_TRUE(status.ok())
236       << "InternProtoFieldsIntoArgsTable failed with error: "
237       << status.message();
238   EXPECT_THAT(args(), testing::ElementsAre(
239                           "super_nested.value_c super_nested.value_c 3"));
240 }
241 
TEST_F(ProtoToArgsParserTest,CamelCaseFieldsProto)242 TEST_F(ProtoToArgsParserTest, CamelCaseFieldsProto) {
243   using namespace protozero::test::protos::pbzero;
244   protozero::HeapBuffered<CamelCaseFields> msg{kChunkSize, kChunkSize};
245   msg->set_barbaz(true);
246   msg->set_moomoo(true);
247   msg->set___bigbang(true);
248 
249   auto binary_proto = msg.SerializeAsArray();
250 
251   DescriptorPool pool;
252   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
253                                               kTestMessagesDescriptor.size());
254   ProtoToArgsParser parser(pool);
255   ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
256                            << status.message();
257 
258   status = parser.ParseMessage(
259       protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
260       ".protozero.test.protos.CamelCaseFields", nullptr, *this);
261   EXPECT_TRUE(status.ok())
262       << "InternProtoFieldsIntoArgsTable failed with error: "
263       << status.message();
264   EXPECT_THAT(args(),
265               testing::ElementsAre("barBaz barBaz true", "MooMoo MooMoo true",
266                                    "__bigBang __bigBang true"));
267 }
268 
TEST_F(ProtoToArgsParserTest,NestedProtoParsingOverrideHandled)269 TEST_F(ProtoToArgsParserTest, NestedProtoParsingOverrideHandled) {
270   using namespace protozero::test::protos::pbzero;
271   protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
272   msg->set_super_nested()->set_value_c(3);
273 
274   auto binary_proto = msg.SerializeAsArray();
275 
276   DescriptorPool pool;
277   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
278                                               kTestMessagesDescriptor.size());
279   ProtoToArgsParser parser(pool);
280   ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
281                            << status.message();
282 
283   parser.AddParsingOverrideForField(
284       "super_nested.value_c",
285       [](const protozero::Field& field, ProtoToArgsParser::Delegate& writer) {
286         EXPECT_EQ(field.type(), protozero::proto_utils::ProtoWireType::kVarInt);
287         std::string key = "super_nested.value_b.replaced";
288         writer.AddInteger({key, key}, field.as_int32());
289         // We've handled this field by adding the desired args.
290         return base::OkStatus();
291       });
292 
293   status = parser.ParseMessage(
294       protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
295       ".protozero.test.protos.NestedA", nullptr, *this);
296   EXPECT_TRUE(status.ok())
297       << "InternProtoFieldsIntoArgsTable failed with error: "
298       << status.message();
299   EXPECT_THAT(
300       args(),
301       testing::ElementsAre(
302           "super_nested.value_b.replaced super_nested.value_b.replaced 3"));
303 }
304 
TEST_F(ProtoToArgsParserTest,NestedProtoParsingOverrideSkipped)305 TEST_F(ProtoToArgsParserTest, NestedProtoParsingOverrideSkipped) {
306   using namespace protozero::test::protos::pbzero;
307   protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
308   msg->set_super_nested()->set_value_c(3);
309 
310   auto binary_proto = msg.SerializeAsArray();
311 
312   DescriptorPool pool;
313   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
314                                               kTestMessagesDescriptor.size());
315   ProtoToArgsParser parser(pool);
316   ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
317                            << status.message();
318 
319   parser.AddParsingOverrideForField(
320       "super_nested.value_c",
321       [](const protozero::Field& field, ProtoToArgsParser::Delegate&) {
322         static int val = 0;
323         ++val;
324         EXPECT_EQ(1, val);
325         EXPECT_EQ(field.type(), protozero::proto_utils::ProtoWireType::kVarInt);
326         return std::nullopt;
327       });
328 
329   status = parser.ParseMessage(
330       protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
331       ".protozero.test.protos.NestedA", nullptr, *this);
332   EXPECT_TRUE(status.ok())
333       << "InternProtoFieldsIntoArgsTable failed with error: "
334       << status.message();
335   EXPECT_THAT(args(), testing::ElementsAre(
336                           "super_nested.value_c super_nested.value_c 3"));
337 }
338 
TEST_F(ProtoToArgsParserTest,LookingUpInternedStateParsingOverride)339 TEST_F(ProtoToArgsParserTest, LookingUpInternedStateParsingOverride) {
340   using namespace protozero::test::protos::pbzero;
341   // The test proto, we will use |value_c| as the source_location iid.
342   protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
343   msg->set_super_nested()->set_value_c(3);
344   auto binary_proto = msg.SerializeAsArray();
345 
346   // The interned source location.
347   protozero::HeapBuffered<protos::pbzero::SourceLocation> src_loc{kChunkSize,
348                                                                   kChunkSize};
349   const uint64_t kIid = 3;
350   src_loc->set_iid(kIid);
351   src_loc->set_file_name("test_file_name");
352   // We need to update sequence_state to point to it.
353   auto binary_data = src_loc.SerializeAsArray();
354   std::unique_ptr<uint8_t[]> buffer(new uint8_t[binary_data.size()]);
355   for (size_t i = 0; i < binary_data.size(); ++i) {
356     buffer.get()[i] = binary_data[i];
357   }
358   TraceBlob blob =
359       TraceBlob::TakeOwnership(std::move(buffer), binary_data.size());
360   AddInternedSourceLocation(kIid, TraceBlobView(std::move(blob)));
361 
362   DescriptorPool pool;
363   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
364                                               kTestMessagesDescriptor.size());
365   ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
366                            << status.message();
367 
368   ProtoToArgsParser parser(pool);
369   // Now we override the behaviour of |value_c| so we can expand the iid into
370   // multiple args rows.
371   parser.AddParsingOverrideForField(
372       "super_nested.value_c",
373       [](const protozero::Field& field,
374          ProtoToArgsParser::Delegate& delegate) -> std::optional<base::Status> {
375         auto* decoder = delegate.GetInternedMessage(
376             protos::pbzero::InternedData::kSourceLocations, field.as_uint64());
377         if (!decoder) {
378           // Lookup failed fall back on default behaviour.
379           return std::nullopt;
380         }
381         delegate.AddString(ProtoToArgsParser::Key("file_name"),
382                            protozero::ConstChars{"file", 4});
383         delegate.AddInteger(ProtoToArgsParser::Key("line_number"), 2);
384         return base::OkStatus();
385       });
386 
387   status = parser.ParseMessage(
388       protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
389       ".protozero.test.protos.NestedA", nullptr, *this);
390   EXPECT_TRUE(status.ok())
391       << "InternProtoFieldsIntoArgsTable failed with error: "
392       << status.message();
393   EXPECT_THAT(args(), testing::ElementsAre("file_name file_name file",
394                                            "line_number line_number 2"));
395 }
396 
TEST_F(ProtoToArgsParserTest,OverrideForType)397 TEST_F(ProtoToArgsParserTest, OverrideForType) {
398   using namespace protozero::test::protos::pbzero;
399   protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
400   msg->set_super_nested()->set_value_c(3);
401 
402   auto binary_proto = msg.SerializeAsArray();
403 
404   DescriptorPool pool;
405   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
406                                               kTestMessagesDescriptor.size());
407   ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
408                            << status.message();
409 
410   ProtoToArgsParser parser(pool);
411 
412   parser.AddParsingOverrideForType(
413       ".protozero.test.protos.NestedA.NestedB.NestedC",
414       [](ProtoToArgsParser::ScopedNestedKeyContext&,
415          const protozero::ConstBytes&, Delegate& delegate) {
416         delegate.AddInteger(ProtoToArgsParser::Key("arg"), 42);
417         return base::OkStatus();
418       });
419 
420   status = parser.ParseMessage(
421       protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
422       ".protozero.test.protos.NestedA", nullptr, *this);
423   EXPECT_TRUE(status.ok())
424       << "InternProtoFieldsIntoArgsTable failed with error: "
425       << status.message();
426   EXPECT_THAT(args(), testing::ElementsAre("arg arg 42"));
427 }
428 
TEST_F(ProtoToArgsParserTest,FieldOverrideTakesPrecedence)429 TEST_F(ProtoToArgsParserTest, FieldOverrideTakesPrecedence) {
430   using namespace protozero::test::protos::pbzero;
431   protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
432   msg->set_super_nested()->set_value_c(3);
433 
434   auto binary_proto = msg.SerializeAsArray();
435 
436   DescriptorPool pool;
437   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
438                                               kTestMessagesDescriptor.size());
439   ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
440                            << status.message();
441 
442   ProtoToArgsParser parser(pool);
443 
444   parser.AddParsingOverrideForField(
445       "super_nested",
446       [](const protozero::Field&, ProtoToArgsParser::Delegate& writer) {
447         writer.AddString(ProtoToArgsParser::Key("arg"),
448                          ToChars("override-for-field"));
449         return base::OkStatus();
450       });
451 
452   parser.AddParsingOverrideForType(
453       ".protozero.test.protos.NestedA.NestedB.NestedC",
454       [](ProtoToArgsParser::ScopedNestedKeyContext&,
455          const protozero::ConstBytes&, Delegate& delegate) {
456         delegate.AddString(ProtoToArgsParser::Key("arg"),
457                            ToChars("override-for-type"));
458         return base::OkStatus();
459       });
460 
461   status = parser.ParseMessage(
462       protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
463       ".protozero.test.protos.NestedA", nullptr, *this);
464   EXPECT_TRUE(status.ok())
465       << "InternProtoFieldsIntoArgsTable failed with error: "
466       << status.message();
467   EXPECT_THAT(args(), testing::ElementsAre("arg arg override-for-field"));
468 }
469 
TEST_F(ProtoToArgsParserTest,EmptyMessage)470 TEST_F(ProtoToArgsParserTest, EmptyMessage) {
471   using namespace protozero::test::protos::pbzero;
472   protozero::HeapBuffered<NestedA> msg{kChunkSize, kChunkSize};
473   msg->set_super_nested();
474 
475   auto binary_proto = msg.SerializeAsArray();
476 
477   DescriptorPool pool;
478   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
479                                               kTestMessagesDescriptor.size());
480   ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
481                            << status.message();
482 
483   ProtoToArgsParser parser(pool);
484   status = parser.ParseMessage(
485       protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
486       ".protozero.test.protos.NestedA", nullptr, *this);
487   EXPECT_TRUE(status.ok())
488       << "InternProtoFieldsIntoArgsTable failed with error: "
489       << status.message();
490   EXPECT_THAT(args(), testing::ElementsAre("super_nested super_nested [NULL]"));
491 }
492 
TEST_F(ProtoToArgsParserTest,WidthAndSignednessOfScalars)493 TEST_F(ProtoToArgsParserTest, WidthAndSignednessOfScalars) {
494   using namespace protozero::test::protos::pbzero;
495   protozero::HeapBuffered<EveryField> msg{kChunkSize, kChunkSize};
496 
497   // Set fields to values with the top bit set, and check that the parser
498   // retains the full value with the correct sign.
499   msg->set_field_int32(-0x80000000ll);
500   msg->set_field_sint32(-0x80000000ll);
501   msg->set_field_sfixed32(-0x80000000ll);
502 
503   msg->set_field_uint32(0x80000000ull);
504   msg->set_field_fixed32(0x80000000ull);
505 
506   msg->set_field_int64(-0x7FFFFFFFFFFFFFFFll - 1);
507   msg->set_field_sint64(-0x7FFFFFFFFFFFFFFFll - 1);
508   msg->set_field_sfixed64(-0x7FFFFFFFFFFFFFFFll - 1);
509 
510   msg->set_field_uint64(0x8000000000000000ull);
511   msg->set_field_fixed64(0x8000000000000000ull);
512 
513   auto binary_proto = msg.SerializeAsArray();
514 
515   DescriptorPool pool;
516   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
517                                               kTestMessagesDescriptor.size());
518   ProtoToArgsParser parser(pool);
519   ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
520                            << status.message();
521 
522   status = parser.ParseMessage(
523       protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
524       ".protozero.test.protos.EveryField", nullptr, *this);
525 
526   EXPECT_TRUE(status.ok())
527       << "InternProtoFieldsIntoArgsTable failed with error: "
528       << status.message();
529 
530   EXPECT_THAT(args(), testing::ElementsAre(
531                           "field_int32 field_int32 -2147483648",
532                           "field_sint32 field_sint32 -2147483648",
533                           "field_sfixed32 field_sfixed32 -2147483648",
534                           "field_uint32 field_uint32 2147483648",
535                           "field_fixed32 field_fixed32 2147483648",
536                           "field_int64 field_int64 -9223372036854775808",
537                           "field_sint64 field_sint64 -9223372036854775808",
538                           "field_sfixed64 field_sfixed64 -9223372036854775808",
539                           "field_uint64 field_uint64 9223372036854775808",
540                           "field_fixed64 field_fixed64 9223372036854775808"));
541 }
542 
TEST_F(ProtoToArgsParserTest,PackedFields)543 TEST_F(ProtoToArgsParserTest, PackedFields) {
544   using namespace protozero::test::protos::pbzero;
545   protozero::HeapBuffered<PackedRepeatedFields> msg{kChunkSize, kChunkSize};
546 
547   protozero::PackedVarInt varint;
548   CreatedPackedVarint(varint, 0, std::numeric_limits<int32_t>::min(),
549                       std::numeric_limits<int32_t>::max());
550   msg->set_field_int32(varint);
551 
552   CreatedPackedVarint(varint, 0ll, std::numeric_limits<int64_t>::min(),
553                       std::numeric_limits<int64_t>::max());
554   msg->set_field_int64(varint);
555 
556   CreatedPackedVarint(varint, 0u, std::numeric_limits<uint32_t>::min(),
557                       std::numeric_limits<uint32_t>::max());
558   msg->set_field_uint32(varint);
559 
560   CreatedPackedVarint(varint, 0ull, std::numeric_limits<uint64_t>::min(),
561                       std::numeric_limits<uint64_t>::max());
562   msg->set_field_uint64(varint);
563 
564   CreatedPackedVarint(varint, BigEnum::BEGIN, BigEnum::END);
565   msg->set_big_enum(varint);
566 
567   protozero::PackedFixedSizeInt<uint32_t> fixed32;
568   fixed32.Append(0);
569   fixed32.Append(std::numeric_limits<uint32_t>::min());
570   fixed32.Append(std::numeric_limits<uint32_t>::max());
571   msg->set_field_fixed32(fixed32);
572 
573   protozero::PackedFixedSizeInt<int32_t> sfixed32;
574   sfixed32.Append(0);
575   sfixed32.Append(std::numeric_limits<int32_t>::min());
576   sfixed32.Append(std::numeric_limits<int32_t>::max());
577   msg->set_field_sfixed32(sfixed32);
578 
579   protozero::PackedFixedSizeInt<float> pfloat;
580   pfloat.Append(0);
581   pfloat.Append(-4839.349f);
582   pfloat.Append(std::numeric_limits<float>::min());
583   pfloat.Append(std::numeric_limits<float>::max());
584   msg->set_field_float(pfloat);
585 
586   protozero::PackedFixedSizeInt<uint64_t> fixed64;
587   fixed64.Append(0);
588   fixed64.Append(std::numeric_limits<uint64_t>::min());
589   fixed64.Append(std::numeric_limits<uint64_t>::max());
590   msg->set_field_fixed64(fixed64);
591 
592   protozero::PackedFixedSizeInt<int64_t> sfixed64;
593   sfixed64.Append(0);
594   sfixed64.Append(std::numeric_limits<int64_t>::min());
595   sfixed64.Append(std::numeric_limits<int64_t>::max());
596   msg->set_field_sfixed64(sfixed64);
597 
598   protozero::PackedFixedSizeInt<double> pdouble;
599   pdouble.Append(0);
600   pdouble.Append(-48948908.349);
601   pdouble.Append(std::numeric_limits<double>::min());
602   pdouble.Append(std::numeric_limits<double>::max());
603   msg->set_field_double(pdouble);
604 
605   auto binary_proto = msg.SerializeAsArray();
606 
607   DescriptorPool pool;
608   auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
609                                               kTestMessagesDescriptor.size());
610   ProtoToArgsParser parser(pool);
611   ASSERT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
612                            << status.message();
613 
614   status = parser.ParseMessage(
615       protozero::ConstBytes{binary_proto.data(), binary_proto.size()},
616       ".protozero.test.protos.PackedRepeatedFields", nullptr, *this);
617 
618   EXPECT_TRUE(status.ok()) << "ParseMessage failed with error: "
619                            << status.message();
620 
621   EXPECT_THAT(
622       args(),
623       testing::ElementsAre(
624           "field_int32 field_int32[0] 0",
625           "field_int32 field_int32[1] -2147483648",
626           "field_int32 field_int32[2] 2147483647",
627           "field_int64 field_int64[0] 0",
628           "field_int64 field_int64[1] -9223372036854775808",
629           "field_int64 field_int64[2] 9223372036854775807",
630           "field_uint32 field_uint32[0] 0", "field_uint32 field_uint32[1] 0",
631           "field_uint32 field_uint32[2] 4294967295",
632           "field_uint64 field_uint64[0] 0", "field_uint64 field_uint64[1] 0",
633           "field_uint64 field_uint64[2] 18446744073709551615",
634           "big_enum big_enum[0] BEGIN", "big_enum big_enum[1] END",
635           "field_fixed32 field_fixed32[0] 0",
636           "field_fixed32 field_fixed32[1] 0",
637           "field_fixed32 field_fixed32[2] 4294967295",
638           "field_sfixed32 field_sfixed32[0] 0",
639           "field_sfixed32 field_sfixed32[1] -2147483648",
640           "field_sfixed32 field_sfixed32[2] 2147483647",
641           "field_float field_float[0] 0", "field_float field_float[1] -4839.35",
642           "field_float field_float[2] 1.17549e-38",
643           "field_float field_float[3] 3.40282e+38",
644           "field_fixed64 field_fixed64[0] 0",
645           "field_fixed64 field_fixed64[1] 0",
646           "field_fixed64 field_fixed64[2] 18446744073709551615",
647           "field_sfixed64 field_sfixed64[0] 0",
648           "field_sfixed64 field_sfixed64[1] -9223372036854775808",
649           "field_sfixed64 field_sfixed64[2] 9223372036854775807",
650           "field_double field_double[0] 0",
651           "field_double field_double[1] -4.89489e+07",
652           "field_double field_double[2] 2.22507e-308",
653           "field_double field_double[3] 1.79769e+308"));
654 }
655 
656 }  // namespace
657 }  // namespace util
658 }  // namespace trace_processor
659 }  // namespace perfetto
660