d2b8a2be5172aed203246fc7c8404bf589148ded
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / LayoutTests / inspector / profiler / heap-snapshot-test.js
1 var initialize_HeapSnapshotTest = function() {
2
3 InspectorTest.preloadPanel("profiles");
4
5 InspectorTest.createHeapSnapshotMockFactories = function() {
6
7 InspectorTest.createJSHeapSnapshotMockObject = function()
8 {
9     return {
10         _rootNodeIndex: 0,
11         _nodeTypeOffset: 0,
12         _nodeNameOffset: 1,
13         _nodeEdgeCountOffset: 2,
14         _nodeFieldCount: 3,
15         _edgeFieldsCount: 3,
16         _edgeTypeOffset: 0,
17         _edgeNameOffset: 1,
18         _edgeToNodeOffset: 2,
19         _nodeTypes: ["hidden", "object"],
20         _edgeTypes: ["element", "property", "shortcut"],
21         _edgeShortcutType: -1,
22         _edgeHiddenType: -1,
23         _edgeElementType: 0,
24         _realNodesLength: 18,
25         // Represents the following graph:
26         //   (numbers in parentheses indicate node offset)
27         //
28         //         -> A (3) --ac- C (9) -ce- E(15)
29         //       a/   |          /
30         //  "" (0)    1    - bc -
31         //       b\   v   /
32         //         -> B (6) -bd- D (12)
33         //
34         nodes: new Uint32Array([
35             0, 0, 2,    //  0: root
36             1, 1, 2,    //  3: A
37             1, 2, 2,    //  6: B
38             1, 3, 1,    //  9: C
39             1, 4, 0,    // 12: D
40             1, 5, 0]),  // 15: E
41         containmentEdges: new Uint32Array([
42             2,  6, 3,   //  0: shortcut 'a' to node 'A'
43             1,  7, 6,   //  3: property 'b' to node 'B'
44             0,  1, 6,   //  6: element '1' to node 'B'
45             1,  8, 9,   //  9: property 'ac' to node 'C'
46             1,  9, 9,   // 12: property 'bc' to node 'C'
47             1, 10, 12,  // 15: property 'bd' to node 'D'
48             1, 11, 15]),// 18: property 'ce' to node 'E'
49         strings: ["", "A", "B", "C", "D", "E", "a", "b", "ac", "bc", "bd", "ce"],
50         _firstEdgeIndexes: new Uint32Array([0, 6, 12, 18, 21, 21, 21]),
51         createNode: WebInspector.JSHeapSnapshot.prototype.createNode,
52         createEdge: WebInspector.JSHeapSnapshot.prototype.createEdge,
53         createRetainingEdge: WebInspector.JSHeapSnapshot.prototype.createRetainingEdge
54     };
55 };
56
57 InspectorTest.createHeapSnapshotMockRaw = function()
58 {
59     // Effectively the same graph as in createJSHeapSnapshotMockObject,
60     // but having full set of fields.
61     //
62     // A triple in parentheses indicates node index, self size and
63     // retained size.
64     //
65     //          --- A (7,2,2) --ac- C (21,4,10) -ce- E(35,6,6)
66     //         /    |                /
67     //  "" (0,0,20) 1       --bc-----
68     //         \    v      /
69     //          --- B (14,3,8) --bd- D (28,5,5)
70     //
71     return {
72         snapshot: {
73             meta: {
74                 node_fields: ["type", "name", "id", "self_size", "retained_size", "dominator", "edge_count"],
75                 node_types: [["hidden", "object"], "", "", "", "", "", ""],
76                 edge_fields: ["type", "name_or_index", "to_node"],
77                 edge_types: [["element", "property", "shortcut"], "", ""]
78             },
79             node_count: 6,
80             edge_count: 7},
81         nodes: [
82             0, 0, 1, 0, 20,  0, 2,  // root (0)
83             1, 1, 2, 2,  2,  0, 2,  // A (7)
84             1, 2, 3, 3,  8,  0, 2,  // B (14)
85             1, 3, 4, 4, 10,  0, 1,  // C (21)
86             1, 4, 5, 5,  5, 14, 0,  // D (28)
87             1, 5, 6, 6,  6, 21, 0], // E (35)
88         edges: [
89             // root node edges
90             1,  6,  7, // property 'a' to node 'A'
91             1,  7, 14, // property 'b' to node 'B'
92
93             // A node edges
94             0,  1, 14, // element 1 to node 'B'
95             1,  8, 21, // property 'ac' to node 'C'
96
97             // B node edges
98             1,  9, 21, // property 'bc' to node 'C'
99             1, 10, 28, // property 'bd' to node 'D'
100
101             // C node edges
102             1, 11, 35], // property 'ce' to node 'E'
103         strings: ["", "A", "B", "C", "D", "E", "a", "b", "ac", "bc", "bd", "ce"]
104     };
105 };
106
107 InspectorTest._postprocessHeapSnapshotMock = function(mock)
108 {
109     mock.nodes = new Uint32Array(mock.nodes);
110     mock.edges = new Uint32Array(mock.edges);
111     return mock;
112 };
113
114 InspectorTest.createHeapSnapshotMock = function()
115 {
116     return InspectorTest._postprocessHeapSnapshotMock(InspectorTest.createHeapSnapshotMockRaw());
117 };
118
119 InspectorTest.createHeapSnapshotMockWithDOM = function()
120 {
121     return InspectorTest._postprocessHeapSnapshotMock({
122         snapshot: {
123             meta: {
124                 node_fields: ["type", "name", "id", "edge_count"],
125                 node_types: [["hidden", "object", "synthetic"], "", "", ""],
126                 edge_fields: ["type", "name_or_index", "to_node"],
127                 edge_types: [["element", "hidden", "internal"], "", ""]
128             },
129             node_count: 13,
130             edge_count: 13
131         },
132         nodes: [
133             // A tree with Window objects.
134             //
135             //    |----->Window--->A
136             //    |             \
137             //    |----->Window--->B--->C
138             //    |        |     \
139             //  (root)   hidden   --->D--internal / "native"-->N
140             //    |          \        |
141             //    |----->E    H    internal
142             //    |                   v
143             //    |----->F--->G       M
144             //
145             /* (root) */    2,  0,  1, 4,
146             /* Window */    1, 11,  2, 2,
147             /* Window */    1, 11,  3, 3,
148             /* E */         2,  5,  4, 0,
149             /* F */         2,  6,  5, 1,
150             /* A */         1,  1,  6, 0,
151             /* B */         1,  2,  7, 1,
152             /* D */         1,  4,  8, 2,
153             /* H */         1,  8,  9, 0,
154             /* G */         1,  7, 10, 0,
155             /* C */         1,  3, 11, 0,
156             /* N */         1, 10, 12, 0,
157             /* M */         1,  9, 13, 0
158             ],
159         edges: [
160             /* from (root) */  0,  1,  4, 0, 2,  8, 0, 3, 12, 0, 4, 16,
161             /* from Window */  0,  1, 20, 0, 2, 24,
162             /* from Window */  0,  1, 24, 0, 2, 28, 1, 3, 32,
163             /* from F */       0,  1, 36,
164             /* from B */       0,  1, 40,
165             /* from D */       2, 12, 44, 2, 1, 48
166             ],
167         strings: ["", "A", "B", "C", "D", "E", "F", "G", "H", "M", "N", "Window", "native"]
168     });
169 };
170
171 InspectorTest.HeapNode = function(name, selfSize, type, id)
172 {
173     this._type = type || InspectorTest.HeapNode.Type.object;
174     this._name = name;
175     this._selfSize = selfSize || 0;
176     this._builder = null;
177     this._edges = {};
178     this._edgesCount = 0;
179     this._id = id;
180 }
181
182 InspectorTest.HeapNode.Type = {
183     "hidden": "hidden",
184     "array": "array",
185     "string": "string",
186     "object": "object",
187     "code": "code",
188     "closure": "closure",
189     "regexp": "regexp",
190     "number": "number",
191     "native": "native",
192     "synthetic": "synthetic"
193 };
194
195 InspectorTest.HeapNode.prototype = {
196     linkNode: function(node, type, nameOrIndex)
197     {
198         if (!this._builder)
199             throw new Error("parent node is not connected to a snapshot");
200
201         if (!node._builder)
202             node._setBuilder(this._builder);
203
204         if (nameOrIndex === undefined)
205             nameOrIndex = this._edgesCount;
206         ++this._edgesCount;
207
208         if (nameOrIndex in this._edges)
209             throw new Error("Can't add edge with the same nameOrIndex. nameOrIndex: " + nameOrIndex + " oldNodeName: " + this._edges[nameOrIndex]._name + " newNodeName: " + node._name);
210         this._edges[nameOrIndex] = new InspectorTest.HeapEdge(node, type, nameOrIndex);
211     },
212
213     _setBuilder: function(builder)
214     {
215         if (this._builder)
216             throw new Error("node reusing is prohibited");
217
218         this._builder = builder;
219         this._ordinal = this._builder._registerNode(this);
220     },
221
222     _serialize: function(rawSnapshot)
223     {
224         rawSnapshot.nodes.push(this._builder.lookupNodeType(this._type));
225         rawSnapshot.nodes.push(this._builder.lookupOrAddString(this._name));
226         // JS engine snapshot impementation generates monotonicaly increasing odd id for JS objects,
227         // and even ids based on a hash for native DOMObject groups.
228         rawSnapshot.nodes.push(this._id || this._ordinal * 2 + 1);
229         rawSnapshot.nodes.push(this._selfSize);
230         rawSnapshot.nodes.push(0);                               // retained_size
231         rawSnapshot.nodes.push(0);                               // dominator
232         rawSnapshot.nodes.push(Object.keys(this._edges).length); // edge_count
233
234         for (var i in this._edges)
235             this._edges[i]._serialize(rawSnapshot);
236     }
237 }
238
239 InspectorTest.HeapEdge = function(targetNode, type, nameOrIndex)
240 {
241     this._targetNode = targetNode;
242     this._type = type;
243     this._nameOrIndex = nameOrIndex;
244 }
245
246 InspectorTest.HeapEdge.prototype = {
247     _serialize: function(rawSnapshot)
248     {
249         if (!this._targetNode._builder)
250             throw new Error("Inconsistent state of node: " + this._name + " no builder assigned");
251         var builder = this._targetNode._builder;
252         rawSnapshot.edges.push(builder.lookupEdgeType(this._type));
253         rawSnapshot.edges.push(typeof this._nameOrIndex === "string" ? builder.lookupOrAddString(this._nameOrIndex) : this._nameOrIndex);
254         rawSnapshot.edges.push(this._targetNode._ordinal * builder.nodeFieldsCount); // index
255     }
256 }
257
258 InspectorTest.HeapEdge.Type = {
259     "context": "context",
260     "element": "element",
261     "property": "property",
262     "internal": "internal",
263     "hidden": "hidden",
264     "shortcut": "shortcut",
265     "weak": "weak"
266 };
267
268 InspectorTest.HeapSnapshotBuilder = function()
269 {
270     this._nodes = [];
271     this._string2id = {};
272     this._strings = [];
273     this.nodeFieldsCount = 7;
274
275     this._nodeTypesMap = {};
276     this._nodeTypesArray = [];
277     for (var nodeType in InspectorTest.HeapNode.Type) {
278         this._nodeTypesMap[nodeType] = this._nodeTypesArray.length
279         this._nodeTypesArray.push(nodeType);
280     }
281
282     this._edgeTypesMap = {};
283     this._edgeTypesArray = [];
284     for (var edgeType in InspectorTest.HeapEdge.Type) {
285         this._edgeTypesMap[edgeType] = this._edgeTypesArray.length
286         this._edgeTypesArray.push(edgeType);
287     }
288
289     this.rootNode = new InspectorTest.HeapNode("root", 0, "object");
290     this.rootNode._setBuilder(this);
291 }
292
293 InspectorTest.HeapSnapshotBuilder.prototype = {
294     generateSnapshot: function()
295     {
296         var rawSnapshot = {
297             "snapshot": {
298                 "meta": {
299                     "node_fields": ["type","name","id","self_size","retained_size","dominator","edge_count"],
300                     "node_types": [
301                         this._nodeTypesArray,
302                         "string",
303                         "number",
304                         "number",
305                         "number",
306                         "number",
307                         "number"
308                     ],
309                     "edge_fields": ["type","name_or_index","to_node"],
310                     "edge_types": [
311                         this._edgeTypesArray,
312                         "string_or_number",
313                         "node"
314                     ]
315                 }
316             },
317             "nodes": [],
318             "edges":[],
319             "strings": []
320         };
321
322         for (var i = 0; i < this._nodes.length; ++i)
323             this._nodes[i]._serialize(rawSnapshot);
324
325         rawSnapshot.strings = this._strings.slice();
326
327         var meta = rawSnapshot.snapshot.meta;
328         rawSnapshot.snapshot.edge_count = rawSnapshot.edges.length / meta.edge_fields.length;
329         rawSnapshot.snapshot.node_count = rawSnapshot.nodes.length / meta.node_fields.length;
330
331         return rawSnapshot;
332     },
333
334     createJSHeapSnapshot: function()
335     {
336         var parsedSnapshot = InspectorTest._postprocessHeapSnapshotMock(this.generateSnapshot());
337         return new WebInspector.JSHeapSnapshot(parsedSnapshot, new WebInspector.HeapSnapshotProgress());
338     },
339
340     _registerNode: function(node)
341     {
342         this._nodes.push(node);
343         return this._nodes.length - 1;
344     },
345
346     lookupNodeType: function(typeName)
347     {
348         if (typeName === undefined)
349             throw new Error("wrong node type: " + typeName);
350         if (!typeName in this._nodeTypesMap)
351             throw new Error("wrong node type name: " + typeName);
352         return this._nodeTypesMap[typeName];
353     },
354
355     lookupEdgeType: function(typeName)
356     {
357         if (!typeName in this._edgeTypesMap)
358             throw new Error("wrong edge type name: " + typeName);
359         return this._edgeTypesMap[typeName];
360     },
361
362     lookupOrAddString: function(string)
363     {
364         if (string in this._string2id)
365             return this._string2id[string];
366         this._string2id[string] = this._strings.length;
367         this._strings.push(string);
368         return this._strings.length - 1;
369     }
370 }
371
372 InspectorTest.createHeapSnapshot = function(instanceCount, firstId)
373 {
374     // Mocking results of running the following code:
375     //
376     // function A() { this.a = this; }
377     // function B() { this.a = new A(); }
378     // for (var i = 0; i < instanceCount; ++i) window[i] = new B();
379     //
380     // Set A and B object sizes to pseudo random numbers. It is used in sorting tests.
381
382     var seed = 881669;
383     function pseudoRandom(limit) {
384         seed = ((seed * 355109 + 153763) >> 2) & 0xffff;
385         return seed % limit;
386     }
387
388     var builder = new InspectorTest.HeapSnapshotBuilder();
389     var rootNode = builder.rootNode;
390
391     var gcRootsNode = new InspectorTest.HeapNode("(GC roots)", 0, InspectorTest.HeapNode.Type.synthetic);
392     rootNode.linkNode(gcRootsNode, InspectorTest.HeapEdge.Type.element);
393
394     var windowNode = new InspectorTest.HeapNode("Window", 20);
395     rootNode.linkNode(windowNode, InspectorTest.HeapEdge.Type.shortcut);
396     gcRootsNode.linkNode(windowNode, InspectorTest.HeapEdge.Type.element);
397
398     for (var i = 0; i < instanceCount; ++i) {
399         var sizeOfB = pseudoRandom(20) + 1;
400         var nodeB = new InspectorTest.HeapNode("B", sizeOfB, undefined, firstId++);
401         windowNode.linkNode(nodeB, InspectorTest.HeapEdge.Type.element);
402         var sizeOfA = pseudoRandom(50) + 1;
403         var nodeA = new InspectorTest.HeapNode("A", sizeOfA, undefined, firstId++);
404         nodeB.linkNode(nodeA, InspectorTest.HeapEdge.Type.property, "a");
405         nodeA.linkNode(nodeA, InspectorTest.HeapEdge.Type.property, "a");
406     }
407     return builder.generateSnapshot();
408 }
409
410 }
411
412 InspectorTest.createHeapSnapshotMockFactories();
413
414
415 InspectorTest.startProfilerTest = function(callback)
416 {
417     WebInspector.settings.showAdvancedHeapSnapshotProperties.set(true);
418
419     InspectorTest.addResult("Profiler was enabled.");
420     // We mock out HeapProfilerAgent -- as DRT runs in single-process mode, Inspector
421     // and test share the same heap. Taking a snapshot takes too long for a test,
422     // so we provide synthetic snapshots.
423     InspectorTest._panelReset = InspectorTest.override(WebInspector.panels.profiles, "_reset", function(){}, true);
424     InspectorTest.addSniffer(WebInspector.HeapSnapshotView.prototype, "show", InspectorTest._snapshotViewShown, true);
425
426     // Reduce the number of populated nodes to speed up testing.
427     WebInspector.HeapSnapshotContainmentDataGrid.prototype.defaultPopulateCount = function() { return 10; };
428     WebInspector.HeapSnapshotConstructorsDataGrid.prototype.defaultPopulateCount = function() { return 10; };
429     WebInspector.HeapSnapshotDiffDataGrid.prototype.defaultPopulateCount = function() { return 5; };
430     InspectorTest.addResult("Detailed heap profiles were enabled.");
431     InspectorTest.safeWrap(callback)();
432 };
433
434 InspectorTest.completeProfilerTest = function()
435 {
436     // There is no way to disable detailed heap profiles.
437     InspectorTest.addResult("");
438     InspectorTest.addResult("Profiler was disabled.");
439     InspectorTest.completeTest();
440 };
441
442 InspectorTest.runHeapSnapshotTestSuite = function(testSuite)
443 {
444     var testSuiteTests = testSuite.slice();
445     var completeTestStack;
446
447     function runner()
448     {
449         if (!testSuiteTests.length) {
450             if (completeTestStack)
451                 InspectorTest.addResult("FAIL: test already completed at " + completeTestStack);
452             InspectorTest.completeProfilerTest();
453             completeTestStack = new Error().stack;
454             return;
455         }
456
457         var nextTest = testSuiteTests.shift();
458         InspectorTest.addResult("");
459         InspectorTest.addResult("Running: " + /function\s([^(]*)/.exec(nextTest)[1]);
460         InspectorTest._panelReset.call(WebInspector.panels.profiles);
461         InspectorTest.safeWrap(nextTest)(runner, runner);
462     }
463
464     InspectorTest.startProfilerTest(runner);
465 };
466
467 InspectorTest.assertColumnContentsEqual = function(reference, actual)
468 {
469     var length = Math.min(reference.length, actual.length);
470     for (var i = 0; i < length; ++i)
471         InspectorTest.assertEquals(reference[i], actual[i], "row " + i);
472     if (reference.length > length)
473         InspectorTest.addResult("extra rows in reference array:\n" + reference.slice(length).join("\n"));
474     else if (actual.length > length)
475         InspectorTest.addResult("extra rows in actual array:\n" + actual.slice(length).join("\n"));
476 };
477
478 InspectorTest.checkArrayIsSorted = function(contents, sortType, sortOrder)
479 {
480     function simpleComparator(a, b)
481     {
482         return a < b ? -1 : (a > b ? 1 : 0);
483     }
484     function parseSize(size)
485     {
486         // Remove thousands separator.
487         return parseInt(size.replace(/[\u2009,]/g, ""), 10);
488     }
489     var extractor = {
490         text: function (data) { data; },
491         number: function (data) { return parseInt(data, 10); },
492         size: parseSize,
493         name: function (data) { return data; },
494         id: function (data) { return parseInt(data, 10); }
495     }[sortType];
496
497     if (!extractor) {
498         InspectorTest.addResult("Invalid sort type: " + sortType);
499         return;
500     }
501
502     var acceptableComparisonResult;
503     if (sortOrder === WebInspector.DataGrid.Order.Ascending) {
504         acceptableComparisonResult = -1;
505     } else if (sortOrder === WebInspector.DataGrid.Order.Descending) {
506         acceptableComparisonResult = 1;
507     } else {
508         InspectorTest.addResult("Invalid sort order: " + sortOrder);
509         return;
510     }
511
512     for (var i = 0; i < contents.length - 1; ++i) {
513         var a = extractor(contents[i]);
514         var b = extractor(contents[i + 1]);
515         var result = simpleComparator(a, b);
516         if (result !== 0 && result !== acceptableComparisonResult) {
517             InspectorTest.addResult("Elements " + i + " and " + (i + 1) + " are out of order: " + a + " " + b + " (" + sortOrder + ")");
518         }
519     }
520 };
521
522 InspectorTest.clickColumn = function(column, callback)
523 {
524     callback = InspectorTest.safeWrap(callback);
525     var cell = this._currentGrid()._headerTableHeaders[column.identifier];
526     var event = { target: { enclosingNodeOrSelfWithNodeName: function() { return cell; } } };
527
528     function sortingComplete()
529     {
530         InspectorTest._currentGrid().removeEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.SortingComplete, sortingComplete, this);
531         InspectorTest.assertEquals(column.identifier, this._currentGrid().sortColumnIdentifier(), "unexpected sorting");
532         column.sort = this._currentGrid().sortOrder();
533         function callCallback()
534         {
535             callback(column);
536         }
537         setTimeout(callCallback, 0);
538     }
539     InspectorTest._currentGrid().addEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.SortingComplete, sortingComplete, this);
540     this._currentGrid()._clickInHeaderCell(event);
541 };
542
543 InspectorTest.clickRowAndGetRetainers = function(row, callback)
544 {
545     callback = InspectorTest.safeWrap(callback);
546     var event = {
547         target: {
548             enclosingNodeOrSelfWithNodeName: function() { return row._element; },
549             selectedNode: row
550         }
551     };
552     this._currentGrid()._mouseDownInDataTable(event);
553     var rootNode = InspectorTest.currentProfileView()._retainmentDataGrid.rootNode();
554     function populateComplete()
555     {
556         rootNode.removeEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this);
557         callback(rootNode);
558     }
559     rootNode.addEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this);
560 };
561
562 InspectorTest.clickShowMoreButton = function(buttonName, row, callback)
563 {
564     callback = InspectorTest.safeWrap(callback);
565     var parent = row.parent;
566     function populateComplete()
567     {
568         parent.removeEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this);
569         function callCallback()
570         {
571             callback(parent);
572         }
573         setTimeout(callCallback, 0);
574     }
575     parent.addEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this);
576     row[buttonName].click();
577 };
578
579 InspectorTest.columnContents = function(column, row)
580 {
581     // Make sure invisible nodes are removed from the view port.
582     this._currentGrid().updateVisibleNodes();
583     var columnOrdinal = InspectorTest.viewColumns().indexOf(column);
584     var result = [];
585     var parent = row || this._currentGrid().rootNode();
586     for (var node = parent.children[0]; node; node = node.traverseNextNode(true, parent, true)) {
587         if (!node.selectable)
588             continue;
589         var content = node.element().children[columnOrdinal];
590         // Do not inlcude percents
591         if (content.firstElementChild)
592             content = content.firstElementChild;
593         result.push(content.textContent);
594     }
595     return result;
596 };
597
598 InspectorTest.countDataRows = function(row, filter)
599 {
600     var result = 0;
601     filter = filter || function(node) { return node.selectable; };
602     for (var node = row.children[0]; node; node = node.traverseNextNode(true, row, true)) {
603         if (filter(node))
604             ++result;
605     }
606     return result;
607 };
608
609 InspectorTest.expandRow = function(row, callback)
610 {
611     callback = InspectorTest.safeWrap(callback);
612     function populateComplete()
613     {
614         row.removeEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this);
615         function callCallback()
616         {
617             callback(row);
618         }
619         setTimeout(callCallback, 0);
620     }
621     row.addEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this);
622     (function expand()
623     {
624         if (row.hasChildren)
625             row.expand();
626         else
627             setTimeout(expand, 0);
628     })();
629 };
630
631 InspectorTest.findAndExpandGCRoots = function(callback)
632 {
633     InspectorTest.findAndExpandRow("(GC roots)", callback);
634 };
635
636 InspectorTest.findAndExpandWindow = function(callback)
637 {
638     InspectorTest.findAndExpandRow("Window", callback);
639 };
640
641 InspectorTest.findAndExpandRow = function(name, callback)
642 {
643     callback = InspectorTest.safeWrap(callback);
644     var row = InspectorTest.findRow(name);
645     InspectorTest.assertEquals(true, !!row, '"' + name + '" row');
646     InspectorTest.expandRow(row, callback);
647 };
648
649 InspectorTest.findButtonsNode = function(row, startNode)
650 {
651     var result = 0;
652     for (var node = startNode || row.children[0]; node; node = node.traverseNextNode(true, row, true)) {
653         if (!node.selectable && node.showNext)
654             return node;
655     }
656     return null;
657 };
658
659 InspectorTest.findRow = function(name, parent)
660 {
661     function matcher(x)
662     {
663         return x._name === name;
664     };
665     return InspectorTest.findMatchingRow(matcher, parent);
666 };
667
668 InspectorTest.findMatchingRow = function(matcher, parent)
669 {
670     parent = parent || this._currentGrid().rootNode();
671     for (var node = parent.children[0]; node; node = node.traverseNextNode(true, parent, true)) {
672         if (matcher(node))
673             return node;
674     }
675     return null;
676 };
677
678 InspectorTest.switchToView = function(title, callback)
679 {
680     callback = InspectorTest.safeWrap(callback);
681     var view = WebInspector.panels.profiles.visibleView;
682     view._changePerspectiveAndWait(title, callback);
683     // Increase the grid container height so the viewport don't limit the number of nodes.
684     InspectorTest._currentGrid().scrollContainer.style.height = "10000px";
685 };
686
687 InspectorTest.takeAndOpenSnapshot = function(generator, callback)
688 {
689     callback = InspectorTest.safeWrap(callback);
690     var snapshot = generator();
691     var profileType =  WebInspector.ProfileTypeRegistry.instance.heapSnapshotProfileType;
692     function pushGeneratedSnapshot(reportProgress, callback2)
693     {
694         var profile = profileType.profileBeingRecorded();
695         if (reportProgress) {
696             profileType._reportHeapSnapshotProgress({data: {done: 50, total: 100, finished: false}});
697             profileType._reportHeapSnapshotProgress({data: {done: 100, total: 100, finished: true}});
698         }
699         snapshot.snapshot.typeId = "HEAP";
700         profileType._addHeapSnapshotChunk({data: JSON.stringify(snapshot)});
701         setTimeout(callback2, 0);
702     }
703     InspectorTest.override(HeapProfilerAgent, "takeHeapSnapshot", pushGeneratedSnapshot);
704     InspectorTest._takeAndOpenSnapshotCallback = callback;
705     profileType._takeHeapSnapshot(function() { });
706 };
707
708 InspectorTest.viewColumns = function()
709 {
710     return InspectorTest._currentGrid()._columnsArray;
711 };
712
713 InspectorTest.currentProfileView = function()
714 {
715     return WebInspector.panels.profiles.visibleView;
716 };
717
718 InspectorTest._currentGrid = function()
719 {
720     return this.currentProfileView()._dataGrid;
721 };
722
723 InspectorTest._snapshotViewShown = function()
724 {
725     if (InspectorTest._takeAndOpenSnapshotCallback) {
726         var callback = InspectorTest._takeAndOpenSnapshotCallback;
727         InspectorTest._takeAndOpenSnapshotCallback = null;
728         var dataGrid = this._dataGrid;
729         function sortingComplete()
730         {
731             dataGrid.removeEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.SortingComplete, sortingComplete, null);
732             callback();
733         }
734         dataGrid.addEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.SortingComplete, sortingComplete, null);
735     }
736 };
737
738 };