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