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