Unreviewed follow-up fix to test after r198353.
[WebKit-https.git] / LayoutTests / inspector / unit-tests / heap-snapshot.html
1 <!doctype html>
2 <html>
3 <head>
4 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
5 <script>
6 function test()
7 {
8     // Simple HeapSnapshot representation.
9
10     WebInspector.TestHeapSnapshotNode = class TestHeapSnapshotNode
11     {
12         constructor(identifier, className, size, internal)
13         {
14             this.id = identifier;
15             this.className = className;
16             this.size = size; 
17             this.internal = internal;
18             this.gcRoot = false;
19             this.outgoingEdges = [];
20             this.incomingEdges = [];
21         }
22     }
23
24     WebInspector.TestHeapSnapshotEdge = class TestHeapSnapshotEdge
25     {
26         constructor(from, to, type, data)
27         {
28             this.from = from;
29             this.to = to;
30             this.type = type;
31             this.data = data;
32         }
33     };
34
35     WebInspector.TestHeapSnapshot = class TestHeapSnapshot
36     {
37         constructor(rootNode, nodes, nodeMap)
38         {
39             console.assert(rootNode instanceof WebInspector.TestHeapSnapshotNode);
40             console.assert(nodes.every((n) => n instanceof WebInspector.TestHeapSnapshotNode));
41
42             this.rootNode = rootNode;
43             this.nodes = nodes;
44             this.nodeMap = nodeMap;
45             this.totalSize = nodes.reduce((sum, node) => sum += node.size, 0);
46             this.totalObjectCount = nodes.length - 1; // <root>.
47         }
48
49         static fromPayload(payload)
50         {
51             let {version, nodes, nodeClassNames, edges, edgeTypes, edgeNames} = payload;
52             console.assert(version === 1, "Only know how to handle JavaScriptCore Heap Snapshot Format Version 1");
53
54             let nodeMap = new Map;
55
56             // Turn nodes into real nodes.
57             let processedNodes = [];
58             for (let i = 0, length = nodes.length; i < length;) {
59                 let id = nodes[i++];
60                 let size = nodes[i++];
61                 let classNameIndex = nodes[i++];
62                 let internal = nodes[i++];
63
64                 let node = new WebInspector.TestHeapSnapshotNode(id, nodeClassNames[classNameIndex], size, !!internal);
65                 nodeMap.set(id, node);
66                 processedNodes.push(node);
67             }
68
69             // Turn edges into real edges and set them on the nodes.
70             for (let i = 0, length = edges.length; i < length;) {
71                 let fromIdentifier = edges[i++];
72                 let toIdentifier = edges[i++];
73                 let edgeTypeIndex = edges[i++];
74                 let data = edges[i++];
75
76                 let from = nodeMap.get(fromIdentifier);
77                 let to = nodeMap.get(toIdentifier);
78                 let type = edgeTypes[edgeTypeIndex];
79                 if (type === "Property" || type === "Variable")
80                     data = edgeNames[data];
81
82                 let edge = new WebInspector.TestHeapSnapshotEdge(from, to, type, data);
83                 from.outgoingEdges.push(edge);
84                 to.incomingEdges.push(edge);
85             }
86
87             // Root node.
88             let rootNode = nodeMap.get(0);
89             console.assert(rootNode, "Node with identifier 0 is the synthetic <root> node.");
90             console.assert(rootNode.outgoingEdges.length > 0, "This had better have children!");
91             console.assert(rootNode.incomingEdges.length === 0, "This had better not have back references!");
92
93             // Mark GC roots.
94             let rootNodeEdges = rootNode.outgoingEdges;
95             for (let i = 0, length = rootNodeEdges.length; i < length; ++i)
96                 rootNodeEdges[i].to.gcRoot = true;
97
98             return new WebInspector.TestHeapSnapshot(rootNode, processedNodes, nodeMap);
99         }
100
101         // Public
102
103         instancesWithClassName(className)
104         {
105             let results = [];
106             // Skip <root>.
107             for (let i = 1; i < this.nodes.length; ++i) {
108                 let node = this.nodes[i];
109                 if (node.className === className)
110                     results.push(node);
111             }
112             return results;
113         }
114     };
115
116     // ------
117
118     let suite = InspectorTest.createAsyncSuite("HeapSnapshot");
119
120     let snapshot = null;
121     let snapshotNodeForWindowObject = null;
122     let testSnapshot = null;
123     let testSnapshotNodeForWindowObject = null;
124
125     function compareNodes(node1, node2) {
126         return node1.id === node2.id
127             && node1.size === node2.size
128             && node1.className === node2.className
129             && node1.internal === node2.internal
130             && node1.gcRoot === node2.gcRoot;
131     }
132
133     suite.addTestCase({
134         name: "HeapSnapshotProxy data",
135         test: (resolve, reject) => {
136             HeapAgent.snapshot((error, timestamp, snapshotStringData) => {
137                 InspectorTest.expectThat(!error, "Should not have an error creating a snapshot.");
138                 testSnapshot = WebInspector.TestHeapSnapshot.fromPayload(JSON.parse(snapshotStringData));
139                 let workerProxy = WebInspector.HeapSnapshotWorkerProxy.singleton();
140                 workerProxy.createSnapshot(snapshotStringData, ({objectId, snapshot: serializedSnapshot}) => {
141                     snapshot = WebInspector.HeapSnapshotProxy.deserialize(objectId, serializedSnapshot);
142                     InspectorTest.assert(testSnapshot, "Created TestHeapSnapshot");
143                     InspectorTest.assert(snapshot, "Created HeapSnapshotProxy");
144                     InspectorTest.expectThat(snapshot.totalSize === testSnapshot.totalSize, "Snapshots totalSize should match.");
145                     InspectorTest.expectThat(snapshot.totalObjectCount === testSnapshot.totalObjectCount, "Snapshots totalObjectCount should match.");
146                     resolve();
147                 });
148             });
149         }
150     });
151
152     suite.addTestCase({
153         name: "HeapSnapshotProxy.prototype.instancesWithClassName",
154         test: (resolve, reject) => {
155             let windowObjects = testSnapshot.instancesWithClassName("Window")
156             let windowObjectCount = windowObjects.length;
157             let functionObjectCount = testSnapshot.instancesWithClassName("Function").length;
158             let stringCount = testSnapshot.instancesWithClassName("string").length;
159
160             snapshot.instancesWithClassName("Window", (windows) => {
161                 testSnapshotNodeForWindowObject = windowObjects[0]; // Used by later tests.
162                 snapshotNodeForWindowObject = windows[0]; // Used by later tests.
163
164                 InspectorTest.expectThat(windows.length > 0, "Should be at least 1 Window.");
165                 InspectorTest.expectThat(windows.length === windowObjectCount, "Window object count is expected.");
166                 InspectorTest.expectThat(windows.every((node) => node.className === "Window"), "Every className should be 'Window'.");
167             });
168
169             snapshot.instancesWithClassName("Function", (functions) => {
170                 InspectorTest.expectThat(functions.length > 0, "Should be at least 1 Function.");
171                 InspectorTest.expectThat(functions.length === functionObjectCount, "Function object count is expected.");
172                 InspectorTest.expectThat(functions.every((node) => node.className === "Function"), "Every className should be 'Function'.");
173             });
174
175             snapshot.instancesWithClassName("string", (strings) => {
176                 InspectorTest.expectThat(strings.length > 0, "Should be at least 1 string.");
177                 InspectorTest.expectThat(strings.length === stringCount, "string count is expected.");
178                 InspectorTest.expectThat(strings.every((node) => node.className === "string"), "Every className should be 'string'.");
179                 resolve();
180             });
181         }
182     });
183
184     suite.addTestCase({
185         name: "HeapSnapshotProxy.prototype.nodeWithIdentifier and HeapSnapshotNodeProxy data",
186         test: (resolve, reject) => {
187             snapshot.nodeWithIdentifier(testSnapshotNodeForWindowObject.id, (heapSnapshotNode) => {
188                 InspectorTest.expectThat(heapSnapshotNode.className === "Window", "Node className should be 'Window'.");
189                 InspectorTest.expectThat(heapSnapshotNode.id === testSnapshotNodeForWindowObject.id, "Node identifier should match.")
190                 InspectorTest.expectThat(heapSnapshotNode.size === testSnapshotNodeForWindowObject.size, "Node size should match.");
191                 InspectorTest.expectThat(heapSnapshotNode.internal === testSnapshotNodeForWindowObject.internal, "Node internal state should match.");
192                 InspectorTest.expectThat(heapSnapshotNode.gcRoot === testSnapshotNodeForWindowObject.gcRoot, "Node gcRoot state should match.");
193                 InspectorTest.expectThat(heapSnapshotNode.retainedSize >= heapSnapshotNode.size, "Node retainedSize should at least be the size.");
194                 resolve();
195             });
196         }
197     });
198
199     suite.addTestCase({
200         name: "HeapSnapshotProxy.prototype.allocationBucketCounts",
201         test: (resolve, reject) => {
202             let testSmall = 0, testMedium = 0, testLarge = 0;
203             const smallSize = 32, mediumSize = 128;
204             // Skip <root>.
205             for (let i = 1; i < testSnapshot.nodes.length; ++i) {
206                 let {size} = testSnapshot.nodes[i];
207                 if (size < smallSize)
208                     testSmall++;
209                 else if (size < mediumSize)
210                     testMedium++;
211                 else
212                     testLarge++;
213             }
214
215             snapshot.allocationBucketCounts([smallSize, mediumSize], (results) => {
216                 let [small, medium, large] = results;
217                 InspectorTest.expectThat(results.length === 3, "Result should have 3 buckets, for small/medium/large.");
218                 InspectorTest.expectThat(small === testSmall, "Small count should match.");
219                 InspectorTest.expectThat(medium === testMedium, "Medium count should match.");
220                 InspectorTest.expectThat(large === testLarge, "Large count should match.");
221                 resolve();
222             });
223         }
224     });
225
226     suite.addTestCase({
227         name: "HeapSnapshotNodeProxy.prototype.retainedNodes",
228         test: (resolve, reject) => {
229             let expectedNodes = testSnapshotNodeForWindowObject.outgoingEdges.map((edge) => edge.to);
230             expectedNodes.sort((a, b) => a.id - b.id);
231
232             snapshotNodeForWindowObject.retainedNodes((nodes) => {
233                 nodes.sort((a, b) => a.id - b.id);
234                 InspectorTest.assert(nodes.length > 0, "Test only makes since if there are retained nodes");
235                 InspectorTest.expectThat(nodes.length === expectedNodes.length, "Number of retained nodes should match.");
236                 InspectorTest.expectThat(nodes.every((node, i) => compareNodes(node, expectedNodes[i])), "Node values should match.");
237                 resolve();
238             });
239         }
240     });
241
242     suite.addTestCase({
243         name: "HeapSnapshotNodeProxy.prototype.retainers",
244         test: (resolve, reject) => {
245             let expectedNodes = testSnapshotNodeForWindowObject.incomingEdges.map((edge) => edge.from);
246             expectedNodes.sort((a, b) => a.id - b.id);
247
248             snapshotNodeForWindowObject.retainers((nodes) => {
249                 nodes.sort((a, b) => a.id - b.id);
250                 InspectorTest.assert(nodes.length > 0, "Test only makes since if there are retainer nodes");
251                 InspectorTest.expectThat(nodes.length === expectedNodes.length, "Number of retainer nodes should match.");
252                 InspectorTest.expectThat(nodes.every((node, i) => compareNodes(node, expectedNodes[i])), "Node values should match.");
253                 resolve();
254             });
255         }
256     });
257
258     suite.runTestCasesAndFinish();
259 }
260 </script>
261 </head>
262 <body onload="runTest()">
263     <p>Testing HeapSnapshot Worker and Proxy objects.</p>
264 </body>
265 </html>