1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "base/trace_event/trace_arguments.h"
11
12 #include <gtest/gtest.h>
13 #include <limits>
14 #include <string>
15
16 #include "base/memory/raw_ptr.h"
17
18 namespace base {
19 namespace trace_event {
20
21 namespace {
22
23 // Simple convertable that holds a string to append to the trace,
24 // and can also write to a boolean flag on destruction.
25 class MyConvertable : public ConvertableToTraceFormat {
26 public:
MyConvertable(const char * text,bool * destroy_flag=nullptr)27 MyConvertable(const char* text, bool* destroy_flag = nullptr)
28 : text_(text), destroy_flag_(destroy_flag) {}
~MyConvertable()29 ~MyConvertable() override {
30 if (destroy_flag_)
31 *destroy_flag_ = true;
32 }
AppendAsTraceFormat(std::string * out) const33 void AppendAsTraceFormat(std::string* out) const override { *out += text_; }
text() const34 const char* text() const { return text_; }
35
36 private:
37 const char* text_;
38 raw_ptr<bool> destroy_flag_;
39 };
40
41 } // namespace
42
TEST(TraceArguments,StringStorageDefaultConstruction)43 TEST(TraceArguments, StringStorageDefaultConstruction) {
44 StringStorage storage;
45 EXPECT_TRUE(storage.empty());
46 EXPECT_FALSE(storage.data());
47 EXPECT_EQ(0U, storage.size());
48 }
49
TEST(TraceArguments,StringStorageConstructionWithSize)50 TEST(TraceArguments, StringStorageConstructionWithSize) {
51 const size_t kSize = 128;
52 StringStorage storage(kSize);
53 EXPECT_FALSE(storage.empty());
54 EXPECT_TRUE(storage.data());
55 EXPECT_EQ(kSize, storage.size());
56 EXPECT_EQ(storage.data(), storage.begin());
57 EXPECT_EQ(storage.data() + kSize, storage.end());
58 }
59
TEST(TraceArguments,StringStorageReset)60 TEST(TraceArguments, StringStorageReset) {
61 StringStorage storage(128);
62 EXPECT_FALSE(storage.empty());
63
64 storage.Reset();
65 EXPECT_TRUE(storage.empty());
66 EXPECT_FALSE(storage.data());
67 EXPECT_EQ(0u, storage.size());
68 }
69
TEST(TraceArguments,StringStorageResetWithSize)70 TEST(TraceArguments, StringStorageResetWithSize) {
71 StringStorage storage;
72 EXPECT_TRUE(storage.empty());
73
74 const size_t kSize = 128;
75 storage.Reset(kSize);
76 EXPECT_FALSE(storage.empty());
77 EXPECT_TRUE(storage.data());
78 EXPECT_EQ(kSize, storage.size());
79 EXPECT_EQ(storage.data(), storage.begin());
80 EXPECT_EQ(storage.data() + kSize, storage.end());
81 }
82
TEST(TraceArguments,StringStorageEstimateTraceMemoryOverhead)83 TEST(TraceArguments, StringStorageEstimateTraceMemoryOverhead) {
84 StringStorage storage;
85 EXPECT_EQ(0u, storage.EstimateTraceMemoryOverhead());
86
87 const size_t kSize = 128;
88 storage.Reset(kSize);
89 EXPECT_EQ(sizeof(size_t) + kSize, storage.EstimateTraceMemoryOverhead());
90 }
91
CheckJSONFor(TraceValue v,char type,const char * expected)92 static void CheckJSONFor(TraceValue v, char type, const char* expected) {
93 std::string out;
94 v.AppendAsJSON(type, &out);
95 EXPECT_STREQ(expected, out.c_str());
96 }
97
CheckStringFor(TraceValue v,char type,const char * expected)98 static void CheckStringFor(TraceValue v, char type, const char* expected) {
99 std::string out;
100 v.AppendAsString(type, &out);
101 EXPECT_STREQ(expected, out.c_str());
102 }
103
TEST(TraceArguments,TraceValueAppend)104 TEST(TraceArguments, TraceValueAppend) {
105 TraceValue v;
106
107 v.Init(-1024);
108 CheckJSONFor(v, TRACE_VALUE_TYPE_INT, "-1024");
109 CheckStringFor(v, TRACE_VALUE_TYPE_INT, "-1024");
110 v.Init(1024ULL);
111 CheckJSONFor(v, TRACE_VALUE_TYPE_UINT, "1024");
112 CheckStringFor(v, TRACE_VALUE_TYPE_UINT, "1024");
113 v.Init(3.1415926535);
114 CheckJSONFor(v, TRACE_VALUE_TYPE_DOUBLE, "3.1415926535");
115 CheckStringFor(v, TRACE_VALUE_TYPE_DOUBLE, "3.1415926535");
116 v.Init(2.0);
117 CheckJSONFor(v, TRACE_VALUE_TYPE_DOUBLE, "2.0");
118 CheckStringFor(v, TRACE_VALUE_TYPE_DOUBLE, "2.0");
119 v.Init(0.5);
120 CheckJSONFor(v, TRACE_VALUE_TYPE_DOUBLE, "0.5");
121 CheckStringFor(v, TRACE_VALUE_TYPE_DOUBLE, "0.5");
122 v.Init(-0.5);
123 CheckJSONFor(v, TRACE_VALUE_TYPE_DOUBLE, "-0.5");
124 CheckStringFor(v, TRACE_VALUE_TYPE_DOUBLE, "-0.5");
125 v.Init(std::numeric_limits<double>::quiet_NaN());
126 CheckJSONFor(v, TRACE_VALUE_TYPE_DOUBLE, "\"NaN\"");
127 CheckStringFor(v, TRACE_VALUE_TYPE_DOUBLE, "NaN");
128 v.Init(std::numeric_limits<double>::quiet_NaN());
129 CheckJSONFor(v, TRACE_VALUE_TYPE_DOUBLE, "\"NaN\"");
130 CheckStringFor(v, TRACE_VALUE_TYPE_DOUBLE, "NaN");
131 v.Init(std::numeric_limits<double>::infinity());
132 CheckJSONFor(v, TRACE_VALUE_TYPE_DOUBLE, "\"Infinity\"");
133 CheckStringFor(v, TRACE_VALUE_TYPE_DOUBLE, "Infinity");
134 v.Init(-std::numeric_limits<double>::infinity());
135 CheckJSONFor(v, TRACE_VALUE_TYPE_DOUBLE, "\"-Infinity\"");
136 CheckStringFor(v, TRACE_VALUE_TYPE_DOUBLE, "-Infinity");
137 v.Init(true);
138 CheckJSONFor(v, TRACE_VALUE_TYPE_BOOL, "true");
139 CheckStringFor(v, TRACE_VALUE_TYPE_BOOL, "true");
140 v.Init(false);
141 CheckJSONFor(v, TRACE_VALUE_TYPE_BOOL, "false");
142 CheckStringFor(v, TRACE_VALUE_TYPE_BOOL, "false");
143 v.Init("Some \"nice\" String");
144 CheckJSONFor(v, TRACE_VALUE_TYPE_STRING, "\"Some \\\"nice\\\" String\"");
145 CheckStringFor(v, TRACE_VALUE_TYPE_STRING, "Some \"nice\" String");
146 CheckJSONFor(v, TRACE_VALUE_TYPE_COPY_STRING, "\"Some \\\"nice\\\" String\"");
147 CheckStringFor(v, TRACE_VALUE_TYPE_COPY_STRING, "Some \"nice\" String");
148
149 int* p = nullptr;
150 v.Init(static_cast<void*>(p));
151 CheckJSONFor(v, TRACE_VALUE_TYPE_POINTER, "\"0x0\"");
152 CheckStringFor(v, TRACE_VALUE_TYPE_POINTER, "0x0");
153
154 const char kText[] = "Hello World";
155 bool destroy_flag = false;
156 TraceArguments args("arg1",
157 std::make_unique<MyConvertable>(kText, &destroy_flag));
158
159 CheckJSONFor(std::move(args.values()[0]), args.types()[0], kText);
160 CheckStringFor(std::move(args.values()[0]), args.types()[0], kText);
161 }
162
TEST(TraceArguments,DefaultConstruction)163 TEST(TraceArguments, DefaultConstruction) {
164 TraceArguments args;
165 EXPECT_EQ(0U, args.size());
166 }
167
TEST(TraceArguments,ConstructorSingleInteger)168 TEST(TraceArguments, ConstructorSingleInteger) {
169 TraceArguments args("foo_int", int(10));
170 EXPECT_EQ(1U, args.size());
171 EXPECT_EQ(TRACE_VALUE_TYPE_INT, args.types()[0]);
172 EXPECT_STREQ("foo_int", args.names()[0]);
173 EXPECT_EQ(10, args.values()[0].as_int);
174 }
175
TEST(TraceArguments,ConstructorSingleFloat)176 TEST(TraceArguments, ConstructorSingleFloat) {
177 TraceArguments args("foo_pi", float(3.1415));
178 double expected = float(3.1415);
179 EXPECT_EQ(1U, args.size());
180 EXPECT_EQ(TRACE_VALUE_TYPE_DOUBLE, args.types()[0]);
181 EXPECT_STREQ("foo_pi", args.names()[0]);
182 EXPECT_EQ(expected, args.values()[0].as_double);
183 }
184
TEST(TraceArguments,ConstructorSingleNoCopyString)185 TEST(TraceArguments, ConstructorSingleNoCopyString) {
186 const char kText[] = "Persistent string";
187 TraceArguments args("foo_cstring", kText);
188 EXPECT_EQ(1U, args.size());
189 EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args.types()[0]);
190 EXPECT_STREQ("foo_cstring", args.names()[0]);
191 EXPECT_EQ(kText, args.values()[0].as_string);
192 }
193
TEST(TraceArguments,ConstructorSingleStdString)194 TEST(TraceArguments, ConstructorSingleStdString) {
195 std::string text = "Non-persistent string";
196 TraceArguments args("foo_stdstring", text);
197 EXPECT_EQ(1U, args.size());
198 EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[0]);
199 EXPECT_STREQ("foo_stdstring", args.names()[0]);
200 EXPECT_EQ(text.c_str(), args.values()[0].as_string);
201 }
202
TEST(TraceArguments,ConstructorSingleTraceStringWithCopy)203 TEST(TraceArguments, ConstructorSingleTraceStringWithCopy) {
204 const char kText[] = "Persistent string #2";
205 TraceArguments args("foo_tracestring", TraceStringWithCopy(kText));
206 EXPECT_EQ(1U, args.size());
207 EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[0]);
208 EXPECT_STREQ("foo_tracestring", args.names()[0]);
209 EXPECT_EQ(kText, args.values()[0].as_string);
210 }
211
TEST(TraceArguments,ConstructorSinglePointer)212 TEST(TraceArguments, ConstructorSinglePointer) {
213 bool destroy_flag = false;
214 {
215 // Simple class that can set a boolean flag on destruction.
216 class Foo {
217 public:
218 Foo(bool* destroy_flag) : destroy_flag_(destroy_flag) {}
219 ~Foo() {
220 if (destroy_flag_)
221 *destroy_flag_ = true;
222 }
223
224 private:
225 raw_ptr<bool> destroy_flag_;
226 };
227 auto foo = std::make_unique<Foo>(&destroy_flag);
228 EXPECT_FALSE(destroy_flag);
229 // This test also verifies that the object is not destroyed by the
230 // TraceArguments destructor. This should only be possible for
231 // TRACE_VALUE_TYPE_CONVERTABLE instances.
232 {
233 TraceArguments args("foo_pointer", static_cast<void*>(foo.get()));
234 EXPECT_EQ(1U, args.size());
235 EXPECT_EQ(TRACE_VALUE_TYPE_POINTER, args.types()[0]);
236 EXPECT_STREQ("foo_pointer", args.names()[0]);
237 EXPECT_EQ(foo.get(), args.values()[0].as_pointer);
238 EXPECT_FALSE(destroy_flag);
239 } // Calls TraceArguments destructor.
240 EXPECT_FALSE(destroy_flag);
241 } // Calls Foo destructor.
242 EXPECT_TRUE(destroy_flag);
243 }
244
TEST(TraceArguments,ConstructorSingleConvertable)245 TEST(TraceArguments, ConstructorSingleConvertable) {
246 bool destroy_flag = false;
247 const char kText[] = "Text for MyConvertable instance";
248 MyConvertable* ptr = new MyConvertable(kText, &destroy_flag);
249
250 // This test also verifies that the MyConvertable instance is properly
251 // destroyed when the TraceArguments destructor is called.
252 EXPECT_FALSE(destroy_flag);
253 {
254 TraceArguments args("foo_convertable", std::unique_ptr<MyConvertable>(ptr));
255 EXPECT_EQ(1U, args.size());
256 EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args.types()[0]);
257 EXPECT_STREQ("foo_convertable", args.names()[0]);
258 EXPECT_EQ(ptr, args.values()[0].as_convertable);
259 EXPECT_FALSE(destroy_flag);
260 } // Calls TraceArguments destructor.
261 EXPECT_TRUE(destroy_flag);
262 }
263
TEST(TraceArguments,ConstructorWithTwoArguments)264 TEST(TraceArguments, ConstructorWithTwoArguments) {
265 const char kText1[] = "First argument";
266 const char kText2[] = "Second argument";
267 bool destroy_flag = false;
268
269 {
270 MyConvertable* ptr = new MyConvertable(kText2, &destroy_flag);
271 TraceArguments args1("foo_arg1_cstring", kText1, "foo_arg2_convertable",
272 std::unique_ptr<MyConvertable>(ptr));
273 EXPECT_EQ(2U, args1.size());
274 EXPECT_STREQ("foo_arg1_cstring", args1.names()[0]);
275 EXPECT_STREQ("foo_arg2_convertable", args1.names()[1]);
276 EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args1.types()[0]);
277 EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args1.types()[1]);
278 EXPECT_EQ(kText1, args1.values()[0].as_string);
279 EXPECT_EQ(ptr, args1.values()[1].as_convertable);
280 EXPECT_FALSE(destroy_flag);
281 } // calls |args1| destructor. Should delete |ptr|.
282 EXPECT_TRUE(destroy_flag);
283 }
284
TEST(TraceArguments,ConstructorLegacyNoConvertables)285 TEST(TraceArguments, ConstructorLegacyNoConvertables) {
286 const char* const kNames[3] = {"legacy_arg1", "legacy_arg2", "legacy_arg3"};
287 const unsigned char kTypes[3] = {
288 TRACE_VALUE_TYPE_INT,
289 TRACE_VALUE_TYPE_STRING,
290 TRACE_VALUE_TYPE_POINTER,
291 };
292 static const char kText[] = "Some text";
293 const unsigned long long kValues[3] = {
294 1000042ULL,
295 reinterpret_cast<unsigned long long>(kText),
296 reinterpret_cast<unsigned long long>(kText + 2),
297 };
298 TraceArguments args(3, kNames, kTypes, kValues);
299 // Check that only the first kMaxSize arguments are taken!
300 EXPECT_EQ(2U, args.size());
301 EXPECT_STREQ(kNames[0], args.names()[0]);
302 EXPECT_STREQ(kNames[1], args.names()[1]);
303 EXPECT_EQ(TRACE_VALUE_TYPE_INT, args.types()[0]);
304 EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args.types()[1]);
305 EXPECT_EQ(kValues[0], args.values()[0].as_uint);
306 EXPECT_EQ(kText, args.values()[1].as_string);
307 }
308
TEST(TraceArguments,ConstructorLegacyWithConvertables)309 TEST(TraceArguments, ConstructorLegacyWithConvertables) {
310 const char* const kNames[3] = {"legacy_arg1", "legacy_arg2", "legacy_arg3"};
311 const unsigned char kTypes[3] = {
312 TRACE_VALUE_TYPE_CONVERTABLE,
313 TRACE_VALUE_TYPE_CONVERTABLE,
314 TRACE_VALUE_TYPE_CONVERTABLE,
315 };
316 std::unique_ptr<MyConvertable> convertables[3] = {
317 std::make_unique<MyConvertable>("First one"),
318 std::make_unique<MyConvertable>("Second one"),
319 std::make_unique<MyConvertable>("Third one"),
320 };
321 TraceArguments args(3, kNames, kTypes, nullptr, convertables);
322 // Check that only the first kMaxSize arguments are taken!
323 EXPECT_EQ(2U, args.size());
324 EXPECT_STREQ(kNames[0], args.names()[0]);
325 EXPECT_STREQ(kNames[1], args.names()[1]);
326 EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args.types()[0]);
327 EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args.types()[1]);
328 // Check that only the first two items were moved to |args|.
329 EXPECT_FALSE(convertables[0].get());
330 EXPECT_FALSE(convertables[1].get());
331 EXPECT_TRUE(convertables[2].get());
332 }
333
TEST(TraceArguments,MoveConstruction)334 TEST(TraceArguments, MoveConstruction) {
335 const char kText1[] = "First argument";
336 const char kText2[] = "Second argument";
337 bool destroy_flag = false;
338
339 {
340 MyConvertable* ptr = new MyConvertable(kText2, &destroy_flag);
341 TraceArguments args1("foo_arg1_cstring", kText1, "foo_arg2_convertable",
342 std::unique_ptr<MyConvertable>(ptr));
343 EXPECT_EQ(2U, args1.size());
344 EXPECT_STREQ("foo_arg1_cstring", args1.names()[0]);
345 EXPECT_STREQ("foo_arg2_convertable", args1.names()[1]);
346 EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args1.types()[0]);
347 EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args1.types()[1]);
348 EXPECT_EQ(kText1, args1.values()[0].as_string);
349 EXPECT_EQ(ptr, args1.values()[1].as_convertable);
350
351 {
352 TraceArguments args2(std::move(args1));
353 EXPECT_FALSE(destroy_flag);
354
355 // |args1| is now empty.
356 EXPECT_EQ(0U, args1.size());
357
358 // Check that everything was transferred to |args2|.
359 EXPECT_EQ(2U, args2.size());
360 EXPECT_STREQ("foo_arg1_cstring", args2.names()[0]);
361 EXPECT_STREQ("foo_arg2_convertable", args2.names()[1]);
362 EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args2.types()[0]);
363 EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args2.types()[1]);
364 EXPECT_EQ(kText1, args2.values()[0].as_string);
365 EXPECT_EQ(ptr, args2.values()[1].as_convertable);
366 } // Calls |args2| destructor. Should delete |ptr|.
367 EXPECT_TRUE(destroy_flag);
368 destroy_flag = false;
369 } // Calls |args1| destructor. Should not delete |ptr|.
370 EXPECT_FALSE(destroy_flag);
371 }
372
TEST(TraceArguments,MoveAssignment)373 TEST(TraceArguments, MoveAssignment) {
374 const char kText1[] = "First argument";
375 const char kText2[] = "Second argument";
376 bool destroy_flag = false;
377
378 {
379 MyConvertable* ptr = new MyConvertable(kText2, &destroy_flag);
380 TraceArguments args1("foo_arg1_cstring", kText1, "foo_arg2_convertable",
381 std::unique_ptr<MyConvertable>(ptr));
382 EXPECT_EQ(2U, args1.size());
383 EXPECT_STREQ("foo_arg1_cstring", args1.names()[0]);
384 EXPECT_STREQ("foo_arg2_convertable", args1.names()[1]);
385 EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args1.types()[0]);
386 EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args1.types()[1]);
387 EXPECT_EQ(kText1, args1.values()[0].as_string);
388 EXPECT_EQ(ptr, args1.values()[1].as_convertable);
389
390 {
391 TraceArguments args2;
392
393 args2 = std::move(args1);
394 EXPECT_FALSE(destroy_flag);
395
396 // |args1| is now empty.
397 EXPECT_EQ(0U, args1.size());
398
399 // Check that everything was transferred to |args2|.
400 EXPECT_EQ(2U, args2.size());
401 EXPECT_STREQ("foo_arg1_cstring", args2.names()[0]);
402 EXPECT_STREQ("foo_arg2_convertable", args2.names()[1]);
403 EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args2.types()[0]);
404 EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args2.types()[1]);
405 EXPECT_EQ(kText1, args2.values()[0].as_string);
406 EXPECT_EQ(ptr, args2.values()[1].as_convertable);
407 } // Calls |args2| destructor. Should delete |ptr|.
408 EXPECT_TRUE(destroy_flag);
409 destroy_flag = false;
410 } // Calls |args1| destructor. Should not delete |ptr|.
411 EXPECT_FALSE(destroy_flag);
412 }
413
TEST(TraceArguments,Reset)414 TEST(TraceArguments, Reset) {
415 bool destroy_flag = false;
416 {
417 TraceArguments args(
418 "foo_arg1", "Hello", "foo_arg2",
419 std::make_unique<MyConvertable>("World", &destroy_flag));
420
421 EXPECT_EQ(2U, args.size());
422 EXPECT_FALSE(destroy_flag);
423 args.Reset();
424 EXPECT_EQ(0U, args.size());
425 EXPECT_TRUE(destroy_flag);
426 destroy_flag = false;
427 } // Calls |args| destructor. Should not delete twice.
428 EXPECT_FALSE(destroy_flag);
429 }
430
TEST(TraceArguments,CopyStringsTo_NoStrings)431 TEST(TraceArguments, CopyStringsTo_NoStrings) {
432 StringStorage storage;
433
434 TraceArguments args("arg1", 10, "arg2", 42);
435 args.CopyStringsTo(&storage, false, nullptr, nullptr);
436 EXPECT_TRUE(storage.empty());
437 EXPECT_EQ(0U, storage.size());
438 }
439
TEST(TraceArguments,CopyStringsTo_OnlyArgs)440 TEST(TraceArguments, CopyStringsTo_OnlyArgs) {
441 StringStorage storage;
442
443 TraceArguments args("arg1", TraceStringWithCopy("Hello"), "arg2",
444 TraceStringWithCopy("World"));
445
446 const char kExtra1[] = "extra1";
447 const char kExtra2[] = "extra2";
448 const char* extra1 = kExtra1;
449 const char* extra2 = kExtra2;
450
451 // Types should be copyable strings.
452 EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[0]);
453 EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[1]);
454
455 args.CopyStringsTo(&storage, false, &extra1, &extra2);
456
457 // Storage should be allocated.
458 EXPECT_TRUE(storage.data());
459 EXPECT_NE(0U, storage.size());
460
461 // Types should not be changed.
462 EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[0]);
463 EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[1]);
464
465 // names should not be copied.
466 EXPECT_FALSE(storage.Contains(args.names()[0]));
467 EXPECT_FALSE(storage.Contains(args.names()[1]));
468 EXPECT_STREQ("arg1", args.names()[0]);
469 EXPECT_STREQ("arg2", args.names()[1]);
470
471 // strings should be copied.
472 EXPECT_TRUE(storage.Contains(args.values()[0].as_string));
473 EXPECT_TRUE(storage.Contains(args.values()[1].as_string));
474 EXPECT_STREQ("Hello", args.values()[0].as_string);
475 EXPECT_STREQ("World", args.values()[1].as_string);
476
477 // |extra1| and |extra2| should not be copied.
478 EXPECT_EQ(kExtra1, extra1);
479 EXPECT_EQ(kExtra2, extra2);
480 }
481
TEST(TraceArguments,CopyStringsTo_Everything)482 TEST(TraceArguments, CopyStringsTo_Everything) {
483 StringStorage storage;
484
485 TraceArguments args("arg1", "Hello", "arg2", "World");
486 const char kExtra1[] = "extra1";
487 const char kExtra2[] = "extra2";
488 const char* extra1 = kExtra1;
489 const char* extra2 = kExtra2;
490
491 // Types should be normal strings.
492 EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args.types()[0]);
493 EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args.types()[1]);
494
495 args.CopyStringsTo(&storage, true, &extra1, &extra2);
496
497 // Storage should be allocated.
498 EXPECT_TRUE(storage.data());
499 EXPECT_NE(0U, storage.size());
500
501 // Types should be changed to copyable strings.
502 EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[0]);
503 EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[1]);
504
505 // names should be copied.
506 EXPECT_TRUE(storage.Contains(args.names()[0]));
507 EXPECT_TRUE(storage.Contains(args.names()[1]));
508 EXPECT_STREQ("arg1", args.names()[0]);
509 EXPECT_STREQ("arg2", args.names()[1]);
510
511 // strings should be copied.
512 EXPECT_TRUE(storage.Contains(args.values()[0].as_string));
513 EXPECT_TRUE(storage.Contains(args.values()[1].as_string));
514 EXPECT_STREQ("Hello", args.values()[0].as_string);
515 EXPECT_STREQ("World", args.values()[1].as_string);
516
517 // |extra1| and |extra2| should be copied.
518 EXPECT_NE(kExtra1, extra1);
519 EXPECT_NE(kExtra2, extra2);
520 EXPECT_TRUE(storage.Contains(extra1));
521 EXPECT_TRUE(storage.Contains(extra2));
522 EXPECT_STREQ(kExtra1, extra1);
523 EXPECT_STREQ(kExtra2, extra2);
524 }
525
526 } // namespace trace_event
527 } // namespace base
528