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