blob: 6b8f5f901ec9f733f8bde7da1f3bddf805850198 [file] [log] [blame]
scheib@chromium.org603f46e2011-05-10 11:23:58 +09001// Copyright (c) 2011 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/debug/trace_event.h"
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/json/json_reader.h"
10#include "base/json/json_writer.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/stringprintf.h"
13#include "base/synchronization/waitable_event.h"
14#include "base/threading/thread.h"
15#include "base/values.h"
16#include "testing/gmock/include/gmock/gmock.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19namespace base {
20namespace debug {
21
22namespace {
23
jbates@chromium.orgb3cab862011-05-14 08:30:35 +090024struct JsonKeyValue {
25 const char* key;
26 const char* value;
27};
28
scheib@chromium.org603f46e2011-05-10 11:23:58 +090029class TraceEventTestFixture : public testing::Test {
30 public:
joth@chromium.org113de992011-07-21 21:28:59 +090031 // This fixture does not use SetUp() because the fixture must be manually set
32 // up multiple times when testing AtExit. Use ManualTestSetUp for this.
scheib@chromium.org603f46e2011-05-10 11:23:58 +090033 void ManualTestSetUp();
ajwong@chromium.orgec1750a2011-06-27 01:22:50 +090034 void OnTraceDataCollected(
35 scoped_refptr<TraceLog::RefCountedString> json_events_str);
jbates@chromium.orgb3cab862011-05-14 08:30:35 +090036 bool FindMatchingTraceEntry(const JsonKeyValue* key_values);
37 bool FindNamePhase(const char* name, const char* phase);
scheib@chromium.org603f46e2011-05-10 11:23:58 +090038
39 std::string trace_string_;
40 ListValue trace_parsed_;
41
42 private:
43 // We want our singleton torn down after each test.
44 ShadowingAtExitManager at_exit_manager_;
45};
46
47void TraceEventTestFixture::ManualTestSetUp() {
48 TraceLog::Resurrect();
49 TraceLog* tracelog = TraceLog::GetInstance();
50 ASSERT_TRUE(tracelog);
51 ASSERT_FALSE(tracelog->IsEnabled());
52 tracelog->SetOutputCallback(
53 base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
54 base::Unretained(this)));
55}
56
57void TraceEventTestFixture::OnTraceDataCollected(
ajwong@chromium.orgec1750a2011-06-27 01:22:50 +090058 scoped_refptr<TraceLog::RefCountedString> json_events_str) {
scheib@chromium.org603f46e2011-05-10 11:23:58 +090059 trace_string_ += json_events_str->data;
60
61 scoped_ptr<Value> root;
62 root.reset(base::JSONReader::Read(json_events_str->data, false));
63
64 ListValue* root_list = NULL;
65 ASSERT_TRUE(root.get());
66 ASSERT_TRUE(root->GetAsList(&root_list));
67
68 // Move items into our aggregate collection
69 while (root_list->GetSize()) {
70 Value* item = NULL;
71 root_list->Remove(0, &item);
72 trace_parsed_.Append(item);
73 }
74}
75
jbates@chromium.orgb3cab862011-05-14 08:30:35 +090076static bool IsKeyValueInDict(const JsonKeyValue* key_value,
77 DictionaryValue* dict) {
78 Value* value = NULL;
79 std::string value_str;
80 if (dict->Get(key_value->key, &value) &&
81 value->GetAsString(&value_str) &&
82 value_str == key_value->value)
83 return true;
84
85 // Recurse to test arguments
86 DictionaryValue* args_dict = NULL;
87 dict->GetDictionary("args", &args_dict);
88 if (args_dict)
89 return IsKeyValueInDict(key_value, args_dict);
90
91 return false;
92}
93
94static bool IsAllKeyValueInDict(const JsonKeyValue* key_values,
95 DictionaryValue* dict) {
96 // Scan all key_values, they must all be present and equal.
97 while (key_values && key_values->key) {
98 if (!IsKeyValueInDict(key_values, dict))
99 return false;
100 ++key_values;
101 }
102 return true;
103}
104
105bool TraceEventTestFixture::FindMatchingTraceEntry(
106 const JsonKeyValue* key_values) {
107 // Scan all items
108 size_t trace_parsed_count = trace_parsed_.GetSize();
109 for (size_t i = 0; i < trace_parsed_count; i++) {
110 Value* value = NULL;
111 trace_parsed_.Get(i, &value);
112 if (!value || value->GetType() != Value::TYPE_DICTIONARY)
113 continue;
114 DictionaryValue* dict = static_cast<DictionaryValue*>(value);
115
116 if (IsAllKeyValueInDict(key_values, dict))
117 return true;
118 }
119 return false;
120}
121
122bool TraceEventTestFixture::FindNamePhase(const char* name, const char* phase) {
123 JsonKeyValue key_values[] = {
124 {"name", name},
125 {"ph", phase},
126 {0, 0}
127 };
128 return FindMatchingTraceEntry(key_values);
129}
130
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900131bool IsStringInDict(const char* string_to_match, DictionaryValue* dict) {
132 for (DictionaryValue::key_iterator ikey = dict->begin_keys();
133 ikey != dict->end_keys(); ++ikey) {
134 Value* child = NULL;
135 if (!dict->GetWithoutPathExpansion(*ikey, &child))
136 continue;
137
138 if ((*ikey).find(string_to_match) != std::string::npos)
139 return true;
140
141 std::string value_str;
142 child->GetAsString(&value_str);
143 if (value_str.find(string_to_match) != std::string::npos)
144 return true;
145 }
146
147 // Recurse to test arguments
148 DictionaryValue* args_dict = NULL;
149 dict->GetDictionary("args", &args_dict);
150 if (args_dict)
151 return IsStringInDict(string_to_match, args_dict);
152
153 return false;
154}
155
156DictionaryValue* FindTraceEntry(const ListValue& trace_parsed,
157 const char *string_to_match,
158 DictionaryValue* match_after_this_item = NULL) {
159 // Scan all items
160 size_t trace_parsed_count = trace_parsed.GetSize();
161 for (size_t i = 0; i < trace_parsed_count; i++) {
162 Value* value = NULL;
163 trace_parsed.Get(i, &value);
164 if (match_after_this_item) {
165 if (value == match_after_this_item)
166 match_after_this_item = NULL;
167 continue;
168 }
169 if (!value || value->GetType() != Value::TYPE_DICTIONARY)
170 continue;
171 DictionaryValue* dict = static_cast<DictionaryValue*>(value);
172
173 if (IsStringInDict(string_to_match, dict))
174 return dict;
175 }
176 return NULL;
177}
178
179void DataCapturedCallTraces(WaitableEvent* task_complete_event) {
180 {
181 TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW call", 1122, "extrastring1");
182 TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW call", 3344, "extrastring2");
183 TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW call",
184 5566, "extrastring3");
185
186 TRACE_EVENT0("all", "TRACE_EVENT0 call");
187 TRACE_EVENT1("all", "TRACE_EVENT1 call", "name1", "value1");
188 TRACE_EVENT2("all", "TRACE_EVENT2 call",
189 "name1", "value1",
190 "name2", "value2");
191
192 TRACE_EVENT_INSTANT0("all", "TRACE_EVENT_INSTANT0 call");
193 TRACE_EVENT_INSTANT1("all", "TRACE_EVENT_INSTANT1 call", "name1", "value1");
194 TRACE_EVENT_INSTANT2("all", "TRACE_EVENT_INSTANT2 call",
195 "name1", "value1",
196 "name2", "value2");
197
198 TRACE_EVENT_BEGIN0("all", "TRACE_EVENT_BEGIN0 call");
199 TRACE_EVENT_BEGIN1("all", "TRACE_EVENT_BEGIN1 call", "name1", "value1");
200 TRACE_EVENT_BEGIN2("all", "TRACE_EVENT_BEGIN2 call",
201 "name1", "value1",
202 "name2", "value2");
203
204 TRACE_EVENT_END0("all", "TRACE_EVENT_END0 call");
205 TRACE_EVENT_END1("all", "TRACE_EVENT_END1 call", "name1", "value1");
206 TRACE_EVENT_END2("all", "TRACE_EVENT_END2 call",
207 "name1", "value1",
208 "name2", "value2");
209 } // Scope close causes TRACE_EVENT0 etc to send their END events.
210
211 if (task_complete_event)
212 task_complete_event->Signal();
213}
214
215void DataCapturedValidateTraces(const ListValue& trace_parsed,
216 const std::string& trace_string) {
217 DictionaryValue* item = NULL;
218
219#define EXPECT_FIND_(string) \
220 EXPECT_TRUE((item = FindTraceEntry(trace_parsed, string)));
221#define EXPECT_NOT_FIND_(string) \
222 EXPECT_FALSE((item = FindTraceEntry(trace_parsed, string)));
223#define EXPECT_SUB_FIND_(string) \
224 if (item) EXPECT_TRUE((IsStringInDict(string, item)));
225
226 EXPECT_FIND_("ETW Trace Event");
227 EXPECT_FIND_("all");
228 EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW call");
229 {
230 int int_val = 0;
231 EXPECT_TRUE(item && item->GetInteger("args.id", &int_val));
232 EXPECT_EQ(1122, int_val);
233 }
234 EXPECT_SUB_FIND_("extrastring1");
235 EXPECT_FIND_("TRACE_EVENT_END_ETW call");
236 EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW call");
237 EXPECT_FIND_("TRACE_EVENT0 call");
238 {
239 std::string ph_begin;
240 std::string ph_end;
241 EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call")));
242 EXPECT_TRUE((item && item->GetString("ph", &ph_begin)));
243 EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call",
244 item)));
245 EXPECT_TRUE((item && item->GetString("ph", &ph_end)));
246 EXPECT_EQ("B", ph_begin);
247 EXPECT_EQ("E", ph_end);
248 }
249 EXPECT_FIND_("TRACE_EVENT1 call");
250 EXPECT_FIND_("TRACE_EVENT2 call");
251 EXPECT_SUB_FIND_("name1");
252 EXPECT_SUB_FIND_("value1");
253 EXPECT_SUB_FIND_("name2");
254 EXPECT_SUB_FIND_("value2");
255 EXPECT_FIND_("TRACE_EVENT_INSTANT0 call");
256 EXPECT_FIND_("TRACE_EVENT_INSTANT1 call");
257 EXPECT_FIND_("TRACE_EVENT_INSTANT2 call");
258 EXPECT_SUB_FIND_("name1");
259 EXPECT_SUB_FIND_("value1");
260 EXPECT_SUB_FIND_("name2");
261 EXPECT_SUB_FIND_("value2");
262 EXPECT_FIND_("TRACE_EVENT_BEGIN0 call");
263 EXPECT_FIND_("TRACE_EVENT_BEGIN1 call");
264 EXPECT_FIND_("TRACE_EVENT_BEGIN2 call");
265 EXPECT_SUB_FIND_("name1");
266 EXPECT_SUB_FIND_("value1");
267 EXPECT_SUB_FIND_("name2");
268 EXPECT_SUB_FIND_("value2");
269 EXPECT_FIND_("TRACE_EVENT_END0 call");
270 EXPECT_FIND_("TRACE_EVENT_END1 call");
271 EXPECT_FIND_("TRACE_EVENT_END2 call");
272 EXPECT_SUB_FIND_("name1");
273 EXPECT_SUB_FIND_("value1");
274 EXPECT_SUB_FIND_("name2");
275 EXPECT_SUB_FIND_("value2");
276}
277
278} // namespace
279
280// Simple Test for emitting data and validating it was received.
281TEST_F(TraceEventTestFixture, DataCaptured) {
282 ManualTestSetUp();
283 TraceLog::GetInstance()->SetEnabled(true);
284
285 DataCapturedCallTraces(NULL);
286
287 TraceLog::GetInstance()->SetEnabled(false);
288
289 DataCapturedValidateTraces(trace_parsed_, trace_string_);
290}
291
jbates@chromium.orgb3cab862011-05-14 08:30:35 +0900292// Simple Test for time threshold events.
293TEST_F(TraceEventTestFixture, DataCapturedThreshold) {
294 ManualTestSetUp();
295 TraceLog::GetInstance()->SetEnabled(true);
296
297 // Test that events at the same level are properly filtered by threshold.
298 {
299 TRACE_EVENT_IF_LONGER_THAN0(100, "time", "threshold 100");
300 TRACE_EVENT_IF_LONGER_THAN0(1000, "time", "threshold 1000");
301 TRACE_EVENT_IF_LONGER_THAN0(10000, "time", "threshold 10000");
302 // 100+ seconds to avoid flakiness.
303 TRACE_EVENT_IF_LONGER_THAN0(100000000, "time", "threshold long1");
304 TRACE_EVENT_IF_LONGER_THAN0(200000000, "time", "threshold long2");
305 base::PlatformThread::Sleep(20); // 20000 us
306 }
307
308 // Test that a normal nested event remains after it's parent event is dropped.
309 {
310 TRACE_EVENT_IF_LONGER_THAN0(1000000, "time", "2threshold10000");
311 {
312 TRACE_EVENT0("time", "nonthreshold1");
313 }
314 }
315
316 // Test that parent thresholded events are dropped while some nested events
317 // remain.
318 {
319 TRACE_EVENT0("time", "nonthreshold3");
320 {
321 TRACE_EVENT_IF_LONGER_THAN0(200000000, "time", "3thresholdlong2");
322 {
323 TRACE_EVENT_IF_LONGER_THAN0(100000000, "time", "3thresholdlong1");
324 {
325 TRACE_EVENT_IF_LONGER_THAN0(10000, "time", "3threshold10000");
326 {
327 TRACE_EVENT_IF_LONGER_THAN0(1000, "time", "3threshold1000");
328 {
329 TRACE_EVENT_IF_LONGER_THAN0(100, "time", "3threshold100");
330 base::PlatformThread::Sleep(20);
331 }
332 }
333 }
334 }
335 }
336 }
337
338 // Test that child thresholded events are dropped while some parent events
339 // remain.
340 {
341 TRACE_EVENT0("time", "nonthreshold4");
342 {
343 TRACE_EVENT_IF_LONGER_THAN0(100, "time", "4threshold100");
344 {
345 TRACE_EVENT_IF_LONGER_THAN0(1000, "time", "4threshold1000");
346 {
347 TRACE_EVENT_IF_LONGER_THAN0(10000, "time", "4threshold10000");
348 {
349 TRACE_EVENT_IF_LONGER_THAN0(100000000, "time",
350 "4thresholdlong1");
351 {
352 TRACE_EVENT_IF_LONGER_THAN0(200000000, "time",
353 "4thresholdlong2");
354 base::PlatformThread::Sleep(20);
355 }
356 }
357 }
358 }
359 }
360 }
361
362 TraceLog::GetInstance()->SetEnabled(false);
363
364#define EXPECT_FIND_BE_(str) \
365 EXPECT_TRUE(FindNamePhase(str, "B")); \
366 EXPECT_TRUE(FindNamePhase(str, "E"))
367#define EXPECT_NOT_FIND_BE_(str) \
368 EXPECT_FALSE(FindNamePhase(str, "B")); \
369 EXPECT_FALSE(FindNamePhase(str, "E"))
370
371 EXPECT_FIND_BE_("threshold 100");
372 EXPECT_FIND_BE_("threshold 1000");
373 EXPECT_FIND_BE_("threshold 10000");
374 EXPECT_NOT_FIND_BE_("threshold long1");
375 EXPECT_NOT_FIND_BE_("threshold long2");
376
377 EXPECT_NOT_FIND_BE_("2threshold10000");
378 EXPECT_FIND_BE_("nonthreshold1");
379
380 EXPECT_FIND_BE_("nonthreshold3");
381 EXPECT_FIND_BE_("3threshold100");
382 EXPECT_FIND_BE_("3threshold1000");
383 EXPECT_FIND_BE_("3threshold10000");
384 EXPECT_NOT_FIND_BE_("3thresholdlong1");
385 EXPECT_NOT_FIND_BE_("3thresholdlong2");
386
387 EXPECT_FIND_BE_("nonthreshold4");
388 EXPECT_FIND_BE_("4threshold100");
389 EXPECT_FIND_BE_("4threshold1000");
390 EXPECT_FIND_BE_("4threshold10000");
391 EXPECT_NOT_FIND_BE_("4thresholdlong1");
392 EXPECT_NOT_FIND_BE_("4thresholdlong2");
393}
394
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900395// Test that data sent from other threads is gathered
396TEST_F(TraceEventTestFixture, DataCapturedOnThread) {
397 ManualTestSetUp();
398 TraceLog::GetInstance()->SetEnabled(true);
399
400 Thread thread("1");
401 WaitableEvent task_complete_event(false, false);
402 thread.Start();
403
404 thread.message_loop()->PostTask(
405 FROM_HERE, NewRunnableFunction(&DataCapturedCallTraces,
406 &task_complete_event));
407 task_complete_event.Wait();
408
409 TraceLog::GetInstance()->SetEnabled(false);
410 thread.Stop();
411 DataCapturedValidateTraces(trace_parsed_, trace_string_);
412}
413
414namespace {
415
416void DataCapturedCallManyTraces(int thread_id, int num_events,
417 WaitableEvent* task_complete_event) {
418 for (int i = 0; i < num_events; i++) {
419 TRACE_EVENT_INSTANT2("all", "multi thread event",
420 "thread", thread_id,
421 "event", i);
422 }
423
424 if (task_complete_event)
425 task_complete_event->Signal();
426}
427
428void DataCapturedValidateManyTraces(const ListValue& trace_parsed,
429 const std::string& trace_string,
430 int num_threads, int num_events) {
431 std::map<int, std::map<int, bool> > results;
432
433 size_t trace_parsed_count = trace_parsed.GetSize();
434 for (size_t i = 0; i < trace_parsed_count; i++) {
435 Value* value = NULL;
436 trace_parsed.Get(i, &value);
437 if (!value || value->GetType() != Value::TYPE_DICTIONARY)
438 continue;
439 DictionaryValue* dict = static_cast<DictionaryValue*>(value);
440 std::string name;
441 dict->GetString("name", &name);
442 if (name != "multi thread event")
443 continue;
444
445 int thread = 0;
446 int event = 0;
447 EXPECT_TRUE(dict->GetInteger("args.thread", &thread));
448 EXPECT_TRUE(dict->GetInteger("args.event", &event));
449 results[thread][event] = true;
450 }
451
452 EXPECT_FALSE(results[-1][-1]);
453 for (int thread = 0; thread < num_threads; thread++) {
454 for (int event = 0; event < num_events; event++) {
455 EXPECT_TRUE(results[thread][event]);
456 }
457 }
458}
459
460} // namespace
461
462// Test that data sent from multiple threads is gathered
463TEST_F(TraceEventTestFixture, DataCapturedManyThreads) {
464 ManualTestSetUp();
465 TraceLog::GetInstance()->SetEnabled(true);
466
467 const int num_threads = 4;
468 const int num_events = 4000;
469 Thread* threads[num_threads];
470 WaitableEvent* task_complete_events[num_threads];
471 for (int i = 0; i < num_threads; i++) {
472 threads[i] = new Thread(StringPrintf("Thread %d", i).c_str());
473 task_complete_events[i] = new WaitableEvent(false, false);
474 threads[i]->Start();
475 threads[i]->message_loop()->PostTask(
476 FROM_HERE, NewRunnableFunction(&DataCapturedCallManyTraces,
477 i, num_events, task_complete_events[i]));
478 }
479
480 for (int i = 0; i < num_threads; i++) {
481 task_complete_events[i]->Wait();
482 }
483
484 TraceLog::GetInstance()->SetEnabled(false);
485
486 for (int i = 0; i < num_threads; i++) {
487 threads[i]->Stop();
488 delete threads[i];
489 delete task_complete_events[i];
490 }
491
492 DataCapturedValidateManyTraces(trace_parsed_, trace_string_,
493 num_threads, num_events);
494}
495
496void TraceCallsWithCachedCategoryPointersPointers(const char* name_str) {
497 TRACE_EVENT0("category name1", name_str);
498 TRACE_EVENT_INSTANT0("category name2", name_str);
499 TRACE_EVENT_BEGIN0("category name3", name_str);
500 TRACE_EVENT_END0("category name4", name_str);
501}
502
503// Test trace calls made after tracing singleton shut down.
504//
505// The singleton is destroyed by our base::AtExitManager, but there can be
506// code still executing as the C++ static objects are destroyed. This test
507// forces the singleton to destroy early, and intentinally makes trace calls
508// afterwards.
509TEST_F(TraceEventTestFixture, AtExit) {
510 // Repeat this test a few times. Besides just showing robustness, it also
511 // allows us to test that events at shutdown do not appear with valid events
512 // recorded after the system is started again.
513 for (int i = 0; i < 4; i++) {
514 // Scope to contain the then destroy the TraceLog singleton.
515 {
516 base::ShadowingAtExitManager exit_manager_will_destroy_singletons;
517
518 // Setup TraceLog singleton inside this test's exit manager scope
519 // so that it will be destroyed when this scope closes.
520 ManualTestSetUp();
521
522 TRACE_EVENT_INSTANT0("all", "not recorded; system not enabled");
523
524 TraceLog::GetInstance()->SetEnabled(true);
525
526 TRACE_EVENT_INSTANT0("all", "is recorded 1; system has been enabled");
527 // Trace calls that will cache pointers to categories; they're valid here
528 TraceCallsWithCachedCategoryPointersPointers(
529 "is recorded 2; system has been enabled");
530
531 TraceLog::GetInstance()->SetEnabled(false);
532 } // scope to destroy singleton
533 ASSERT_FALSE(TraceLog::GetInstance());
534
535 // Now that singleton is destroyed, check what trace events were recorded
536 DictionaryValue* item = NULL;
537 ListValue& trace_parsed = trace_parsed_;
538 EXPECT_FIND_("is recorded 1");
539 EXPECT_FIND_("is recorded 2");
540 EXPECT_NOT_FIND_("not recorded");
541
542 // Make additional trace event calls on the shutdown system. They should
543 // all pass cleanly, but the data not be recorded. We'll verify that next
544 // time around the loop (the only way to flush the trace buffers).
545 TRACE_EVENT_BEGIN_ETW("not recorded; system shutdown", 0, NULL);
546 TRACE_EVENT_END_ETW("not recorded; system shutdown", 0, NULL);
547 TRACE_EVENT_INSTANT_ETW("not recorded; system shutdown", 0, NULL);
548 TRACE_EVENT0("all", "not recorded; system shutdown");
549 TRACE_EVENT_INSTANT0("all", "not recorded; system shutdown");
550 TRACE_EVENT_BEGIN0("all", "not recorded; system shutdown");
551 TRACE_EVENT_END0("all", "not recorded; system shutdown");
552
553 TRACE_EVENT0("new category 0!", "not recorded; system shutdown");
554 TRACE_EVENT_INSTANT0("new category 1!", "not recorded; system shutdown");
555 TRACE_EVENT_BEGIN0("new category 2!", "not recorded; system shutdown");
556 TRACE_EVENT_END0("new category 3!", "not recorded; system shutdown");
557
558 // Cached categories should be safe to check, and still disable traces
559 TraceCallsWithCachedCategoryPointersPointers(
560 "not recorded; system shutdown");
561 }
562}
563
joth@chromium.org113de992011-07-21 21:28:59 +0900564TEST_F(TraceEventTestFixture, NormallyNoDeepCopy) {
565 // Test that the TRACE_EVENT macros do not deep-copy their string. If they
566 // do so it may indicate a performance regression, but more-over it would
567 // make the DEEP_COPY overloads redundant.
568 ManualTestSetUp();
569
570 std::string name_string("event name");
571
572 TraceLog::GetInstance()->SetEnabled(true);
573 TRACE_EVENT_INSTANT0("category", name_string.c_str());
574
575 // Modify the string in place (a wholesale reassignment may leave the old
576 // string intact on the heap).
577 name_string[0] = '@';
578
579 TraceLog::GetInstance()->SetEnabled(false);
580
581 EXPECT_FALSE(FindTraceEntry(trace_parsed_, "event name"));
582 EXPECT_TRUE(FindTraceEntry(trace_parsed_, name_string.c_str()));
583}
584
585TEST_F(TraceEventTestFixture, DeepCopy) {
586 ManualTestSetUp();
587
588 static const char kOriginalName1[] = "name1";
589 static const char kOriginalName2[] = "name2";
590 static const char kOriginalName3[] = "name3";
591 std::string name1(kOriginalName1);
592 std::string name2(kOriginalName2);
593 std::string name3(kOriginalName3);
594 std::string arg1("arg1");
595 std::string arg2("arg2");
596 std::string val1("val1");
597 std::string val2("val2");
598
599 TraceLog::GetInstance()->SetEnabled(true);
600 TRACE_EVENT_COPY_INSTANT0("category", name1.c_str());
601 TRACE_EVENT_COPY_BEGIN1("category", name2.c_str(),
602 arg1.c_str(), 5);
603 TRACE_EVENT_COPY_END2("category", name3.c_str(),
604 arg1.c_str(), val1.c_str(),
605 arg2.c_str(), val2.c_str());
606
607 // As per NormallyNoDeepCopy, modify the strings in place.
608 name1[0] = name2[0] = name3[0] = arg1[0] = arg2[0] = val1[0] = val2[0] = '@';
609
610 TraceLog::GetInstance()->SetEnabled(false);
611
612 EXPECT_FALSE(FindTraceEntry(trace_parsed_, name1.c_str()));
613 EXPECT_FALSE(FindTraceEntry(trace_parsed_, name2.c_str()));
614 EXPECT_FALSE(FindTraceEntry(trace_parsed_, name3.c_str()));
615
616 DictionaryValue* entry1 = FindTraceEntry(trace_parsed_, kOriginalName1);
617 DictionaryValue* entry2 = FindTraceEntry(trace_parsed_, kOriginalName2);
618 DictionaryValue* entry3 = FindTraceEntry(trace_parsed_, kOriginalName3);
619 ASSERT_TRUE(entry1);
620 ASSERT_TRUE(entry2);
621 ASSERT_TRUE(entry3);
622
623 int i;
624 EXPECT_FALSE(entry2->GetInteger("args.@rg1", &i));
625 EXPECT_TRUE(entry2->GetInteger("args.arg1", &i));
626 EXPECT_EQ(5, i);
627
628 std::string s;
629 EXPECT_TRUE(entry3->GetString("args.arg1", &s));
630 EXPECT_EQ("val1", s);
631 EXPECT_TRUE(entry3->GetString("args.arg2", &s));
632 EXPECT_EQ("val2", s);
633}
634
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900635} // namespace debug
636} // namespace base