Alexander Timin | 02d7985 | 2021-01-15 16:31:24 +0000 | [diff] [blame] | 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 <map> |
| 23 | #include <queue> |
| 24 | #include <set> |
| 25 | #include <sstream> |
| 26 | #include <stack> |
| 27 | #include <unordered_map> |
| 28 | #include <unordered_set> |
| 29 | |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 30 | #include "perfetto/base/template_util.h" |
Alexander Timin | 02d7985 | 2021-01-15 16:31:24 +0000 | [diff] [blame] | 31 | #include "perfetto/protozero/scattered_heap_buffer.h" |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 32 | #include "perfetto/test/traced_value_test_support.h" |
Alexander Timin | 02d7985 | 2021-01-15 16:31:24 +0000 | [diff] [blame] | 33 | #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 | |
| 39 | namespace perfetto { |
| 40 | |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 41 | // 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 | |
| 50 | struct NonSupportedType {}; |
| 51 | |
| 52 | ASSERT_TYPE_SUPPORTED(bool); |
| 53 | |
| 54 | ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType); |
| 55 | |
| 56 | // Integer types. |
| 57 | ASSERT_TYPE_SUPPORTED(short int); |
| 58 | ASSERT_TYPE_SUPPORTED(unsigned short int); |
| 59 | ASSERT_TYPE_SUPPORTED(int); |
| 60 | ASSERT_TYPE_SUPPORTED(unsigned int); |
| 61 | ASSERT_TYPE_SUPPORTED(long int); |
| 62 | ASSERT_TYPE_SUPPORTED(unsigned long int); |
| 63 | ASSERT_TYPE_SUPPORTED(long long int); |
| 64 | ASSERT_TYPE_SUPPORTED(unsigned long long int); |
| 65 | |
| 66 | // References and const references types. |
| 67 | ASSERT_TYPE_SUPPORTED(int&); |
| 68 | ASSERT_TYPE_SUPPORTED(const int&); |
| 69 | ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType&); |
| 70 | ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType&); |
| 71 | |
| 72 | // Character types. |
| 73 | ASSERT_TYPE_SUPPORTED(signed char); |
| 74 | ASSERT_TYPE_SUPPORTED(unsigned char); |
| 75 | ASSERT_TYPE_SUPPORTED(char); |
| 76 | ASSERT_TYPE_SUPPORTED(wchar_t); |
| 77 | |
| 78 | // Float types. |
| 79 | ASSERT_TYPE_SUPPORTED(float); |
| 80 | ASSERT_TYPE_SUPPORTED(double); |
| 81 | ASSERT_TYPE_SUPPORTED(long double); |
| 82 | |
| 83 | // Strings. |
| 84 | ASSERT_TYPE_SUPPORTED(const char*); |
| 85 | ASSERT_TYPE_SUPPORTED(const char[]); |
| 86 | ASSERT_TYPE_SUPPORTED(const char[2]); |
| 87 | ASSERT_TYPE_SUPPORTED(std::string); |
| 88 | |
| 89 | // Pointers. |
| 90 | ASSERT_TYPE_SUPPORTED(int*); |
| 91 | ASSERT_TYPE_SUPPORTED(const int*); |
| 92 | ASSERT_TYPE_SUPPORTED(void*); |
| 93 | ASSERT_TYPE_SUPPORTED(const void*); |
| 94 | ASSERT_TYPE_SUPPORTED(nullptr_t); |
| 95 | ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType*); |
| 96 | ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType*); |
| 97 | |
| 98 | // Arrays. |
| 99 | ASSERT_TYPE_NOT_SUPPORTED(int[]); |
| 100 | ASSERT_TYPE_NOT_SUPPORTED(const int[]); |
| 101 | ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType[]); |
| 102 | ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType[]); |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 103 | ASSERT_TYPE_SUPPORTED(int (&)[3]); |
| 104 | ASSERT_TYPE_SUPPORTED(const int (&)[3]); |
| 105 | ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType (&)[3]); |
| 106 | ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType (&)[3]); |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 107 | |
| 108 | // STL containers. |
| 109 | ASSERT_TYPE_SUPPORTED(std::vector<int>); |
| 110 | ASSERT_TYPE_NOT_SUPPORTED(std::vector<NonSupportedType>); |
| 111 | |
| 112 | using array_int_t = std::array<int, 4>; |
| 113 | ASSERT_TYPE_SUPPORTED(array_int_t); |
| 114 | ASSERT_TYPE_SUPPORTED(std::deque<int>); |
| 115 | ASSERT_TYPE_SUPPORTED(std::forward_list<int>); |
| 116 | ASSERT_TYPE_SUPPORTED(std::list<int>); |
| 117 | ASSERT_TYPE_NOT_SUPPORTED(std::stack<int>); |
| 118 | ASSERT_TYPE_NOT_SUPPORTED(std::queue<int>); |
| 119 | ASSERT_TYPE_NOT_SUPPORTED(std::priority_queue<int>); |
| 120 | ASSERT_TYPE_SUPPORTED(std::set<int>); |
| 121 | ASSERT_TYPE_SUPPORTED(std::multiset<int>); |
| 122 | using map_int_int_t = std::map<int, int>; |
| 123 | ASSERT_TYPE_NOT_SUPPORTED(map_int_int_t); |
| 124 | using multimap_int_int_t = std::multimap<int, int>; |
| 125 | ASSERT_TYPE_NOT_SUPPORTED(multimap_int_int_t); |
| 126 | ASSERT_TYPE_SUPPORTED(std::unordered_set<int>); |
| 127 | ASSERT_TYPE_SUPPORTED(std::unordered_multiset<int>); |
| 128 | using unordered_map_int_int_t = std::unordered_map<int, int>; |
| 129 | ASSERT_TYPE_NOT_SUPPORTED(unordered_map_int_int_t); |
| 130 | using unordered_multimap_int_int_t = std::unordered_multimap<int, int>; |
| 131 | ASSERT_TYPE_NOT_SUPPORTED(unordered_multimap_int_int_t); |
| 132 | |
| 133 | // unique_ptr. |
| 134 | ASSERT_TYPE_SUPPORTED(std::unique_ptr<int>); |
| 135 | ASSERT_TYPE_NOT_SUPPORTED(std::unique_ptr<NonSupportedType>); |
| 136 | |
Alexander Timin | 02d7985 | 2021-01-15 16:31:24 +0000 | [diff] [blame] | 137 | |
| 138 | TEST(TracedValueTest, FlatDictionary_Explicit) { |
| 139 | protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message; |
| 140 | { |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 141 | auto dict = |
| 142 | internal::CreateTracedValueFromProto(message.get()).WriteDictionary(); |
Alexander Timin | 02d7985 | 2021-01-15 16:31:24 +0000 | [diff] [blame] | 143 | 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 Timin | cd5e07a | 2021-02-12 16:37:53 +0000 | [diff] [blame] | 147 | dict.AddItem("truncated_string").WriteString("truncated_string", 9); |
Alexander Timin | 02d7985 | 2021-01-15 16:31:24 +0000 | [diff] [blame] | 148 | dict.AddItem("ptr").WritePointer(reinterpret_cast<void*>(0x1234)); |
| 149 | } |
Alexander Timin | cd5e07a | 2021-02-12 16:37:53 +0000 | [diff] [blame] | 150 | EXPECT_EQ( |
| 151 | "{bool:true,double:0,int:2014,string:string,truncated_string:truncated," |
Alexander Timin | 562cb1f | 2021-04-14 16:15:29 +0000 | [diff] [blame] | 152 | "ptr:0x1234}", |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 153 | internal::DebugAnnotationToString(message.SerializeAsString())); |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 154 | } |
| 155 | |
| 156 | TEST(TracedValueTest, FlatDictionary_Short) { |
| 157 | protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message; |
| 158 | { |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 159 | auto dict = |
| 160 | internal::CreateTracedValueFromProto(message.get()).WriteDictionary(); |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 161 | 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 Timin | 562cb1f | 2021-04-14 16:15:29 +0000 | [diff] [blame] | 167 | EXPECT_EQ("{bool:true,double:0,int:2014,string:string,ptr:0x1234}", |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 168 | internal::DebugAnnotationToString(message.SerializeAsString())); |
Alexander Timin | 02d7985 | 2021-01-15 16:31:24 +0000 | [diff] [blame] | 169 | } |
| 170 | |
| 171 | TEST(TracedValueTest, Hierarchy_Explicit) { |
| 172 | protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message; |
| 173 | { |
| 174 | auto root_dict = |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 175 | internal::CreateTracedValueFromProto(message.get()).WriteDictionary(); |
Alexander Timin | 02d7985 | 2021-01-15 16:31:24 +0000 | [diff] [blame] | 176 | { |
| 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 Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 202 | "a1:[1,true,{i2:3}]," |
| 203 | "b0:true," |
Alexander Timin | 02d7985 | 2021-01-15 16:31:24 +0000 | [diff] [blame] | 204 | "d0:0," |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 205 | "dict1:{dict2:{b2:false},i1:2014,s1:foo}," |
Alexander Timin | 02d7985 | 2021-01-15 16:31:24 +0000 | [diff] [blame] | 206 | "i0:2014," |
| 207 | "s0:foo}", |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 208 | internal::DebugAnnotationToString(message.SerializeAsString())); |
Alexander Timin | 02d7985 | 2021-01-15 16:31:24 +0000 | [diff] [blame] | 209 | } |
| 210 | |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 211 | TEST(TracedValueTest, Hierarchy_Short) { |
| 212 | protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message; |
| 213 | { |
| 214 | auto root_dict = |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 215 | internal::CreateTracedValueFromProto(message.get()).WriteDictionary(); |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 216 | { |
| 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 Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 248 | internal::DebugAnnotationToString(message.SerializeAsString())); |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 249 | } |
| 250 | |
| 251 | namespace { |
| 252 | |
Alexander Timin | ab9d84e | 2021-04-16 10:48:44 +0000 | [diff] [blame] | 253 | class HasWriteIntoTracedValueConvertorMember { |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 254 | 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 Timin | ab9d84e | 2021-04-16 10:48:44 +0000 | [diff] [blame] | 262 | class 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 | |
| 271 | class HasExternalWriteIntoTraceConvertor {}; |
| 272 | class HasExternalWriteIntoTracedValueConvertor {}; |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 273 | |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 274 | class 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 | |
| 285 | class NoConversions {}; |
| 286 | |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 287 | class HasConstWriteMember { |
| 288 | public: |
| 289 | void WriteIntoTracedValue(TracedValue context) const { |
| 290 | std::move(context).WriteString("T::WriteIntoTracedValue const"); |
| 291 | } |
| 292 | }; |
| 293 | |
| 294 | class HasNonConstWriteMember { |
| 295 | public: |
| 296 | void WriteIntoTracedValue(TracedValue context) { |
| 297 | std::move(context).WriteString("T::WriteIntoTracedValue"); |
| 298 | } |
| 299 | }; |
| 300 | |
| 301 | class 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 Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 312 | } // namespace |
| 313 | |
| 314 | template <> |
Alexander Timin | ab9d84e | 2021-04-16 10:48:44 +0000 | [diff] [blame] | 315 | struct TraceFormatTraits<HasExternalWriteIntoTraceConvertor> { |
| 316 | static void WriteIntoTrace(TracedValue context, |
| 317 | const HasExternalWriteIntoTraceConvertor&) { |
| 318 | std::move(context).WriteString("TraceFormatTraits::WriteIntoTrace"); |
| 319 | } |
| 320 | }; |
| 321 | |
| 322 | template <> |
| 323 | struct TraceFormatTraits<HasExternalWriteIntoTracedValueConvertor> { |
| 324 | static void WriteIntoTracedValue( |
| 325 | TracedValue context, |
| 326 | const HasExternalWriteIntoTracedValueConvertor&) { |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 327 | std::move(context).WriteString("TraceFormatTraits::WriteIntoTracedValue"); |
| 328 | } |
| 329 | }; |
| 330 | |
| 331 | template <> |
| 332 | struct TraceFormatTraits<HasAllConversionMethods> { |
| 333 | static void WriteIntoTracedValue(TracedValue context, |
| 334 | const HasAllConversionMethods&) { |
| 335 | std::move(context).WriteString("TraceFormatTraits::WriteIntoTracedValue"); |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 336 | } |
| 337 | }; |
| 338 | |
| 339 | template <typename T> |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 340 | std::string ToStringWithFallback(T&& value, const std::string& fallback) { |
| 341 | protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message; |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 342 | WriteIntoTracedValueWithFallback( |
| 343 | internal::CreateTracedValueFromProto(message.get()), |
| 344 | std::forward<T>(value), fallback); |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 345 | return internal::DebugAnnotationToString(message.SerializeAsString()); |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 346 | } |
| 347 | |
Alexander Timin | ab9d84e | 2021-04-16 10:48:44 +0000 | [diff] [blame] | 348 | ASSERT_TYPE_SUPPORTED(HasWriteIntoTraceConvertorMember); |
| 349 | ASSERT_TYPE_SUPPORTED(HasWriteIntoTracedValueConvertorMember); |
| 350 | ASSERT_TYPE_SUPPORTED(HasExternalWriteIntoTraceConvertor); |
| 351 | ASSERT_TYPE_SUPPORTED(HasExternalWriteIntoTracedValueConvertor); |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 352 | ASSERT_TYPE_SUPPORTED(HasAllConversionMethods); |
| 353 | |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 354 | ASSERT_TYPE_SUPPORTED(HasConstWriteMember); |
| 355 | ASSERT_TYPE_SUPPORTED(HasConstWriteMember&); |
| 356 | ASSERT_TYPE_SUPPORTED(HasConstWriteMember*); |
| 357 | ASSERT_TYPE_SUPPORTED(std::unique_ptr<HasConstWriteMember>); |
| 358 | ASSERT_TYPE_SUPPORTED(std::vector<HasConstWriteMember>); |
| 359 | ASSERT_TYPE_SUPPORTED(const HasConstWriteMember); |
| 360 | ASSERT_TYPE_SUPPORTED(const HasConstWriteMember&); |
| 361 | ASSERT_TYPE_SUPPORTED(const HasConstWriteMember*); |
| 362 | ASSERT_TYPE_SUPPORTED(std::unique_ptr<const HasConstWriteMember>); |
| 363 | ASSERT_TYPE_SUPPORTED(const std::vector<HasConstWriteMember>); |
| 364 | ASSERT_TYPE_SUPPORTED(std::vector<const HasConstWriteMember*>); |
| 365 | |
| 366 | ASSERT_TYPE_SUPPORTED(HasNonConstWriteMember); |
| 367 | ASSERT_TYPE_SUPPORTED(HasNonConstWriteMember&); |
| 368 | ASSERT_TYPE_SUPPORTED(HasNonConstWriteMember*); |
| 369 | ASSERT_TYPE_SUPPORTED(std::unique_ptr<HasNonConstWriteMember>); |
| 370 | ASSERT_TYPE_SUPPORTED(std::vector<HasNonConstWriteMember>); |
| 371 | ASSERT_TYPE_NOT_SUPPORTED(const HasNonConstWriteMember); |
| 372 | ASSERT_TYPE_NOT_SUPPORTED(const HasNonConstWriteMember&); |
| 373 | ASSERT_TYPE_NOT_SUPPORTED(const HasNonConstWriteMember*); |
| 374 | ASSERT_TYPE_NOT_SUPPORTED(std::unique_ptr<const HasNonConstWriteMember>); |
| 375 | ASSERT_TYPE_NOT_SUPPORTED(const std::vector<HasNonConstWriteMember>); |
| 376 | ASSERT_TYPE_NOT_SUPPORTED(std::vector<const HasNonConstWriteMember*>); |
| 377 | |
| 378 | ASSERT_TYPE_SUPPORTED(HasConstAndNonConstWriteMember); |
| 379 | ASSERT_TYPE_SUPPORTED(HasConstAndNonConstWriteMember&); |
| 380 | ASSERT_TYPE_SUPPORTED(HasConstAndNonConstWriteMember*); |
| 381 | ASSERT_TYPE_SUPPORTED(std::unique_ptr<HasConstAndNonConstWriteMember>); |
| 382 | ASSERT_TYPE_SUPPORTED(const HasConstAndNonConstWriteMember); |
| 383 | ASSERT_TYPE_SUPPORTED(const HasConstAndNonConstWriteMember&); |
| 384 | ASSERT_TYPE_SUPPORTED(const HasConstAndNonConstWriteMember*); |
| 385 | ASSERT_TYPE_SUPPORTED(std::unique_ptr<const HasConstAndNonConstWriteMember*>); |
| 386 | |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 387 | TEST(TracedValueTest, UserDefinedConvertors) { |
Alexander Timin | ab9d84e | 2021-04-16 10:48:44 +0000 | [diff] [blame] | 388 | HasWriteIntoTraceConvertorMember value1; |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 389 | EXPECT_EQ(TracedValueToString(value1), "{int:42,bool:false}"); |
| 390 | EXPECT_EQ(TracedValueToString(&value1), "{int:42,bool:false}"); |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 391 | |
Alexander Timin | ab9d84e | 2021-04-16 10:48:44 +0000 | [diff] [blame] | 392 | 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 Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 398 | "TraceFormatTraits::WriteIntoTracedValue"); |
Alexander Timin | ab9d84e | 2021-04-16 10:48:44 +0000 | [diff] [blame] | 399 | EXPECT_EQ(TracedValueToString(&value3), |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 400 | "TraceFormatTraits::WriteIntoTracedValue"); |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 401 | |
Alexander Timin | ab9d84e | 2021-04-16 10:48:44 +0000 | [diff] [blame] | 402 | 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 Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 409 | } |
| 410 | |
| 411 | TEST(TracedValueTest, WriteAsLambda) { |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 412 | EXPECT_EQ("42", TracedValueToString([&](TracedValue context) { |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 413 | std::move(context).WriteInt64(42); |
| 414 | })); |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 415 | } |
| 416 | |
Alexander Timin | ab5cba1 | 2021-01-19 17:23:19 +0000 | [diff] [blame] | 417 | #if PERFETTO_DCHECK_IS_ON() |
| 418 | // This death test makes sense only when dchecks are enabled. |
| 419 | TEST(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 Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 426 | auto dict = internal::CreateTracedValueFromProto(message.get()) |
| 427 | .WriteDictionary(); |
Alexander Timin | ab5cba1 | 2021-01-19 17:23:19 +0000 | [diff] [blame] | 428 | 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 Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 440 | auto array = |
| 441 | internal::CreateTracedValueFromProto(message.get()).WriteArray(); |
Alexander Timin | ab5cba1 | 2021-01-19 17:23:19 +0000 | [diff] [blame] | 442 | 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 Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 453 | auto outer_dict = internal::CreateTracedValueFromProto(message.get()) |
| 454 | .WriteDictionary(); |
Alexander Timin | ab5cba1 | 2021-01-19 17:23:19 +0000 | [diff] [blame] | 455 | { |
| 456 | auto inner_dict = outer_dict.AddDictionary("inner"); |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 457 | outer_dict.Add("key", "value"); |
Alexander Timin | ab5cba1 | 2021-01-19 17:23:19 +0000 | [diff] [blame] | 458 | } |
| 459 | }, |
| 460 | ""); |
| 461 | } |
| 462 | #endif // PERFETTO_DCHECK_IS_ON() |
| 463 | |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 464 | TEST(TracedValueTest, PrimitiveTypesSupport) { |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 465 | EXPECT_EQ("0x0", TracedValueToString(nullptr)); |
| 466 | EXPECT_EQ("0x1", TracedValueToString(reinterpret_cast<void*>(1))); |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 467 | |
| 468 | const int int_value = 1; |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 469 | EXPECT_EQ("1", TracedValueToString(int_value)); |
| 470 | EXPECT_EQ("1", TracedValueToString(&int_value)); |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 471 | |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 472 | 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 Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 476 | } |
| 477 | |
| 478 | TEST(TracedValueTest, UniquePtrSupport) { |
| 479 | std::unique_ptr<int> value1; |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 480 | EXPECT_EQ("0x0", TracedValueToString(value1)); |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 481 | |
| 482 | std::unique_ptr<int> value2(new int(4)); |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 483 | EXPECT_EQ("4", TracedValueToString(value2)); |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 484 | } |
| 485 | |
| 486 | namespace { |
| 487 | |
| 488 | enum OldStyleEnum { kFoo, kBar }; |
| 489 | |
| 490 | enum class NewStyleEnum { kValue1, kValue2 }; |
| 491 | |
| 492 | enum class EnumWithPrettyPrint { kValue1, kValue2 }; |
| 493 | |
| 494 | } // namespace |
| 495 | |
| 496 | template <> |
| 497 | struct 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 | |
| 511 | TEST(TracedValueTest, EnumSupport) { |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 512 | EXPECT_EQ(TracedValueToString(kFoo), "0"); |
| 513 | EXPECT_EQ(TracedValueToString(NewStyleEnum::kValue2), "1"); |
| 514 | EXPECT_EQ(TracedValueToString(EnumWithPrettyPrint::kValue2), "value2"); |
Alexander Timin | 4e669c8 | 2021-02-05 13:48:29 +0000 | [diff] [blame] | 515 | } |
| 516 | |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 517 | TEST(TracedValueTest, ContainerSupport) { |
| 518 | std::vector<std::list<int>> value1{{1, 2}, {3, 4}}; |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 519 | EXPECT_EQ("[[1,2],[3,4]]", TracedValueToString(value1)); |
Alexander Timin | ba53cc7 | 2021-02-05 15:46:57 +0000 | [diff] [blame] | 520 | } |
| 521 | |
| 522 | TEST(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 Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 528 | TEST(TracedValueTest, ConstAndNotConstSupport) { |
| 529 | { |
| 530 | HasConstWriteMember value; |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 531 | EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(value)); |
| 532 | EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(&value)); |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 533 | |
| 534 | std::vector<HasConstWriteMember> arr(1, value); |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 535 | EXPECT_EQ("[T::WriteIntoTracedValue const]", TracedValueToString(arr)); |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 536 | } |
| 537 | |
| 538 | { |
| 539 | const HasConstWriteMember value; |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 540 | EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(value)); |
| 541 | EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(&value)); |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 542 | |
| 543 | const std::vector<HasConstWriteMember> arr(1, value); |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 544 | EXPECT_EQ("[T::WriteIntoTracedValue const]", TracedValueToString(arr)); |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 545 | } |
| 546 | |
| 547 | { |
| 548 | HasNonConstWriteMember value; |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 549 | EXPECT_EQ("T::WriteIntoTracedValue", TracedValueToString(value)); |
| 550 | EXPECT_EQ("T::WriteIntoTracedValue", TracedValueToString(&value)); |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 551 | |
| 552 | std::vector<HasNonConstWriteMember> arr(1, value); |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 553 | EXPECT_EQ("[T::WriteIntoTracedValue]", TracedValueToString(arr)); |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 554 | } |
| 555 | |
| 556 | { |
| 557 | HasConstAndNonConstWriteMember value; |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 558 | EXPECT_EQ("T::WriteIntoTracedValue", TracedValueToString(value)); |
| 559 | EXPECT_EQ("T::WriteIntoTracedValue", TracedValueToString(&value)); |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 560 | |
| 561 | std::vector<HasConstAndNonConstWriteMember> arr(1, value); |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 562 | EXPECT_EQ("[T::WriteIntoTracedValue]", TracedValueToString(arr)); |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 563 | } |
| 564 | |
| 565 | { |
| 566 | const HasConstAndNonConstWriteMember value; |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 567 | EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(value)); |
| 568 | EXPECT_EQ("T::WriteIntoTracedValue const", TracedValueToString(&value)); |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 569 | |
| 570 | const std::vector<HasConstAndNonConstWriteMember> arr(1, value); |
Alexander Timin | dfc4b69 | 2021-02-15 13:32:53 +0000 | [diff] [blame] | 571 | EXPECT_EQ("[T::WriteIntoTracedValue const]", TracedValueToString(arr)); |
Alexander Timin | aa9d9b1 | 2021-02-08 14:24:01 +0000 | [diff] [blame] | 572 | } |
| 573 | } |
| 574 | |
Alexander Timin | 0d96172 | 2021-03-15 16:58:21 +0000 | [diff] [blame] | 575 | // Note: interning of the dictionary keys is not implemented yet, so there is no |
| 576 | // difference in behaviour for StaticString and DynamicString yet. |
| 577 | TEST(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 Timin | 562cb1f | 2021-04-14 16:15:29 +0000 | [diff] [blame] | 608 | TEST(TracedValueTest, EmptyDict) { |
| 609 | EXPECT_EQ("{}", TracedValueToString([&](TracedValue context) { |
| 610 | auto dict = std::move(context).WriteDictionary(); |
| 611 | })); |
| 612 | } |
| 613 | |
| 614 | TEST(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 Timin | 02d7985 | 2021-01-15 16:31:24 +0000 | [diff] [blame] | 622 | } // namespace perfetto |