• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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