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