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