blob: b82d6fc866aeb9f8f7ccfef5dfe0d2621e04295c [file] [log] [blame]
Alexander Timin02d79852021-01-15 16:31:24 +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 "perfetto/tracing/traced_value.h"
18
19#include <array>
20#include <deque>
21#include <forward_list>
22#include <map>
23#include <queue>
24#include <set>
25#include <sstream>
26#include <stack>
27#include <unordered_map>
28#include <unordered_set>
29
Alexander Timinba53cc72021-02-05 15:46:57 +000030#include "perfetto/base/template_util.h"
Alexander Timin02d79852021-01-15 16:31:24 +000031#include "perfetto/protozero/scattered_heap_buffer.h"
Alexander Timindfc4b692021-02-15 13:32:53 +000032#include "perfetto/test/traced_value_test_support.h"
Alexander Timin02d79852021-01-15 16:31:24 +000033#include "perfetto/tracing/debug_annotation.h"
34#include "perfetto/tracing/track_event.h"
35#include "protos/perfetto/trace/track_event/debug_annotation.gen.h"
36#include "protos/perfetto/trace/track_event/debug_annotation.pb.h"
37#include "test/gtest_and_gmock.h"
38
39namespace perfetto {
40
Alexander Timinba53cc72021-02-05 15:46:57 +000041// static asserts checking for conversion support for known types.
42
43#define ASSERT_TYPE_SUPPORTED(T) \
44 static_assert(check_traced_value_support<T>::value, ""); \
45 static_assert(internal::has_traced_value_support<T>::value, "")
46
47#define ASSERT_TYPE_NOT_SUPPORTED(T) \
48 static_assert(!internal::has_traced_value_support<T>::value, "")
49
50struct NonSupportedType {};
51
52ASSERT_TYPE_SUPPORTED(bool);
53
54ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType);
55
56// Integer types.
57ASSERT_TYPE_SUPPORTED(short int);
58ASSERT_TYPE_SUPPORTED(unsigned short int);
59ASSERT_TYPE_SUPPORTED(int);
60ASSERT_TYPE_SUPPORTED(unsigned int);
61ASSERT_TYPE_SUPPORTED(long int);
62ASSERT_TYPE_SUPPORTED(unsigned long int);
63ASSERT_TYPE_SUPPORTED(long long int);
64ASSERT_TYPE_SUPPORTED(unsigned long long int);
65
66// References and const references types.
67ASSERT_TYPE_SUPPORTED(int&);
68ASSERT_TYPE_SUPPORTED(const int&);
69ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType&);
70ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType&);
71
72// Character types.
73ASSERT_TYPE_SUPPORTED(signed char);
74ASSERT_TYPE_SUPPORTED(unsigned char);
75ASSERT_TYPE_SUPPORTED(char);
76ASSERT_TYPE_SUPPORTED(wchar_t);
77
78// Float types.
79ASSERT_TYPE_SUPPORTED(float);
80ASSERT_TYPE_SUPPORTED(double);
81ASSERT_TYPE_SUPPORTED(long double);
82
83// Strings.
84ASSERT_TYPE_SUPPORTED(const char*);
85ASSERT_TYPE_SUPPORTED(const char[]);
86ASSERT_TYPE_SUPPORTED(const char[2]);
87ASSERT_TYPE_SUPPORTED(std::string);
88
89// Pointers.
90ASSERT_TYPE_SUPPORTED(int*);
91ASSERT_TYPE_SUPPORTED(const int*);
92ASSERT_TYPE_SUPPORTED(void*);
93ASSERT_TYPE_SUPPORTED(const void*);
94ASSERT_TYPE_SUPPORTED(nullptr_t);
95ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType*);
96ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType*);
97
98// Arrays.
99ASSERT_TYPE_NOT_SUPPORTED(int[]);
100ASSERT_TYPE_NOT_SUPPORTED(const int[]);
101ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType[]);
102ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType[]);
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000103ASSERT_TYPE_SUPPORTED(int (&)[3]);
104ASSERT_TYPE_SUPPORTED(const int (&)[3]);
105ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType (&)[3]);
106ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType (&)[3]);
Alexander Timinba53cc72021-02-05 15:46:57 +0000107
108// STL containers.
109ASSERT_TYPE_SUPPORTED(std::vector<int>);
110ASSERT_TYPE_NOT_SUPPORTED(std::vector<NonSupportedType>);
111
112using array_int_t = std::array<int, 4>;
113ASSERT_TYPE_SUPPORTED(array_int_t);
114ASSERT_TYPE_SUPPORTED(std::deque<int>);
115ASSERT_TYPE_SUPPORTED(std::forward_list<int>);
116ASSERT_TYPE_SUPPORTED(std::list<int>);
117ASSERT_TYPE_NOT_SUPPORTED(std::stack<int>);
118ASSERT_TYPE_NOT_SUPPORTED(std::queue<int>);
119ASSERT_TYPE_NOT_SUPPORTED(std::priority_queue<int>);
120ASSERT_TYPE_SUPPORTED(std::set<int>);
121ASSERT_TYPE_SUPPORTED(std::multiset<int>);
122using map_int_int_t = std::map<int, int>;
123ASSERT_TYPE_NOT_SUPPORTED(map_int_int_t);
124using multimap_int_int_t = std::multimap<int, int>;
125ASSERT_TYPE_NOT_SUPPORTED(multimap_int_int_t);
126ASSERT_TYPE_SUPPORTED(std::unordered_set<int>);
127ASSERT_TYPE_SUPPORTED(std::unordered_multiset<int>);
128using unordered_map_int_int_t = std::unordered_map<int, int>;
129ASSERT_TYPE_NOT_SUPPORTED(unordered_map_int_int_t);
130using unordered_multimap_int_int_t = std::unordered_multimap<int, int>;
131ASSERT_TYPE_NOT_SUPPORTED(unordered_multimap_int_int_t);
132
133// unique_ptr.
134ASSERT_TYPE_SUPPORTED(std::unique_ptr<int>);
135ASSERT_TYPE_NOT_SUPPORTED(std::unique_ptr<NonSupportedType>);
136
Alexander Timin02d79852021-01-15 16:31:24 +0000137
138TEST(TracedValueTest, FlatDictionary_Explicit) {
139 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
140 {
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000141 auto dict =
142 internal::CreateTracedValueFromProto(message.get()).WriteDictionary();
Alexander Timin02d79852021-01-15 16:31:24 +0000143 dict.AddItem("bool").WriteBoolean(true);
144 dict.AddItem("double").WriteDouble(0.0);
145 dict.AddItem("int").WriteInt64(2014);
146 dict.AddItem("string").WriteString("string");
Alexander Timincd5e07a2021-02-12 16:37:53 +0000147 dict.AddItem("truncated_string").WriteString("truncated_string", 9);
Alexander Timin02d79852021-01-15 16:31:24 +0000148 dict.AddItem("ptr").WritePointer(reinterpret_cast<void*>(0x1234));
149 }
Alexander Timincd5e07a2021-02-12 16:37:53 +0000150 EXPECT_EQ(
151 "{bool:true,double:0,int:2014,string:string,truncated_string:truncated,"
Alexander Timin562cb1f2021-04-14 16:15:29 +0000152 "ptr:0x1234}",
Alexander Timindfc4b692021-02-15 13:32:53 +0000153 internal::DebugAnnotationToString(message.SerializeAsString()));
Alexander Timin4e669c82021-02-05 13:48:29 +0000154}
155
156TEST(TracedValueTest, FlatDictionary_Short) {
157 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
158 {
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000159 auto dict =
160 internal::CreateTracedValueFromProto(message.get()).WriteDictionary();
Alexander Timin4e669c82021-02-05 13:48:29 +0000161 dict.Add("bool", true);
162 dict.Add("double", 0.0);
163 dict.Add("int", 2014);
164 dict.Add("string", "string");
165 dict.Add("ptr", reinterpret_cast<void*>(0x1234));
166 }
Alexander Timin562cb1f2021-04-14 16:15:29 +0000167 EXPECT_EQ("{bool:true,double:0,int:2014,string:string,ptr:0x1234}",
Alexander Timindfc4b692021-02-15 13:32:53 +0000168 internal::DebugAnnotationToString(message.SerializeAsString()));
Alexander Timin02d79852021-01-15 16:31:24 +0000169}
170
171TEST(TracedValueTest, Hierarchy_Explicit) {
172 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
173 {
174 auto root_dict =
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000175 internal::CreateTracedValueFromProto(message.get()).WriteDictionary();
Alexander Timin02d79852021-01-15 16:31:24 +0000176 {
177 auto array = root_dict.AddItem("a1").WriteArray();
178 array.AppendItem().WriteInt64(1);
179 array.AppendItem().WriteBoolean(true);
180 {
181 auto dict = array.AppendItem().WriteDictionary();
182 dict.AddItem("i2").WriteInt64(3);
183 }
184 }
185 root_dict.AddItem("b0").WriteBoolean(true);
186 root_dict.AddItem("d0").WriteDouble(0.0);
187 {
188 auto dict1 = root_dict.AddItem("dict1").WriteDictionary();
189 {
190 auto dict2 = dict1.AddItem("dict2").WriteDictionary();
191 dict2.AddItem("b2").WriteBoolean(false);
192 }
193 dict1.AddItem("i1").WriteInt64(2014);
194 dict1.AddItem("s1").WriteString("foo");
195 }
196 root_dict.AddItem("i0").WriteInt64(2014);
197 root_dict.AddItem("s0").WriteString("foo");
198 }
199
200 EXPECT_EQ(
201 "{"
Alexander Timin4e669c82021-02-05 13:48:29 +0000202 "a1:[1,true,{i2:3}],"
203 "b0:true,"
Alexander Timin02d79852021-01-15 16:31:24 +0000204 "d0:0,"
Alexander Timin4e669c82021-02-05 13:48:29 +0000205 "dict1:{dict2:{b2:false},i1:2014,s1:foo},"
Alexander Timin02d79852021-01-15 16:31:24 +0000206 "i0:2014,"
207 "s0:foo}",
Alexander Timindfc4b692021-02-15 13:32:53 +0000208 internal::DebugAnnotationToString(message.SerializeAsString()));
Alexander Timin02d79852021-01-15 16:31:24 +0000209}
210
Alexander Timin4e669c82021-02-05 13:48:29 +0000211TEST(TracedValueTest, Hierarchy_Short) {
212 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
213 {
214 auto root_dict =
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000215 internal::CreateTracedValueFromProto(message.get()).WriteDictionary();
Alexander Timin4e669c82021-02-05 13:48:29 +0000216 {
217 auto array = root_dict.AddArray("a1");
218 array.Append(1);
219 array.Append(true);
220 {
221 auto dict = array.AppendDictionary();
222 dict.Add("i2", 3);
223 }
224 }
225 root_dict.Add("b0", true);
226 root_dict.Add("d0", 0.0);
227 {
228 auto dict1 = root_dict.AddDictionary("dict1");
229 {
230 auto dict2 = dict1.AddDictionary("dict2");
231 dict2.Add("b2", false);
232 }
233 dict1.Add("i1", 2014);
234 dict1.Add("s1", "foo");
235 }
236 root_dict.Add("i0", 2014);
237 root_dict.Add("s0", "foo");
238 }
239
240 EXPECT_EQ(
241 "{"
242 "a1:[1,true,{i2:3}],"
243 "b0:true,"
244 "d0:0,"
245 "dict1:{dict2:{b2:false},i1:2014,s1:foo},"
246 "i0:2014,"
247 "s0:foo}",
Alexander Timindfc4b692021-02-15 13:32:53 +0000248 internal::DebugAnnotationToString(message.SerializeAsString()));
Alexander Timin4e669c82021-02-05 13:48:29 +0000249}
250
251namespace {
252
Alexander Timinab9d84e2021-04-16 10:48:44 +0000253class HasWriteIntoTracedValueConvertorMember {
Alexander Timinba53cc72021-02-05 15:46:57 +0000254 public:
255 void WriteIntoTracedValue(TracedValue context) const {
256 auto dict = std::move(context).WriteDictionary();
257 dict.Add("int", 42);
258 dict.Add("bool", false);
259 }
260};
261
Alexander Timinab9d84e2021-04-16 10:48:44 +0000262class HasWriteIntoTraceConvertorMember {
263 public:
264 void WriteIntoTrace(TracedValue context) const {
265 auto dict = std::move(context).WriteDictionary();
266 dict.Add("int", 42);
267 dict.Add("bool", false);
268 }
269};
270
271class HasExternalWriteIntoTraceConvertor {};
272class HasExternalWriteIntoTracedValueConvertor {};
Alexander Timin4e669c82021-02-05 13:48:29 +0000273
Alexander Timinba53cc72021-02-05 15:46:57 +0000274class HasAllConversionMethods {
275 public:
276 void WriteIntoTracedValue(TracedValue context) const {
277 std::move(context).WriteString("T::WriteIntoTracedValue");
278 }
279
280 void operator()(TracedValue context) const {
281 std::move(context).WriteString("T::()");
282 }
283};
284
285class NoConversions {};
286
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000287class HasConstWriteMember {
288 public:
289 void WriteIntoTracedValue(TracedValue context) const {
290 std::move(context).WriteString("T::WriteIntoTracedValue const");
291 }
292};
293
294class HasNonConstWriteMember {
295 public:
296 void WriteIntoTracedValue(TracedValue context) {
297 std::move(context).WriteString("T::WriteIntoTracedValue");
298 }
299};
300
301class HasConstAndNonConstWriteMember {
302 public:
303 void WriteIntoTracedValue(TracedValue context) {
304 std::move(context).WriteString("T::WriteIntoTracedValue");
305 }
306
307 void WriteIntoTracedValue(TracedValue context) const {
308 std::move(context).WriteString("T::WriteIntoTracedValue const");
309 }
310};
311
Alexander Timin4e669c82021-02-05 13:48:29 +0000312} // namespace
313
314template <>
Alexander Timinab9d84e2021-04-16 10:48:44 +0000315struct TraceFormatTraits<HasExternalWriteIntoTraceConvertor> {
316 static void WriteIntoTrace(TracedValue context,
317 const HasExternalWriteIntoTraceConvertor&) {
318 std::move(context).WriteString("TraceFormatTraits::WriteIntoTrace");
319 }
320};
321
322template <>
323struct TraceFormatTraits<HasExternalWriteIntoTracedValueConvertor> {
324 static void WriteIntoTracedValue(
325 TracedValue context,
326 const HasExternalWriteIntoTracedValueConvertor&) {
Alexander Timinba53cc72021-02-05 15:46:57 +0000327 std::move(context).WriteString("TraceFormatTraits::WriteIntoTracedValue");
328 }
329};
330
331template <>
332struct TraceFormatTraits<HasAllConversionMethods> {
333 static void WriteIntoTracedValue(TracedValue context,
334 const HasAllConversionMethods&) {
335 std::move(context).WriteString("TraceFormatTraits::WriteIntoTracedValue");
Alexander Timin4e669c82021-02-05 13:48:29 +0000336 }
337};
338
339template <typename T>
Alexander Timinba53cc72021-02-05 15:46:57 +0000340std::string ToStringWithFallback(T&& value, const std::string& fallback) {
341 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000342 WriteIntoTracedValueWithFallback(
343 internal::CreateTracedValueFromProto(message.get()),
344 std::forward<T>(value), fallback);
Alexander Timindfc4b692021-02-15 13:32:53 +0000345 return internal::DebugAnnotationToString(message.SerializeAsString());
Alexander Timinba53cc72021-02-05 15:46:57 +0000346}
347
Alexander Timinab9d84e2021-04-16 10:48:44 +0000348ASSERT_TYPE_SUPPORTED(HasWriteIntoTraceConvertorMember);
349ASSERT_TYPE_SUPPORTED(HasWriteIntoTracedValueConvertorMember);
350ASSERT_TYPE_SUPPORTED(HasExternalWriteIntoTraceConvertor);
351ASSERT_TYPE_SUPPORTED(HasExternalWriteIntoTracedValueConvertor);
Alexander Timinba53cc72021-02-05 15:46:57 +0000352ASSERT_TYPE_SUPPORTED(HasAllConversionMethods);
353
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000354ASSERT_TYPE_SUPPORTED(HasConstWriteMember);
355ASSERT_TYPE_SUPPORTED(HasConstWriteMember&);
356ASSERT_TYPE_SUPPORTED(HasConstWriteMember*);
357ASSERT_TYPE_SUPPORTED(std::unique_ptr<HasConstWriteMember>);
358ASSERT_TYPE_SUPPORTED(std::vector<HasConstWriteMember>);
359ASSERT_TYPE_SUPPORTED(const HasConstWriteMember);
360ASSERT_TYPE_SUPPORTED(const HasConstWriteMember&);
361ASSERT_TYPE_SUPPORTED(const HasConstWriteMember*);
362ASSERT_TYPE_SUPPORTED(std::unique_ptr<const HasConstWriteMember>);
363ASSERT_TYPE_SUPPORTED(const std::vector<HasConstWriteMember>);
364ASSERT_TYPE_SUPPORTED(std::vector<const HasConstWriteMember*>);
365
366ASSERT_TYPE_SUPPORTED(HasNonConstWriteMember);
367ASSERT_TYPE_SUPPORTED(HasNonConstWriteMember&);
368ASSERT_TYPE_SUPPORTED(HasNonConstWriteMember*);
369ASSERT_TYPE_SUPPORTED(std::unique_ptr<HasNonConstWriteMember>);
370ASSERT_TYPE_SUPPORTED(std::vector<HasNonConstWriteMember>);
371ASSERT_TYPE_NOT_SUPPORTED(const HasNonConstWriteMember);
372ASSERT_TYPE_NOT_SUPPORTED(const HasNonConstWriteMember&);
373ASSERT_TYPE_NOT_SUPPORTED(const HasNonConstWriteMember*);
374ASSERT_TYPE_NOT_SUPPORTED(std::unique_ptr<const HasNonConstWriteMember>);
375ASSERT_TYPE_NOT_SUPPORTED(const std::vector<HasNonConstWriteMember>);
376ASSERT_TYPE_NOT_SUPPORTED(std::vector<const HasNonConstWriteMember*>);
377
378ASSERT_TYPE_SUPPORTED(HasConstAndNonConstWriteMember);
379ASSERT_TYPE_SUPPORTED(HasConstAndNonConstWriteMember&);
380ASSERT_TYPE_SUPPORTED(HasConstAndNonConstWriteMember*);
381ASSERT_TYPE_SUPPORTED(std::unique_ptr<HasConstAndNonConstWriteMember>);
382ASSERT_TYPE_SUPPORTED(const HasConstAndNonConstWriteMember);
383ASSERT_TYPE_SUPPORTED(const HasConstAndNonConstWriteMember&);
384ASSERT_TYPE_SUPPORTED(const HasConstAndNonConstWriteMember*);
385ASSERT_TYPE_SUPPORTED(std::unique_ptr<const HasConstAndNonConstWriteMember*>);
386
Alexander Timin4e669c82021-02-05 13:48:29 +0000387TEST(TracedValueTest, UserDefinedConvertors) {
Alexander Timinab9d84e2021-04-16 10:48:44 +0000388 HasWriteIntoTraceConvertorMember value1;
Alexander Timindfc4b692021-02-15 13:32:53 +0000389 EXPECT_EQ(TracedValueToString(value1), "{int:42,bool:false}");
390 EXPECT_EQ(TracedValueToString(&value1), "{int:42,bool:false}");
Alexander Timinba53cc72021-02-05 15:46:57 +0000391
Alexander Timinab9d84e2021-04-16 10:48:44 +0000392 HasWriteIntoTracedValueConvertorMember value2;
393 EXPECT_EQ(TracedValueToString(value2), "{int:42,bool:false}");
394 EXPECT_EQ(TracedValueToString(&value2), "{int:42,bool:false}");
395
396 HasExternalWriteIntoTracedValueConvertor value3;
397 EXPECT_EQ(TracedValueToString(value3),
Alexander Timindfc4b692021-02-15 13:32:53 +0000398 "TraceFormatTraits::WriteIntoTracedValue");
Alexander Timinab9d84e2021-04-16 10:48:44 +0000399 EXPECT_EQ(TracedValueToString(&value3),
Alexander Timindfc4b692021-02-15 13:32:53 +0000400 "TraceFormatTraits::WriteIntoTracedValue");
Alexander Timinba53cc72021-02-05 15:46:57 +0000401
Alexander Timinab9d84e2021-04-16 10:48:44 +0000402 HasExternalWriteIntoTraceConvertor value4;
403 EXPECT_EQ(TracedValueToString(value4), "TraceFormatTraits::WriteIntoTrace");
404 EXPECT_EQ(TracedValueToString(&value4), "TraceFormatTraits::WriteIntoTrace");
405
406 HasAllConversionMethods value5;
407 EXPECT_EQ(TracedValueToString(value5), "T::WriteIntoTracedValue");
408 EXPECT_EQ(TracedValueToString(&value5), "T::WriteIntoTracedValue");
Alexander Timinba53cc72021-02-05 15:46:57 +0000409}
410
411TEST(TracedValueTest, WriteAsLambda) {
Alexander Timindfc4b692021-02-15 13:32:53 +0000412 EXPECT_EQ("42", TracedValueToString([&](TracedValue context) {
Alexander Timinba53cc72021-02-05 15:46:57 +0000413 std::move(context).WriteInt64(42);
414 }));
Alexander Timin4e669c82021-02-05 13:48:29 +0000415}
416
Alexander Timinab5cba12021-01-19 17:23:19 +0000417#if PERFETTO_DCHECK_IS_ON()
418// This death test makes sense only when dchecks are enabled.
419TEST(TracedValueTest, FailOnIncorrectUsage) {
420 // A new call to AddItem is not allowed before the previous result is
421 // consumed.
422 EXPECT_DEATH(
423
424 {
425 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000426 auto dict = internal::CreateTracedValueFromProto(message.get())
427 .WriteDictionary();
Alexander Timinab5cba12021-01-19 17:23:19 +0000428 auto scope1 = dict.AddItem("key1");
429 auto scope2 = dict.AddItem("key2");
430 std::move(scope1).WriteInt64(1);
431 std::move(scope2).WriteInt64(2);
432 },
433 "");
434
435 // A new call to AppendItem is not allowed before the previous result is
436 // consumed.
437 EXPECT_DEATH(
438 {
439 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000440 auto array =
441 internal::CreateTracedValueFromProto(message.get()).WriteArray();
Alexander Timinab5cba12021-01-19 17:23:19 +0000442 auto scope1 = array.AppendItem();
443 auto scope2 = array.AppendItem();
444 std::move(scope1).WriteInt64(1);
445 std::move(scope2).WriteInt64(2);
446 },
447 "");
448
449 // Writing to parent scope is not allowed.
450 EXPECT_DEATH(
451 {
452 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000453 auto outer_dict = internal::CreateTracedValueFromProto(message.get())
454 .WriteDictionary();
Alexander Timinab5cba12021-01-19 17:23:19 +0000455 {
456 auto inner_dict = outer_dict.AddDictionary("inner");
Alexander Timin4e669c82021-02-05 13:48:29 +0000457 outer_dict.Add("key", "value");
Alexander Timinab5cba12021-01-19 17:23:19 +0000458 }
459 },
460 "");
461}
462#endif // PERFETTO_DCHECK_IS_ON()
463
Alexander Timin4e669c82021-02-05 13:48:29 +0000464TEST(TracedValueTest, PrimitiveTypesSupport) {
Alexander Timindfc4b692021-02-15 13:32:53 +0000465 EXPECT_EQ("0x0", TracedValueToString(nullptr));
466 EXPECT_EQ("0x1", TracedValueToString(reinterpret_cast<void*>(1)));
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000467
468 const int int_value = 1;
Alexander Timindfc4b692021-02-15 13:32:53 +0000469 EXPECT_EQ("1", TracedValueToString(int_value));
470 EXPECT_EQ("1", TracedValueToString(&int_value));
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000471
Alexander Timindfc4b692021-02-15 13:32:53 +0000472 EXPECT_EQ("1.5", TracedValueToString(1.5));
473 EXPECT_EQ("true", TracedValueToString(true));
474 EXPECT_EQ("foo", TracedValueToString("foo"));
475 EXPECT_EQ("bar", TracedValueToString(std::string("bar")));
Alexander Timin4e669c82021-02-05 13:48:29 +0000476}
477
478TEST(TracedValueTest, UniquePtrSupport) {
479 std::unique_ptr<int> value1;
Alexander Timindfc4b692021-02-15 13:32:53 +0000480 EXPECT_EQ("0x0", TracedValueToString(value1));
Alexander Timin4e669c82021-02-05 13:48:29 +0000481
482 std::unique_ptr<int> value2(new int(4));
Alexander Timindfc4b692021-02-15 13:32:53 +0000483 EXPECT_EQ("4", TracedValueToString(value2));
Alexander Timin4e669c82021-02-05 13:48:29 +0000484}
485
486namespace {
487
488enum OldStyleEnum { kFoo, kBar };
489
490enum class NewStyleEnum { kValue1, kValue2 };
491
492enum class EnumWithPrettyPrint { kValue1, kValue2 };
493
494} // namespace
495
496template <>
497struct TraceFormatTraits<EnumWithPrettyPrint> {
498 static void WriteIntoTracedValue(TracedValue context,
499 EnumWithPrettyPrint value) {
500 switch (value) {
501 case EnumWithPrettyPrint::kValue1:
502 std::move(context).WriteString("value1");
503 return;
504 case EnumWithPrettyPrint::kValue2:
505 std::move(context).WriteString("value2");
506 return;
507 }
508 }
509};
510
511TEST(TracedValueTest, EnumSupport) {
Alexander Timindfc4b692021-02-15 13:32:53 +0000512 EXPECT_EQ(TracedValueToString(kFoo), "0");
513 EXPECT_EQ(TracedValueToString(NewStyleEnum::kValue2), "1");
514 EXPECT_EQ(TracedValueToString(EnumWithPrettyPrint::kValue2), "value2");
Alexander Timin4e669c82021-02-05 13:48:29 +0000515}
516
Alexander Timinba53cc72021-02-05 15:46:57 +0000517TEST(TracedValueTest, ContainerSupport) {
518 std::vector<std::list<int>> value1{{1, 2}, {3, 4}};
Alexander Timindfc4b692021-02-15 13:32:53 +0000519 EXPECT_EQ("[[1,2],[3,4]]", TracedValueToString(value1));
Alexander Timinba53cc72021-02-05 15:46:57 +0000520}
521
522TEST(TracedValueTest, WriteWithFallback) {
523 EXPECT_EQ("1", ToStringWithFallback(1, "fallback"));
524 EXPECT_EQ("true", ToStringWithFallback(true, "fallback"));
525 EXPECT_EQ("fallback", ToStringWithFallback(NonSupportedType(), "fallback"));
526}
527
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000528TEST(TracedValueTest, ConstAndNotConstSupport) {
529 {
530 HasConstWriteMember value;
Alexander Timindfc4b692021-02-15 13:32:53 +0000531 EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(value));
532 EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(&value));
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000533
534 std::vector<HasConstWriteMember> arr(1, value);
Alexander Timindfc4b692021-02-15 13:32:53 +0000535 EXPECT_EQ("[T::WriteIntoTracedValue const]", TracedValueToString(arr));
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000536 }
537
538 {
539 const HasConstWriteMember value;
Alexander Timindfc4b692021-02-15 13:32:53 +0000540 EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(value));
541 EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(&value));
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000542
543 const std::vector<HasConstWriteMember> arr(1, value);
Alexander Timindfc4b692021-02-15 13:32:53 +0000544 EXPECT_EQ("[T::WriteIntoTracedValue const]", TracedValueToString(arr));
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000545 }
546
547 {
548 HasNonConstWriteMember value;
Alexander Timindfc4b692021-02-15 13:32:53 +0000549 EXPECT_EQ("T::WriteIntoTracedValue", TracedValueToString(value));
550 EXPECT_EQ("T::WriteIntoTracedValue", TracedValueToString(&value));
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000551
552 std::vector<HasNonConstWriteMember> arr(1, value);
Alexander Timindfc4b692021-02-15 13:32:53 +0000553 EXPECT_EQ("[T::WriteIntoTracedValue]", TracedValueToString(arr));
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000554 }
555
556 {
557 HasConstAndNonConstWriteMember value;
Alexander Timindfc4b692021-02-15 13:32:53 +0000558 EXPECT_EQ("T::WriteIntoTracedValue", TracedValueToString(value));
559 EXPECT_EQ("T::WriteIntoTracedValue", TracedValueToString(&value));
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000560
561 std::vector<HasConstAndNonConstWriteMember> arr(1, value);
Alexander Timindfc4b692021-02-15 13:32:53 +0000562 EXPECT_EQ("[T::WriteIntoTracedValue]", TracedValueToString(arr));
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000563 }
564
565 {
566 const HasConstAndNonConstWriteMember value;
Alexander Timindfc4b692021-02-15 13:32:53 +0000567 EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(value));
568 EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(&value));
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000569
570 const std::vector<HasConstAndNonConstWriteMember> arr(1, value);
Alexander Timindfc4b692021-02-15 13:32:53 +0000571 EXPECT_EQ("[T::WriteIntoTracedValue const]", TracedValueToString(arr));
Alexander Timinaa9d9b12021-02-08 14:24:01 +0000572 }
573}
574
Alexander Timin0d961722021-03-15 16:58:21 +0000575// Note: interning of the dictionary keys is not implemented yet, so there is no
576// difference in behaviour for StaticString and DynamicString yet.
577TEST(TracedValueTest, DictionaryKeys) {
578 EXPECT_EQ("{literal:1}", TracedValueToString([&](TracedValue context) {
579 auto dict = std::move(context).WriteDictionary();
580 dict.Add("literal", 1);
581 }));
582
583 EXPECT_EQ("{static:1}", TracedValueToString([&](TracedValue context) {
584 auto dict = std::move(context).WriteDictionary();
585 const char* key = "static";
586 dict.Add(StaticString{key}, 1);
587 }));
588
589 EXPECT_EQ("{dynamic:1}", TracedValueToString([&](TracedValue context) {
590 auto dict = std::move(context).WriteDictionary();
591 std::string key = "dynamic";
592 dict.Add(DynamicString{key.data()}, 1);
593 }));
594
595 EXPECT_EQ("{dynamic:1}", TracedValueToString([&](TracedValue context) {
596 auto dict = std::move(context).WriteDictionary();
597 std::string key = "dynamic";
598 dict.Add(DynamicString{key.data(), key.length()}, 1);
599 }));
600
601 EXPECT_EQ("{dynamic:1}", TracedValueToString([&](TracedValue context) {
602 auto dict = std::move(context).WriteDictionary();
603 std::string key = "dynamic";
604 dict.Add(DynamicString{key}, 1);
605 }));
606}
607
Alexander Timin562cb1f2021-04-14 16:15:29 +0000608TEST(TracedValueTest, EmptyDict) {
609 EXPECT_EQ("{}", TracedValueToString([&](TracedValue context) {
610 auto dict = std::move(context).WriteDictionary();
611 }));
612}
613
614TEST(TracedValueTest, EmptyArray) {
615 // For now we do not distinguish between empty arrays and empty dicts on proto
616 // level as trace processor ignores them anyway.
617 EXPECT_EQ("{}", TracedValueToString([&](TracedValue context) {
618 auto array = std::move(context).WriteArray();
619 }));
620}
621
Alexander Timin02d79852021-01-15 16:31:24 +0000622} // namespace perfetto