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