• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "perfetto/tracing/traced_value.h"
18 
19 #include <array>
20 #include <deque>
21 #include <forward_list>
22 #include <list>
23 #include <map>
24 #include <queue>
25 #include <set>
26 #include <sstream>
27 #include <stack>
28 #include <unordered_map>
29 #include <unordered_set>
30 
31 #include "perfetto/base/template_util.h"
32 #include "perfetto/protozero/scattered_heap_buffer.h"
33 #include "perfetto/test/traced_value_test_support.h"
34 #include "perfetto/tracing/debug_annotation.h"
35 #include "perfetto/tracing/track_event.h"
36 #include "protos/perfetto/trace/test_event.pb.h"
37 #include "protos/perfetto/trace/test_event.pbzero.h"
38 #include "protos/perfetto/trace/track_event/debug_annotation.gen.h"
39 #include "protos/perfetto/trace/track_event/debug_annotation.pb.h"
40 #include "test/gtest_and_gmock.h"
41 
42 namespace perfetto {
43 
44 // static asserts checking for conversion support for known types.
45 
46 #define ASSERT_TYPE_SUPPORTED(T)                           \
47   static_assert(check_traced_value_support<T>::value, ""); \
48   static_assert(internal::has_traced_value_support<T>::value, "")
49 
50 #define ASSERT_TYPE_NOT_SUPPORTED(T) \
51   static_assert(!internal::has_traced_value_support<T>::value, "")
52 
53 struct NonSupportedType {};
54 
55 ASSERT_TYPE_SUPPORTED(bool);
56 
57 ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType);
58 
59 // Integer types.
60 ASSERT_TYPE_SUPPORTED(short int);
61 ASSERT_TYPE_SUPPORTED(unsigned short int);
62 ASSERT_TYPE_SUPPORTED(int);
63 ASSERT_TYPE_SUPPORTED(unsigned int);
64 ASSERT_TYPE_SUPPORTED(long int);
65 ASSERT_TYPE_SUPPORTED(unsigned long int);
66 ASSERT_TYPE_SUPPORTED(long long int);
67 ASSERT_TYPE_SUPPORTED(unsigned long long int);
68 
69 // References and const references types.
70 ASSERT_TYPE_SUPPORTED(int&);
71 ASSERT_TYPE_SUPPORTED(const int&);
72 ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType&);
73 ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType&);
74 
75 // Character types.
76 ASSERT_TYPE_SUPPORTED(signed char);
77 ASSERT_TYPE_SUPPORTED(unsigned char);
78 ASSERT_TYPE_SUPPORTED(char);
79 ASSERT_TYPE_SUPPORTED(wchar_t);
80 
81 // Float types.
82 ASSERT_TYPE_SUPPORTED(float);
83 ASSERT_TYPE_SUPPORTED(double);
84 ASSERT_TYPE_SUPPORTED(long double);
85 
86 // Strings.
87 ASSERT_TYPE_SUPPORTED(const char*);
88 ASSERT_TYPE_SUPPORTED(const char[]);
89 ASSERT_TYPE_SUPPORTED(const char[2]);
90 ASSERT_TYPE_SUPPORTED(std::string);
91 
92 // Pointers.
93 ASSERT_TYPE_SUPPORTED(int*);
94 ASSERT_TYPE_SUPPORTED(const int*);
95 ASSERT_TYPE_SUPPORTED(void*);
96 ASSERT_TYPE_SUPPORTED(const void*);
97 ASSERT_TYPE_SUPPORTED(std::nullptr_t);
98 ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType*);
99 ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType*);
100 
101 // Arrays.
102 ASSERT_TYPE_NOT_SUPPORTED(int[]);
103 ASSERT_TYPE_NOT_SUPPORTED(const int[]);
104 ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType[]);
105 ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType[]);
106 ASSERT_TYPE_SUPPORTED(int (&)[3]);
107 ASSERT_TYPE_SUPPORTED(const int (&)[3]);
108 ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType (&)[3]);
109 ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType (&)[3]);
110 
111 // STL containers.
112 ASSERT_TYPE_SUPPORTED(std::vector<int>);
113 ASSERT_TYPE_NOT_SUPPORTED(std::vector<NonSupportedType>);
114 
115 using array_int_t = std::array<int, 4>;
116 ASSERT_TYPE_SUPPORTED(array_int_t);
117 ASSERT_TYPE_SUPPORTED(std::deque<int>);
118 ASSERT_TYPE_SUPPORTED(std::forward_list<int>);
119 ASSERT_TYPE_SUPPORTED(std::list<int>);
120 ASSERT_TYPE_NOT_SUPPORTED(std::stack<int>);
121 ASSERT_TYPE_NOT_SUPPORTED(std::queue<int>);
122 ASSERT_TYPE_NOT_SUPPORTED(std::priority_queue<int>);
123 ASSERT_TYPE_SUPPORTED(std::set<int>);
124 ASSERT_TYPE_SUPPORTED(std::multiset<int>);
125 using map_int_int_t = std::map<int, int>;
126 ASSERT_TYPE_NOT_SUPPORTED(map_int_int_t);
127 using multimap_int_int_t = std::multimap<int, int>;
128 ASSERT_TYPE_NOT_SUPPORTED(multimap_int_int_t);
129 ASSERT_TYPE_SUPPORTED(std::unordered_set<int>);
130 ASSERT_TYPE_SUPPORTED(std::unordered_multiset<int>);
131 using unordered_map_int_int_t = std::unordered_map<int, int>;
132 ASSERT_TYPE_NOT_SUPPORTED(unordered_map_int_int_t);
133 using unordered_multimap_int_int_t = std::unordered_multimap<int, int>;
134 ASSERT_TYPE_NOT_SUPPORTED(unordered_multimap_int_int_t);
135 
136 // unique_ptr.
137 ASSERT_TYPE_SUPPORTED(std::unique_ptr<int>);
138 ASSERT_TYPE_NOT_SUPPORTED(std::unique_ptr<NonSupportedType>);
139 
TEST(TracedValueTest,FlatDictionary_Explicit)140 TEST(TracedValueTest, FlatDictionary_Explicit) {
141   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
142   {
143     auto dict =
144         internal::CreateTracedValueFromProto(message.get()).WriteDictionary();
145     dict.AddItem("bool").WriteBoolean(true);
146     dict.AddItem("double").WriteDouble(0.0);
147     dict.AddItem("int").WriteInt64(2014);
148     dict.AddItem("string").WriteString("string");
149     dict.AddItem("truncated_string").WriteString("truncated_string", 9);
150     dict.AddItem("ptr").WritePointer(reinterpret_cast<void*>(0x1234));
151   }
152   EXPECT_EQ(
153       "{bool:true,double:0,int:2014,string:string,truncated_string:truncated,"
154       "ptr:0x1234}",
155       internal::DebugAnnotationToString(message.SerializeAsString()));
156 }
157 
TEST(TracedValueTest,FlatDictionary_Short)158 TEST(TracedValueTest, FlatDictionary_Short) {
159   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
160   {
161     auto dict =
162         internal::CreateTracedValueFromProto(message.get()).WriteDictionary();
163     dict.Add("bool", true);
164     dict.Add("double", 0.0);
165     dict.Add("int", 2014);
166     dict.Add("string", "string");
167     dict.Add("ptr", reinterpret_cast<void*>(0x1234));
168   }
169   EXPECT_EQ("{bool:true,double:0,int:2014,string:string,ptr:0x1234}",
170             internal::DebugAnnotationToString(message.SerializeAsString()));
171 }
172 
TEST(TracedValueTest,Hierarchy_Explicit)173 TEST(TracedValueTest, Hierarchy_Explicit) {
174   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
175   {
176     auto root_dict =
177         internal::CreateTracedValueFromProto(message.get()).WriteDictionary();
178     {
179       auto array = root_dict.AddItem("a1").WriteArray();
180       array.AppendItem().WriteInt64(1);
181       array.AppendItem().WriteBoolean(true);
182       {
183         auto dict = array.AppendItem().WriteDictionary();
184         dict.AddItem("i2").WriteInt64(3);
185       }
186     }
187     root_dict.AddItem("b0").WriteBoolean(true);
188     root_dict.AddItem("d0").WriteDouble(0.0);
189     {
190       auto dict1 = root_dict.AddItem("dict1").WriteDictionary();
191       {
192         auto dict2 = dict1.AddItem("dict2").WriteDictionary();
193         dict2.AddItem("b2").WriteBoolean(false);
194       }
195       dict1.AddItem("i1").WriteInt64(2014);
196       dict1.AddItem("s1").WriteString("foo");
197     }
198     root_dict.AddItem("i0").WriteInt64(2014);
199     root_dict.AddItem("s0").WriteString("foo");
200   }
201 
202   EXPECT_EQ(
203       "{"
204       "a1:[1,true,{i2:3}],"
205       "b0:true,"
206       "d0:0,"
207       "dict1:{dict2:{b2:false},i1:2014,s1:foo},"
208       "i0:2014,"
209       "s0:foo}",
210       internal::DebugAnnotationToString(message.SerializeAsString()));
211 }
212 
TEST(TracedValueTest,Hierarchy_Short)213 TEST(TracedValueTest, Hierarchy_Short) {
214   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
215   {
216     auto root_dict =
217         internal::CreateTracedValueFromProto(message.get()).WriteDictionary();
218     {
219       auto array = root_dict.AddArray("a1");
220       array.Append(1);
221       array.Append(true);
222       {
223         auto dict = array.AppendDictionary();
224         dict.Add("i2", 3);
225       }
226     }
227     root_dict.Add("b0", true);
228     root_dict.Add("d0", 0.0);
229     {
230       auto dict1 = root_dict.AddDictionary("dict1");
231       {
232         auto dict2 = dict1.AddDictionary("dict2");
233         dict2.Add("b2", false);
234       }
235       dict1.Add("i1", 2014);
236       dict1.Add("s1", "foo");
237     }
238     root_dict.Add("i0", 2014);
239     root_dict.Add("s0", "foo");
240   }
241 
242   EXPECT_EQ(
243       "{"
244       "a1:[1,true,{i2:3}],"
245       "b0:true,"
246       "d0:0,"
247       "dict1:{dict2:{b2:false},i1:2014,s1:foo},"
248       "i0:2014,"
249       "s0:foo}",
250       internal::DebugAnnotationToString(message.SerializeAsString()));
251 }
252 
253 namespace {
254 
255 class HasWriteIntoTracedValueConvertorMember {
256  public:
WriteIntoTracedValue(TracedValue context) const257   void WriteIntoTracedValue(TracedValue context) const {
258     auto dict = std::move(context).WriteDictionary();
259     dict.Add("int", 42);
260     dict.Add("bool", false);
261   }
262 };
263 
264 class HasWriteIntoTraceConvertorMember {
265  public:
WriteIntoTrace(TracedValue context) const266   void WriteIntoTrace(TracedValue context) const {
267     auto dict = std::move(context).WriteDictionary();
268     dict.Add("int", 42);
269     dict.Add("bool", false);
270   }
271 };
272 
273 class HasExternalWriteIntoTraceConvertor {};
274 class HasExternalWriteIntoTracedValueConvertor {};
275 
276 class HasAllConversionMethods {
277  public:
WriteIntoTracedValue(TracedValue context) const278   void WriteIntoTracedValue(TracedValue context) const {
279     std::move(context).WriteString("T::WriteIntoTracedValue");
280   }
281 
operator ()(TracedValue context) const282   void operator()(TracedValue context) const {
283     std::move(context).WriteString("T::()");
284   }
285 };
286 
287 class NoConversions {};
288 
289 class HasConstWriteMember {
290  public:
WriteIntoTracedValue(TracedValue context) const291   void WriteIntoTracedValue(TracedValue context) const {
292     std::move(context).WriteString("T::WriteIntoTracedValue const");
293   }
294 };
295 
296 class HasNonConstWriteMember {
297  public:
WriteIntoTracedValue(TracedValue context)298   void WriteIntoTracedValue(TracedValue context) {
299     std::move(context).WriteString("T::WriteIntoTracedValue");
300   }
301 };
302 
303 class HasConstAndNonConstWriteMember {
304  public:
WriteIntoTracedValue(TracedValue context)305   void WriteIntoTracedValue(TracedValue context) {
306     std::move(context).WriteString("T::WriteIntoTracedValue");
307   }
308 
WriteIntoTracedValue(TracedValue context) const309   void WriteIntoTracedValue(TracedValue context) const {
310     std::move(context).WriteString("T::WriteIntoTracedValue const");
311   }
312 };
313 
314 }  // namespace
315 
316 template <>
317 struct TraceFormatTraits<HasExternalWriteIntoTraceConvertor> {
WriteIntoTraceperfetto::TraceFormatTraits318   static void WriteIntoTrace(TracedValue context,
319                              const HasExternalWriteIntoTraceConvertor&) {
320     std::move(context).WriteString("TraceFormatTraits::WriteIntoTrace");
321   }
322 };
323 
324 template <>
325 struct TraceFormatTraits<HasExternalWriteIntoTracedValueConvertor> {
WriteIntoTracedValueperfetto::TraceFormatTraits326   static void WriteIntoTracedValue(
327       TracedValue context,
328       const HasExternalWriteIntoTracedValueConvertor&) {
329     std::move(context).WriteString("TraceFormatTraits::WriteIntoTracedValue");
330   }
331 };
332 
333 template <>
334 struct TraceFormatTraits<HasAllConversionMethods> {
WriteIntoTracedValueperfetto::TraceFormatTraits335   static void WriteIntoTracedValue(TracedValue context,
336                                    const HasAllConversionMethods&) {
337     std::move(context).WriteString("TraceFormatTraits::WriteIntoTracedValue");
338   }
339 };
340 
341 template <typename T>
ToStringWithFallback(T && value,const std::string & fallback)342 std::string ToStringWithFallback(T&& value, const std::string& fallback) {
343   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
344   WriteIntoTracedValueWithFallback(
345       internal::CreateTracedValueFromProto(message.get()),
346       std::forward<T>(value), fallback);
347   return internal::DebugAnnotationToString(message.SerializeAsString());
348 }
349 
350 ASSERT_TYPE_SUPPORTED(HasWriteIntoTraceConvertorMember);
351 ASSERT_TYPE_SUPPORTED(HasWriteIntoTracedValueConvertorMember);
352 ASSERT_TYPE_SUPPORTED(HasExternalWriteIntoTraceConvertor);
353 ASSERT_TYPE_SUPPORTED(HasExternalWriteIntoTracedValueConvertor);
354 ASSERT_TYPE_SUPPORTED(HasAllConversionMethods);
355 
356 ASSERT_TYPE_SUPPORTED(HasConstWriteMember);
357 ASSERT_TYPE_SUPPORTED(HasConstWriteMember&);
358 ASSERT_TYPE_SUPPORTED(HasConstWriteMember*);
359 ASSERT_TYPE_SUPPORTED(std::unique_ptr<HasConstWriteMember>);
360 ASSERT_TYPE_SUPPORTED(std::vector<HasConstWriteMember>);
361 ASSERT_TYPE_SUPPORTED(const HasConstWriteMember);
362 ASSERT_TYPE_SUPPORTED(const HasConstWriteMember&);
363 ASSERT_TYPE_SUPPORTED(const HasConstWriteMember*);
364 ASSERT_TYPE_SUPPORTED(std::unique_ptr<const HasConstWriteMember>);
365 ASSERT_TYPE_SUPPORTED(const std::vector<HasConstWriteMember>);
366 ASSERT_TYPE_SUPPORTED(std::vector<const HasConstWriteMember*>);
367 
368 ASSERT_TYPE_SUPPORTED(HasNonConstWriteMember);
369 ASSERT_TYPE_SUPPORTED(HasNonConstWriteMember&);
370 ASSERT_TYPE_SUPPORTED(HasNonConstWriteMember*);
371 ASSERT_TYPE_SUPPORTED(std::unique_ptr<HasNonConstWriteMember>);
372 ASSERT_TYPE_SUPPORTED(std::vector<HasNonConstWriteMember>);
373 ASSERT_TYPE_NOT_SUPPORTED(const HasNonConstWriteMember);
374 ASSERT_TYPE_NOT_SUPPORTED(const HasNonConstWriteMember&);
375 ASSERT_TYPE_NOT_SUPPORTED(const HasNonConstWriteMember*);
376 ASSERT_TYPE_NOT_SUPPORTED(std::unique_ptr<const HasNonConstWriteMember>);
377 ASSERT_TYPE_NOT_SUPPORTED(const std::vector<HasNonConstWriteMember>);
378 ASSERT_TYPE_NOT_SUPPORTED(std::vector<const HasNonConstWriteMember*>);
379 
380 ASSERT_TYPE_SUPPORTED(HasConstAndNonConstWriteMember);
381 ASSERT_TYPE_SUPPORTED(HasConstAndNonConstWriteMember&);
382 ASSERT_TYPE_SUPPORTED(HasConstAndNonConstWriteMember*);
383 ASSERT_TYPE_SUPPORTED(std::unique_ptr<HasConstAndNonConstWriteMember>);
384 ASSERT_TYPE_SUPPORTED(const HasConstAndNonConstWriteMember);
385 ASSERT_TYPE_SUPPORTED(const HasConstAndNonConstWriteMember&);
386 ASSERT_TYPE_SUPPORTED(const HasConstAndNonConstWriteMember*);
387 ASSERT_TYPE_SUPPORTED(std::unique_ptr<const HasConstAndNonConstWriteMember*>);
388 
TEST(TracedValueTest,UserDefinedConvertors)389 TEST(TracedValueTest, UserDefinedConvertors) {
390   HasWriteIntoTraceConvertorMember value1;
391   EXPECT_EQ(TracedValueToString(value1), "{int:42,bool:false}");
392   EXPECT_EQ(TracedValueToString(&value1), "{int:42,bool:false}");
393 
394   HasWriteIntoTracedValueConvertorMember value2;
395   EXPECT_EQ(TracedValueToString(value2), "{int:42,bool:false}");
396   EXPECT_EQ(TracedValueToString(&value2), "{int:42,bool:false}");
397 
398   HasExternalWriteIntoTracedValueConvertor value3;
399   EXPECT_EQ(TracedValueToString(value3),
400             "TraceFormatTraits::WriteIntoTracedValue");
401   EXPECT_EQ(TracedValueToString(&value3),
402             "TraceFormatTraits::WriteIntoTracedValue");
403 
404   HasExternalWriteIntoTraceConvertor value4;
405   EXPECT_EQ(TracedValueToString(value4), "TraceFormatTraits::WriteIntoTrace");
406   EXPECT_EQ(TracedValueToString(&value4), "TraceFormatTraits::WriteIntoTrace");
407 
408   HasAllConversionMethods value5;
409   EXPECT_EQ(TracedValueToString(value5), "T::WriteIntoTracedValue");
410   EXPECT_EQ(TracedValueToString(&value5), "T::WriteIntoTracedValue");
411 }
412 
TEST(TracedValueTest,WriteAsLambda)413 TEST(TracedValueTest, WriteAsLambda) {
414   EXPECT_EQ("42", TracedValueToString([&](TracedValue context) {
415               std::move(context).WriteInt64(42);
416             }));
417 }
418 
419 #if PERFETTO_DCHECK_IS_ON()
420 // This death test makes sense only when dchecks are enabled.
TEST(TracedValueTest,FailOnIncorrectUsage)421 TEST(TracedValueTest, FailOnIncorrectUsage) {
422   // A new call to AddItem is not allowed before the previous result is
423   // consumed.
424   EXPECT_DEATH(
425 
426       {
427         protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
428         auto dict = internal::CreateTracedValueFromProto(message.get())
429                         .WriteDictionary();
430         auto scope1 = dict.AddItem("key1");
431         auto scope2 = dict.AddItem("key2");
432         std::move(scope1).WriteInt64(1);
433         std::move(scope2).WriteInt64(2);
434       },
435       "");
436 
437   // A new call to AppendItem is not allowed before the previous result is
438   // consumed.
439   EXPECT_DEATH(
440       {
441         protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
442         auto array =
443             internal::CreateTracedValueFromProto(message.get()).WriteArray();
444         auto scope1 = array.AppendItem();
445         auto scope2 = array.AppendItem();
446         std::move(scope1).WriteInt64(1);
447         std::move(scope2).WriteInt64(2);
448       },
449       "");
450 
451   // Writing to parent scope is not allowed.
452   EXPECT_DEATH(
453       {
454         protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
455         auto outer_dict = internal::CreateTracedValueFromProto(message.get())
456                               .WriteDictionary();
457         {
458           auto inner_dict = outer_dict.AddDictionary("inner");
459           outer_dict.Add("key", "value");
460         }
461       },
462       "");
463 }
464 #endif  // PERFETTO_DCHECK_IS_ON()
465 
TEST(TracedValueTest,PrimitiveTypesSupport)466 TEST(TracedValueTest, PrimitiveTypesSupport) {
467   EXPECT_EQ("0x0", TracedValueToString(nullptr));
468   EXPECT_EQ("0x1", TracedValueToString(reinterpret_cast<void*>(1)));
469 
470   const int int_value = 1;
471   EXPECT_EQ("1", TracedValueToString(int_value));
472   EXPECT_EQ("1", TracedValueToString(&int_value));
473 
474   EXPECT_EQ("1.5", TracedValueToString(1.5));
475   EXPECT_EQ("true", TracedValueToString(true));
476   EXPECT_EQ("foo", TracedValueToString("foo"));
477   EXPECT_EQ("bar", TracedValueToString(std::string("bar")));
478 }
479 
TEST(TracedValueTest,UniquePtrSupport)480 TEST(TracedValueTest, UniquePtrSupport) {
481   std::unique_ptr<int> value1;
482   EXPECT_EQ("0x0", TracedValueToString(value1));
483 
484   std::unique_ptr<int> value2(new int(4));
485   EXPECT_EQ("4", TracedValueToString(value2));
486 }
487 
488 namespace {
489 
490 enum OldStyleEnum { kFoo, kBar };
491 
492 enum class NewStyleEnum { kValue1, kValue2 };
493 
494 enum class EnumWithPrettyPrint { kValue1, kValue2 };
495 
496 }  // namespace
497 
498 template <>
499 struct TraceFormatTraits<EnumWithPrettyPrint> {
WriteIntoTracedValueperfetto::TraceFormatTraits500   static void WriteIntoTracedValue(TracedValue context,
501                                    EnumWithPrettyPrint value) {
502     switch (value) {
503       case EnumWithPrettyPrint::kValue1:
504         std::move(context).WriteString("value1");
505         return;
506       case EnumWithPrettyPrint::kValue2:
507         std::move(context).WriteString("value2");
508         return;
509     }
510   }
511 };
512 
TEST(TracedValueTest,EnumSupport)513 TEST(TracedValueTest, EnumSupport) {
514   EXPECT_EQ(TracedValueToString(kFoo), "0");
515   EXPECT_EQ(TracedValueToString(NewStyleEnum::kValue2), "1");
516   EXPECT_EQ(TracedValueToString(EnumWithPrettyPrint::kValue2), "value2");
517 }
518 
TEST(TracedValueTest,ContainerSupport)519 TEST(TracedValueTest, ContainerSupport) {
520   std::vector<std::list<int>> value1{{1, 2}, {3, 4}};
521   EXPECT_EQ("[[1,2],[3,4]]", TracedValueToString(value1));
522 }
523 
TEST(TracedValueTest,WriteWithFallback)524 TEST(TracedValueTest, WriteWithFallback) {
525   EXPECT_EQ("1", ToStringWithFallback(1, "fallback"));
526   EXPECT_EQ("true", ToStringWithFallback(true, "fallback"));
527   EXPECT_EQ("fallback", ToStringWithFallback(NonSupportedType(), "fallback"));
528 }
529 
TEST(TracedValueTest,ConstAndNotConstSupport)530 TEST(TracedValueTest, ConstAndNotConstSupport) {
531   {
532     HasConstWriteMember value;
533     EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(value));
534     EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(&value));
535 
536     std::vector<HasConstWriteMember> arr(1, value);
537     EXPECT_EQ("[T::WriteIntoTracedValue const]", TracedValueToString(arr));
538   }
539 
540   {
541     const HasConstWriteMember value;
542     EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(value));
543     EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(&value));
544 
545     const std::vector<HasConstWriteMember> arr(1, value);
546     EXPECT_EQ("[T::WriteIntoTracedValue const]", TracedValueToString(arr));
547   }
548 
549   {
550     HasNonConstWriteMember value;
551     EXPECT_EQ("T::WriteIntoTracedValue", TracedValueToString(value));
552     EXPECT_EQ("T::WriteIntoTracedValue", TracedValueToString(&value));
553 
554     std::vector<HasNonConstWriteMember> arr(1, value);
555     EXPECT_EQ("[T::WriteIntoTracedValue]", TracedValueToString(arr));
556   }
557 
558   {
559     HasConstAndNonConstWriteMember value;
560     EXPECT_EQ("T::WriteIntoTracedValue", TracedValueToString(value));
561     EXPECT_EQ("T::WriteIntoTracedValue", TracedValueToString(&value));
562 
563     std::vector<HasConstAndNonConstWriteMember> arr(1, value);
564     EXPECT_EQ("[T::WriteIntoTracedValue]", TracedValueToString(arr));
565   }
566 
567   {
568     const HasConstAndNonConstWriteMember value;
569     EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(value));
570     EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(&value));
571 
572     const std::vector<HasConstAndNonConstWriteMember> arr(1, value);
573     EXPECT_EQ("[T::WriteIntoTracedValue const]", TracedValueToString(arr));
574   }
575 }
576 
577 // Note: interning of the dictionary keys is not implemented yet, so there is no
578 // difference in behaviour for StaticString and DynamicString yet.
TEST(TracedValueTest,DictionaryKeys)579 TEST(TracedValueTest, DictionaryKeys) {
580   EXPECT_EQ("{literal:1}", TracedValueToString([&](TracedValue context) {
581               auto dict = std::move(context).WriteDictionary();
582               dict.Add("literal", 1);
583             }));
584 
585   EXPECT_EQ("{static:1}", TracedValueToString([&](TracedValue context) {
586               auto dict = std::move(context).WriteDictionary();
587               const char* key = "static";
588               dict.Add(StaticString{key}, 1);
589             }));
590 
591   EXPECT_EQ("{dynamic:1}", TracedValueToString([&](TracedValue context) {
592               auto dict = std::move(context).WriteDictionary();
593               std::string key = "dynamic";
594               dict.Add(DynamicString{key.data()}, 1);
595             }));
596 
597   EXPECT_EQ("{dynamic:1}", TracedValueToString([&](TracedValue context) {
598               auto dict = std::move(context).WriteDictionary();
599               std::string key = "dynamic";
600               dict.Add(DynamicString{key.data(), key.length()}, 1);
601             }));
602 
603   EXPECT_EQ("{dynamic:1}", TracedValueToString([&](TracedValue context) {
604               auto dict = std::move(context).WriteDictionary();
605               std::string key = "dynamic";
606               dict.Add(DynamicString{key}, 1);
607             }));
608 }
609 
TEST(TracedValueTest,EmptyDict)610 TEST(TracedValueTest, EmptyDict) {
611   EXPECT_EQ("{}", TracedValueToString([&](TracedValue context) {
612               auto dict = std::move(context).WriteDictionary();
613             }));
614 }
615 
TEST(TracedValueTest,EmptyArray)616 TEST(TracedValueTest, EmptyArray) {
617   // For now we do not distinguish between empty arrays and empty dicts on proto
618   // level as trace processor ignores them anyway.
619   EXPECT_EQ("{}", TracedValueToString([&](TracedValue context) {
620               auto array = std::move(context).WriteArray();
621             }));
622 }
623 
TEST(TracedValueTest,WriteTypedProto_Explicit)624 TEST(TracedValueTest, WriteTypedProto_Explicit) {
625   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
626   WriteIntoTracedValue(
627       internal::CreateTracedValueFromProto(message.get()),
628       [](perfetto::TracedValue context) {
629         perfetto::TracedProto<protos::pbzero::TestEvent::TestPayload> proto =
630             std::move(context)
631                 .WriteProto<protos::pbzero::TestEvent::TestPayload>();
632         proto->set_single_string("payload");
633       });
634 
635   protos::DebugAnnotation annotation;
636   annotation.ParseFromString(message.SerializeAsString());
637   EXPECT_EQ(annotation.proto_type_name(),
638             ".perfetto.protos.TestEvent.TestPayload");
639 
640   protos::TestEvent::TestPayload payload;
641   payload.ParseFromString(annotation.proto_value());
642   EXPECT_EQ(payload.single_string(), "payload");
643 }
644 
TEST(TracedValueTest,WriteTypedProto_Implicit)645 TEST(TracedValueTest, WriteTypedProto_Implicit) {
646   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
647   WriteIntoTracedValue(
648       internal::CreateTracedValueFromProto(message.get()),
649       [](perfetto::TracedProto<protos::pbzero::TestEvent::TestPayload> proto) {
650         proto->set_single_string("payload");
651       });
652 
653   protos::DebugAnnotation annotation;
654   annotation.ParseFromString(message.SerializeAsString());
655   EXPECT_EQ(annotation.proto_type_name(),
656             ".perfetto.protos.TestEvent.TestPayload");
657 
658   protos::TestEvent::TestPayload payload;
659   payload.ParseFromString(annotation.proto_value());
660   EXPECT_EQ(payload.single_string(), "payload");
661 }
662 
TEST(TracedValueTest,ImplicitTracedDictionary)663 TEST(TracedValueTest, ImplicitTracedDictionary) {
664   EXPECT_EQ("{key:value}", TracedValueToString([&](TracedDictionary dict) {
665               dict.Add("key", "value");
666             }));
667 }
668 
TEST(TracedValueTest,ImplicitTracedArray)669 TEST(TracedValueTest, ImplicitTracedArray) {
670   EXPECT_EQ("[1]",
671             TracedValueToString([&](TracedArray array) { array.Append(1); }));
672 }
673 
TEST(TracedValueTest,TracedProtoInDict)674 TEST(TracedValueTest, TracedProtoInDict) {
675   struct Foo {
676     void WriteIntoTrace(
677         perfetto::TracedProto<protos::pbzero::TestEvent::TestPayload> message) {
678       message->set_single_int(42);
679     }
680   };
681   Foo foo;
682   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
683   WriteIntoTracedValue(internal::CreateTracedValueFromProto(message.get()),
684                        [&](TracedDictionary dict) { dict.Add("foo", foo); });
685   protos::DebugAnnotation annotation;
686   annotation.ParseFromString(message.SerializeAsString());
687   EXPECT_EQ(annotation.dict_entries_size(), 1);
688   EXPECT_EQ(annotation.dict_entries(0).name(), "foo");
689   EXPECT_EQ(annotation.dict_entries(0).proto_type_name(),
690             ".perfetto.protos.TestEvent.TestPayload");
691 
692   protos::TestEvent::TestPayload payload;
693   payload.ParseFromString(annotation.dict_entries(0).proto_value());
694   EXPECT_EQ(payload.single_int(), 42);
695 }
696 
TEST(TracedValueTest,PointerToTracedProtoInDict)697 TEST(TracedValueTest, PointerToTracedProtoInDict) {
698   struct Foo {
699     void WriteIntoTrace(
700         perfetto::TracedProto<protos::pbzero::TestEvent::TestPayload> message) {
701       message->set_single_int(42);
702     }
703   };
704   Foo foo;
705   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
706   WriteIntoTracedValue(internal::CreateTracedValueFromProto(message.get()),
707                        [&](TracedDictionary dict) { dict.Add("foo", &foo); });
708   protos::DebugAnnotation annotation;
709   annotation.ParseFromString(message.SerializeAsString());
710   EXPECT_EQ(annotation.dict_entries_size(), 1);
711   EXPECT_EQ(annotation.dict_entries(0).name(), "foo");
712   EXPECT_EQ(annotation.dict_entries(0).proto_type_name(),
713             ".perfetto.protos.TestEvent.TestPayload");
714 
715   protos::TestEvent::TestPayload payload;
716   payload.ParseFromString(annotation.dict_entries(0).proto_value());
717   EXPECT_EQ(payload.single_int(), 42);
718 }
719 
TEST(TracedValueTest,UniquePointerToTracedProtoInDict)720 TEST(TracedValueTest, UniquePointerToTracedProtoInDict) {
721   struct Foo {
722     void WriteIntoTrace(
723         perfetto::TracedProto<protos::pbzero::TestEvent::TestPayload> message) {
724       message->set_single_int(42);
725     }
726   };
727   std::unique_ptr<Foo> foo(new Foo());
728   protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
729   WriteIntoTracedValue(internal::CreateTracedValueFromProto(message.get()),
730                        [&](TracedDictionary dict) { dict.Add("foo", foo); });
731   protos::DebugAnnotation annotation;
732   annotation.ParseFromString(message.SerializeAsString());
733   EXPECT_EQ(annotation.dict_entries_size(), 1);
734   EXPECT_EQ(annotation.dict_entries(0).name(), "foo");
735   EXPECT_EQ(annotation.dict_entries(0).proto_type_name(),
736             ".perfetto.protos.TestEvent.TestPayload");
737 
738   protos::TestEvent::TestPayload payload;
739   payload.ParseFromString(annotation.dict_entries(0).proto_value());
740   EXPECT_EQ(payload.single_int(), 42);
741 }
742 
743 }  // namespace perfetto
744