blob: e3f3380c88b1d0facc1ec64c8c0968353a3a0b32 [file] [log] [blame]
Alexander Timin97d87852021-05-17 18:01:33 +00001/*
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/debug_annotation_parser.h"
18
19#include "perfetto/ext/base/string_view.h"
20#include "perfetto/protozero/scattered_heap_buffer.h"
21#include "protos/perfetto/common/descriptor.pbzero.h"
22#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
23#include "protos/perfetto/trace/track_event/source_location.pbzero.h"
24#include "src/protozero/test/example_proto/test_messages.pbzero.h"
25#include "src/trace_processor/test_messages.descriptor.h"
26#include "src/trace_processor/util/interned_message_view.h"
27#include "src/trace_processor/util/proto_to_args_parser.h"
28#include "src/trace_processor/util/trace_blob_view.h"
29#include "test/gtest_and_gmock.h"
30
31#include <sstream>
32
33namespace perfetto {
34namespace trace_processor {
35namespace util {
36namespace {
37
38base::Status ParseDebugAnnotation(
39 DebugAnnotationParser& parser,
40 protozero::HeapBuffered<protos::pbzero::DebugAnnotation>& msg,
41 ProtoToArgsParser::Delegate& delegate) {
42 std::vector<uint8_t> data = msg.SerializeAsArray();
43 return parser.Parse(protozero::ConstBytes{data.data(), data.size()},
44 delegate);
45}
46
47class DebugAnnotationParserTest : public ::testing::Test,
48 public ProtoToArgsParser::Delegate {
49 protected:
50 DebugAnnotationParserTest() {}
51
52 const std::vector<std::string>& args() const { return args_; }
53
54 private:
55 using Key = ProtoToArgsParser::Key;
56
57 void AddInteger(const Key& key, int64_t value) override {
58 std::stringstream ss;
59 ss << key.flat_key << " " << key.key << " " << value;
60 args_.push_back(ss.str());
61 }
62
63 void AddUnsignedInteger(const Key& key, uint64_t value) override {
64 std::stringstream ss;
65 ss << key.flat_key << " " << key.key << " " << value;
66 args_.push_back(ss.str());
67 }
68
69 void AddString(const Key& key, const protozero::ConstChars& value) override {
70 std::stringstream ss;
71 ss << key.flat_key << " " << key.key << " " << value.ToStdString();
72 args_.push_back(ss.str());
73 }
74
75 void AddDouble(const Key& key, double value) override {
76 std::stringstream ss;
77 ss << key.flat_key << " " << key.key << " " << value;
78 args_.push_back(ss.str());
79 }
80
81 void AddPointer(const Key& key, const void* value) override {
82 std::stringstream ss;
83 ss << key.flat_key << " " << key.key << " " << std::hex
84 << reinterpret_cast<uintptr_t>(value) << std::dec;
85 args_.push_back(ss.str());
86 }
87
88 void AddBoolean(const Key& key, bool value) override {
89 std::stringstream ss;
90 ss << key.flat_key << " " << key.key << " " << (value ? "true" : "false");
91 args_.push_back(ss.str());
92 }
93
94 bool AddJson(const Key& key, const protozero::ConstChars& value) override {
95 std::stringstream ss;
96 ss << key.flat_key << " " << key.key << " " << std::hex
97 << value.ToStdString() << std::dec;
98 args_.push_back(ss.str());
99 return true;
100 }
101
102 size_t GetArrayEntryIndex(const std::string& array_key) final {
103 return array_indices_[array_key];
104 }
105
106 size_t IncrementArrayEntryIndex(const std::string& array_key) final {
107 return ++array_indices_[array_key];
108 }
109
110 InternedMessageView* GetInternedMessageView(uint32_t, uint64_t) override {
111 return nullptr;
112 }
113
114 std::vector<std::string> args_;
115 std::map<std::string, size_t> array_indices_;
116};
117
118// This test checks that in when an array is nested inside a dict which is
119// nested inside an array which is nested inside a dict, flat keys and non-flat
120// keys are parsed correctly.
121TEST_F(DebugAnnotationParserTest, DeeplyNestedDictsAndArrays) {
122 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
123
124 msg->set_name("root");
125 auto* dict1 = msg->add_dict_entries();
126 dict1->set_name("k1");
127 auto* array1 = dict1->add_array_values();
128 auto* dict2 = array1->add_dict_entries();
129 dict2->set_name("k2");
130 auto* array2 = dict2->add_array_values();
131 array2->set_int_value(42);
132
133 DescriptorPool pool;
134 auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
135 kTestMessagesDescriptor.size());
136 EXPECT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
137 << status.message();
138
139 ProtoToArgsParser args_parser(pool);
140 DebugAnnotationParser parser(args_parser);
141
142 status = ParseDebugAnnotation(parser, msg, *this);
143 EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
144 << status.message();
145
146 EXPECT_THAT(args(), testing::ElementsAre("root.k1.k2 root.k1[0].k2[0] 42"));
147}
148
149// This test checks that array indexes are correctly merged across messages.
150TEST_F(DebugAnnotationParserTest, MergeArrays) {
151 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg1;
152 msg1->set_name("root");
153 auto* item1 = msg1->add_array_values();
154 item1->set_int_value(1);
155
156 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg2;
157 msg2->set_name("root");
158 auto* item2 = msg1->add_array_values();
159 item2->set_int_value(2);
160
161 DescriptorPool pool;
162 ProtoToArgsParser args_parser(pool);
163 DebugAnnotationParser parser(args_parser);
164
165 base::Status status = ParseDebugAnnotation(parser, msg1, *this);
166 EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
167 << status.message();
168
169 status = ParseDebugAnnotation(parser, msg2, *this);
170 EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
171 << status.message();
172
173 EXPECT_THAT(args(), testing::ElementsAre("root root[0] 1", "root root[1] 2"));
174}
175
176// This test checks that nested empty dictionaries / arrays do not cause array
177// index to be incremented.
178TEST_F(DebugAnnotationParserTest, EmptyArrayIndexIsSkipped) {
179 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
180 msg->set_name("root");
181
182 msg->add_array_values()->set_int_value(1);
183
184 // Empty item.
185 msg->add_array_values();
186
187 msg->add_array_values()->set_int_value(3);
188
189 // Empty dict.
190 msg->add_array_values()->add_dict_entries()->set_name("key1");
191
192 auto* nested_dict_entry = msg->add_array_values()->add_dict_entries();
193 nested_dict_entry->set_name("key2");
194 nested_dict_entry->set_string_value("value");
195
196 msg->add_array_values()->set_int_value(5);
197
198 DescriptorPool pool;
199 ProtoToArgsParser args_parser(pool);
200 DebugAnnotationParser parser(args_parser);
201
202 base::Status status = ParseDebugAnnotation(parser, msg, *this);
203 EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
204 << status.message();
205
206 EXPECT_THAT(args(), testing::ElementsAre("root root[0] 1", "root root[1] 3",
207 "root.key2 root[3].key2 value",
208 "root root[4] 5"));
209}
210
211TEST_F(DebugAnnotationParserTest, NestedArrays) {
212 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
213 msg->set_name("root");
214 auto* item1 = msg->add_array_values();
215 item1->add_array_values()->set_int_value(1);
216 item1->add_array_values()->set_int_value(2);
217 auto* item2 = msg->add_array_values();
218 item2->add_array_values()->set_int_value(3);
219 item2->add_array_values()->set_int_value(4);
220
221 DescriptorPool pool;
222 ProtoToArgsParser args_parser(pool);
223 DebugAnnotationParser parser(args_parser);
224
225 base::Status status = ParseDebugAnnotation(parser, msg, *this);
226 EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
227 << status.message();
228
229 EXPECT_THAT(args(),
230 testing::ElementsAre("root root[0][0] 1", "root root[0][1] 2",
231 "root root[1][0] 3", "root root[1][1] 4"));
232}
233
234} // namespace
235} // namespace util
236} // namespace trace_processor
237} // namespace perfetto