• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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