1 /*
2 * Copyright (C) 2023 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 #ifndef SRC_SHARED_LIB_TEST_UTILS_H_
18 #define SRC_SHARED_LIB_TEST_UTILS_H_
19
20 #include <cassert>
21 #include <cstdint>
22 #include <iterator>
23 #include <ostream>
24 #include <string>
25 #include <vector>
26
27 #include "perfetto/public/abi/pb_decoder_abi.h"
28 #include "perfetto/public/pb_utils.h"
29 #include "perfetto/public/tracing_session.h"
30
31 #include "test/gtest_and_gmock.h"
32
33 // Pretty printer for gtest
34 void PrintTo(const PerfettoPbDecoderField& field, std::ostream*);
35
36 namespace perfetto {
37 namespace shlib {
38 namespace test_utils {
39
40 class TracingSession {
41 public:
42 class Builder {
43 public:
44 Builder() = default;
set_data_source_name(std::string data_source_name)45 Builder& set_data_source_name(std::string data_source_name) {
46 data_source_name_ = std::move(data_source_name);
47 return *this;
48 }
49 TracingSession Build();
50
51 private:
52 std::string data_source_name_;
53 };
54 TracingSession(TracingSession&&) noexcept;
55
56 ~TracingSession();
57
session()58 struct PerfettoTracingSessionImpl* session() const { return session_; }
59
60 void StopBlocking();
61 std::vector<uint8_t> ReadBlocking();
62
63 private:
64 TracingSession() = default;
65 struct PerfettoTracingSessionImpl* session_;
66 bool stopped_ = false;
67 };
68
69 template <typename FieldSkipper>
70 class FieldViewBase {
71 public:
72 class Iterator {
73 public:
74 using iterator_category = std::input_iterator_tag;
75 using value_type = const PerfettoPbDecoderField;
76 using pointer = value_type;
77 using reference = value_type;
78 reference operator*() const {
79 struct PerfettoPbDecoder decoder;
80 decoder.read_ptr = read_ptr_;
81 decoder.end_ptr = end_ptr_;
82 struct PerfettoPbDecoderField field;
83 do {
84 field = PerfettoPbDecoderParseField(&decoder);
85 } while (field.status == PERFETTO_PB_DECODER_OK &&
86 skipper_.ShouldSkip(field));
87 return field;
88 }
89 Iterator& operator++() {
90 struct PerfettoPbDecoder decoder;
91 decoder.read_ptr = read_ptr_;
92 decoder.end_ptr = end_ptr_;
93 PerfettoPbDecoderSkipField(&decoder);
94 read_ptr_ = decoder.read_ptr;
95 AdvanceToFirstInterestingField();
96 return *this;
97 }
98 Iterator operator++(int) {
99 Iterator tmp = *this;
100 ++(*this);
101 return tmp;
102 }
103
104 friend bool operator==(const Iterator& a, const Iterator& b) {
105 return a.read_ptr_ == b.read_ptr_;
106 }
107 friend bool operator!=(const Iterator& a, const Iterator& b) {
108 return a.read_ptr_ != b.read_ptr_;
109 }
110
111 private:
Iterator(const uint8_t * read_ptr,const uint8_t * end_ptr,const FieldSkipper & skipper)112 Iterator(const uint8_t* read_ptr,
113 const uint8_t* end_ptr,
114 const FieldSkipper& skipper)
115 : read_ptr_(read_ptr), end_ptr_(end_ptr), skipper_(skipper) {
116 AdvanceToFirstInterestingField();
117 }
AdvanceToFirstInterestingField()118 void AdvanceToFirstInterestingField() {
119 struct PerfettoPbDecoder decoder;
120 decoder.read_ptr = read_ptr_;
121 decoder.end_ptr = end_ptr_;
122 struct PerfettoPbDecoderField field;
123 const uint8_t* prev_read_ptr;
124 do {
125 prev_read_ptr = decoder.read_ptr;
126 field = PerfettoPbDecoderParseField(&decoder);
127 } while (field.status == PERFETTO_PB_DECODER_OK &&
128 skipper_.ShouldSkip(field));
129 if (field.status == PERFETTO_PB_DECODER_OK) {
130 read_ptr_ = prev_read_ptr;
131 } else {
132 read_ptr_ = decoder.read_ptr;
133 }
134 }
135 friend class FieldViewBase<FieldSkipper>;
136 const uint8_t* read_ptr_;
137 const uint8_t* end_ptr_;
138 const FieldSkipper& skipper_;
139 };
140 using value_type = const PerfettoPbDecoderField;
141 using const_iterator = Iterator;
142 template <typename... Args>
FieldViewBase(const uint8_t * begin,const uint8_t * end,Args...args)143 explicit FieldViewBase(const uint8_t* begin, const uint8_t* end, Args... args)
144 : begin_(begin), end_(end), s_(args...) {}
145 template <typename... Args>
FieldViewBase(const std::vector<uint8_t> & data,Args...args)146 explicit FieldViewBase(const std::vector<uint8_t>& data, Args... args)
147 : FieldViewBase(data.data(), data.data() + data.size(), args...) {}
148 template <typename... Args>
FieldViewBase(const struct PerfettoPbDecoderField & field,Args...args)149 explicit FieldViewBase(const struct PerfettoPbDecoderField& field,
150 Args... args)
151 : s_(args...) {
152 if (field.wire_type != PERFETTO_PB_WIRE_TYPE_DELIMITED) {
153 abort();
154 }
155 begin_ = field.value.delimited.start;
156 end_ = begin_ + field.value.delimited.len;
157 }
begin()158 Iterator begin() const { return Iterator(begin_, end_, s_); }
end()159 Iterator end() const { return Iterator(end_, end_, s_); }
front()160 PerfettoPbDecoderField front() const { return *begin(); }
161
size()162 size_t size() const {
163 size_t count = 0;
164 for (auto field : *this) {
165 (void)field;
166 count++;
167 }
168 return count;
169 }
170
ok()171 bool ok() const {
172 for (auto field : *this) {
173 if (field.status != PERFETTO_PB_DECODER_OK) {
174 return false;
175 }
176 }
177 return true;
178 }
179
180 private:
181 const uint8_t* begin_;
182 const uint8_t* end_;
183 FieldSkipper s_;
184 };
185
186 // Pretty printer for gtest
187 template <typename FieldSkipper>
PrintTo(const FieldViewBase<FieldSkipper> & field_view,std::ostream * pos)188 void PrintTo(const FieldViewBase<FieldSkipper>& field_view, std::ostream* pos) {
189 std::ostream& os = *pos;
190 os << "{";
191 for (PerfettoPbDecoderField f : field_view) {
192 PrintTo(f, pos);
193 os << ", ";
194 }
195 os << "}";
196 }
197
198 class IdFieldSkipper {
199 public:
IdFieldSkipper(uint32_t id)200 explicit IdFieldSkipper(uint32_t id) : id_(id) {}
IdFieldSkipper(int32_t id)201 explicit IdFieldSkipper(int32_t id) : id_(static_cast<uint32_t>(id)) {}
ShouldSkip(const struct PerfettoPbDecoderField & field)202 bool ShouldSkip(const struct PerfettoPbDecoderField& field) const {
203 return field.id != id_;
204 }
205
206 private:
207 uint32_t id_;
208 };
209
210 class NoFieldSkipper {
211 public:
212 NoFieldSkipper() = default;
ShouldSkip(const struct PerfettoPbDecoderField &)213 bool ShouldSkip(const struct PerfettoPbDecoderField&) const { return false; }
214 };
215
216 // View over all the fields of a contiguous serialized protobuf message.
217 //
218 // Examples:
219 //
220 // for (struct PerfettoPbDecoderField field : FieldView(msg_begin, msg_end)) {
221 // //...
222 // }
223 // FieldView fields2(/*PerfettoPbDecoderField*/ nested_field);
224 // FieldView fields3(/*std::vector<uint8_t>*/ data);
225 // size_t num = fields1.size(); // The number of fields.
226 // bool ok = fields1.ok(); // Checks that the message is not malformed.
227 using FieldView = FieldViewBase<NoFieldSkipper>;
228
229 // Like `FieldView`, but only considers fields with a specific id.
230 //
231 // Examples:
232 //
233 // IdFieldView fields(msg_begin, msg_end, id)
234 using IdFieldView = FieldViewBase<IdFieldSkipper>;
235
236 // Matches a PerfettoPbDecoderField with the specified id. Accepts another
237 // matcher to match the contents of the field.
238 //
239 // Example:
240 // PerfettoPbDecoderField field = ...
241 // EXPECT_THAT(field, PbField(900, VarIntField(5)));
242 template <typename M>
PbField(int32_t id,M m)243 auto PbField(int32_t id, M m) {
244 return testing::AllOf(
245 testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
246 testing::Field(&PerfettoPbDecoderField::id, id), m);
247 }
248
249 // Matches a PerfettoPbDecoderField submessage field. Accepts a container
250 // matcher for the subfields.
251 //
252 // Example:
253 // PerfettoPbDecoderField field = ...
254 // EXPECT_THAT(field, MsgField(ElementsAre(...)));
255 template <typename M>
MsgField(M m)256 auto MsgField(M m) {
257 auto f = [](const PerfettoPbDecoderField& field) { return FieldView(field); };
258 return testing::AllOf(
259 testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
260 testing::Field(&PerfettoPbDecoderField::wire_type,
261 PERFETTO_PB_WIRE_TYPE_DELIMITED),
262 testing::ResultOf(f, m));
263 }
264
265 // Matches a PerfettoPbDecoderField length delimited field. Accepts a string
266 // matcher.
267 //
268 // Example:
269 // PerfettoPbDecoderField field = ...
270 // EXPECT_THAT(field, StringField("string"));
271 template <typename M>
StringField(M m)272 auto StringField(M m) {
273 auto f = [](const PerfettoPbDecoderField& field) {
274 return std::string(
275 reinterpret_cast<const char*>(field.value.delimited.start),
276 field.value.delimited.len);
277 };
278 return testing::AllOf(
279 testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
280 testing::Field(&PerfettoPbDecoderField::wire_type,
281 PERFETTO_PB_WIRE_TYPE_DELIMITED),
282 testing::ResultOf(f, m));
283 }
284
285 // Matches a PerfettoPbDecoderField VarInt field. Accepts an integer matcher
286 //
287 // Example:
288 // PerfettoPbDecoderField field = ...
289 // EXPECT_THAT(field, VarIntField(1)));
290 template <typename M>
VarIntField(M m)291 auto VarIntField(M m) {
292 auto f = [](const PerfettoPbDecoderField& field) {
293 return field.value.integer64;
294 };
295 return testing::AllOf(
296 testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
297 testing::Field(&PerfettoPbDecoderField::wire_type,
298 PERFETTO_PB_WIRE_TYPE_VARINT),
299 testing::ResultOf(f, m));
300 }
301
302 } // namespace test_utils
303 } // namespace shlib
304 } // namespace perfetto
305
306 #endif // SRC_SHARED_LIB_TEST_UTILS_H_
307