head.js (9089B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 var { BrowserLoader } = ChromeUtils.importESModule( 7 "resource://devtools/shared/loader/browser-loader.sys.mjs" 8 ); 9 var { require } = BrowserLoader({ 10 baseURI: "resource://devtools/client/memory/", 11 window, 12 }); 13 var { Assert } = ChromeUtils.importESModule( 14 "resource://testing-common/Assert.sys.mjs" 15 ); 16 17 var EXPECTED_DTU_ASSERT_FAILURE_COUNT = 0; 18 19 SimpleTest.registerCleanupFunction(function () { 20 if ( 21 DevToolsUtils.assertionFailureCount !== EXPECTED_DTU_ASSERT_FAILURE_COUNT 22 ) { 23 ok( 24 false, 25 "Should have had the expected number of DevToolsUtils.assert() failures." + 26 "Expected " + 27 EXPECTED_DTU_ASSERT_FAILURE_COUNT + 28 ", got " + 29 DevToolsUtils.assertionFailureCount 30 ); 31 } 32 }); 33 34 var DevToolsUtils = require("resource://devtools/shared/DevToolsUtils.js"); 35 var { immutableUpdate } = DevToolsUtils; 36 37 var constants = require("resource://devtools/client/memory/constants.js"); 38 var { 39 censusDisplays, 40 diffingState, 41 labelDisplays, 42 dominatorTreeState, 43 snapshotState, 44 viewState, 45 censusState, 46 } = constants; 47 48 const { L10N } = require("resource://devtools/client/memory/utils.js"); 49 50 var models = require("resource://devtools/client/memory/models.js"); 51 52 var React = require("resource://devtools/client/shared/vendor/react.mjs"); 53 const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); 54 var ReactDOM = require("resource://devtools/client/shared/vendor/react-dom.mjs"); 55 var { createFactory } = React; 56 var Heap = createFactory( 57 require("resource://devtools/client/memory/components/Heap.js") 58 ); 59 var CensusTreeItem = createFactory( 60 require("resource://devtools/client/memory/components/CensusTreeItem.js") 61 ); 62 var DominatorTreeComponent = createFactory( 63 require("resource://devtools/client/memory/components/DominatorTree.js") 64 ); 65 var DominatorTreeItem = createFactory( 66 require("resource://devtools/client/memory/components/DominatorTreeItem.js") 67 ); 68 var ShortestPaths = createFactory( 69 require("resource://devtools/client/memory/components/ShortestPaths.js") 70 ); 71 var TreeMap = createFactory( 72 require("resource://devtools/client/memory/components/TreeMap.js") 73 ); 74 var SnapshotListItem = createFactory( 75 require("resource://devtools/client/memory/components/SnapshotListItem.js") 76 ); 77 var List = createFactory( 78 require("resource://devtools/client/memory/components/List.js") 79 ); 80 var Toolbar = createFactory( 81 require("resource://devtools/client/memory/components/Toolbar.js") 82 ); 83 84 // All tests are asynchronous. 85 SimpleTest.waitForExplicitFinish(); 86 87 var noop = () => {}; 88 89 var TEST_CENSUS_TREE_ITEM_PROPS = Object.freeze({ 90 item: Object.freeze({ 91 bytes: 10, 92 count: 1, 93 totalBytes: 10, 94 totalCount: 1, 95 name: "foo", 96 children: [ 97 Object.freeze({ 98 bytes: 10, 99 count: 1, 100 totalBytes: 10, 101 totalCount: 1, 102 name: "bar", 103 }), 104 ], 105 }), 106 depth: 0, 107 arrow: ">", 108 focused: true, 109 getPercentBytes: () => 50, 110 getPercentCount: () => 50, 111 showSign: false, 112 onViewSourceInDebugger: noop, 113 inverted: false, 114 }); 115 116 // Counter for mock DominatorTreeNode ids. 117 var TEST_NODE_ID_COUNTER = 0; 118 119 /** 120 * Create a mock DominatorTreeNode for testing, with sane defaults. Override any 121 * property by providing it on `opts`. Optionally pass child nodes as well. 122 * 123 * @param {object} opts 124 * @param {Array<DominatorTreeNode>?} children 125 * 126 * @returns {DominatorTreeNode} 127 */ 128 function makeTestDominatorTreeNode(opts, children) { 129 const nodeId = TEST_NODE_ID_COUNTER++; 130 131 const node = Object.assign( 132 { 133 nodeId, 134 label: ["other", "SomeType"], 135 shallowSize: 1, 136 retainedSize: (children || []).reduce( 137 (size, c) => size + c.retainedSize, 138 1 139 ), 140 parentId: undefined, 141 children, 142 moreChildrenAvailable: true, 143 }, 144 opts 145 ); 146 147 if (children && children.length) { 148 children.map(c => { 149 c.parentId = node.nodeId; 150 }); 151 } 152 153 return node; 154 } 155 156 var TEST_DOMINATOR_TREE = Object.freeze({ 157 dominatorTreeId: 666, 158 root: (function makeTree(depth = 0) { 159 let children; 160 if (depth <= 3) { 161 children = [ 162 makeTree(depth + 1), 163 makeTree(depth + 1), 164 makeTree(depth + 1), 165 ]; 166 } 167 return makeTestDominatorTreeNode({}, children); 168 })(), 169 expanded: new Set(), 170 focused: null, 171 error: null, 172 display: labelDisplays.coarseType, 173 activeFetchRequestCount: null, 174 state: dominatorTreeState.LOADED, 175 }); 176 177 var TEST_DOMINATOR_TREE_PROPS = Object.freeze({ 178 dominatorTree: TEST_DOMINATOR_TREE, 179 onLoadMoreSiblings: noop, 180 onViewSourceInDebugger: noop, 181 onExpand: noop, 182 onCollapse: noop, 183 }); 184 185 var TEST_SHORTEST_PATHS_PROPS = Object.freeze({ 186 graph: Object.freeze({ 187 nodes: [ 188 { id: 1, label: ["other", "SomeType"] }, 189 { id: 2, label: ["other", "SomeType"] }, 190 { id: 3, label: ["other", "SomeType"] }, 191 ], 192 edges: [ 193 { from: 1, to: 2, name: "1->2" }, 194 { from: 1, to: 3, name: "1->3" }, 195 { from: 2, to: 3, name: "2->3" }, 196 ], 197 }), 198 }); 199 200 var TEST_SNAPSHOT = Object.freeze({ 201 id: 1337, 202 selected: true, 203 path: "/fake/path/to/snapshot", 204 census: Object.freeze({ 205 report: Object.freeze({ 206 objects: Object.freeze({ count: 4, bytes: 400 }), 207 scripts: Object.freeze({ count: 3, bytes: 300 }), 208 strings: Object.freeze({ count: 2, bytes: 200 }), 209 other: Object.freeze({ count: 1, bytes: 100 }), 210 }), 211 display: Object.freeze({ 212 displayName: "Test Display", 213 tooltip: "Test display tooltup", 214 inverted: false, 215 breakdown: Object.freeze({ 216 by: "coarseType", 217 objects: Object.freeze({ by: "count", count: true, bytes: true }), 218 scripts: Object.freeze({ by: "count", count: true, bytes: true }), 219 strings: Object.freeze({ by: "count", count: true, bytes: true }), 220 other: Object.freeze({ by: "count", count: true, bytes: true }), 221 }), 222 }), 223 state: censusState.SAVED, 224 inverted: false, 225 filter: null, 226 expanded: new Set(), 227 focused: null, 228 parentMap: Object.freeze(Object.create(null)), 229 }), 230 dominatorTree: TEST_DOMINATOR_TREE, 231 error: null, 232 imported: false, 233 creationTime: 0, 234 state: snapshotState.READ, 235 }); 236 237 var TEST_HEAP_PROPS = Object.freeze({ 238 onSnapshotClick: noop, 239 onLoadMoreSiblings: noop, 240 onCensusExpand: noop, 241 onCensusCollapse: noop, 242 onDominatorTreeExpand: noop, 243 onDominatorTreeCollapse: noop, 244 onCensusFocus: noop, 245 onDominatorTreeFocus: noop, 246 onViewSourceInDebugger: noop, 247 diffing: null, 248 view: { state: viewState.CENSUS }, 249 snapshot: TEST_SNAPSHOT, 250 sizes: Object.freeze({ shortestPathsSize: 0.5 }), 251 onShortestPathsResize: noop, 252 }); 253 254 var TEST_TOOLBAR_PROPS = Object.freeze({ 255 censusDisplays: [ 256 censusDisplays.coarseType, 257 censusDisplays.allocationStack, 258 censusDisplays.invertedAllocationStack, 259 ], 260 censusDisplay: censusDisplays.coarseType, 261 onTakeSnapshotClick: noop, 262 onImportClick: noop, 263 onCensusDisplayChange: noop, 264 onToggleRecordAllocationStacks: noop, 265 allocations: models.allocations, 266 onToggleInverted: noop, 267 inverted: false, 268 filterString: null, 269 setFilterString: noop, 270 diffing: null, 271 onToggleDiffing: noop, 272 view: { state: viewState.CENSUS }, 273 onViewChange: noop, 274 labelDisplays: [labelDisplays.coarseType, labelDisplays.allocationStack], 275 labelDisplay: labelDisplays.coarseType, 276 onLabelDisplayChange: noop, 277 snapshots: [], 278 }); 279 280 function makeTestCensusNode() { 281 return { 282 name: "Function", 283 bytes: 100, 284 totalBytes: 100, 285 count: 100, 286 totalCount: 100, 287 children: [], 288 }; 289 } 290 291 var TEST_TREE_MAP_PROPS = Object.freeze({ 292 treeMap: Object.freeze({ 293 report: { 294 name: null, 295 bytes: 0, 296 totalBytes: 400, 297 count: 0, 298 totalCount: 400, 299 children: [ 300 { 301 name: "objects", 302 bytes: 0, 303 totalBytes: 200, 304 count: 0, 305 totalCount: 200, 306 children: [makeTestCensusNode(), makeTestCensusNode()], 307 }, 308 { 309 name: "other", 310 bytes: 0, 311 totalBytes: 200, 312 count: 0, 313 totalCount: 200, 314 children: [makeTestCensusNode(), makeTestCensusNode()], 315 }, 316 ], 317 }, 318 }), 319 }); 320 321 var TEST_SNAPSHOT_LIST_ITEM_PROPS = Object.freeze({ 322 onClick: noop, 323 onSave: noop, 324 onDelete: noop, 325 item: TEST_SNAPSHOT, 326 index: 1234, 327 }); 328 329 function onNextAnimationFrame(fn) { 330 return () => requestAnimationFrame(() => requestAnimationFrame(fn)); 331 } 332 333 /** 334 * Render the provided ReactElement in the provided HTML container. 335 * Returns a Promise that will resolve the rendered element as a React 336 * component. 337 */ 338 function renderComponent(element, container) { 339 return new Promise(resolve => { 340 const component = ReactDOM.render( 341 element, 342 container, 343 onNextAnimationFrame(() => { 344 dumpn("Rendered = " + container.innerHTML); 345 resolve(component); 346 }) 347 ); 348 }); 349 } 350 351 function dumpn(msg) { 352 dump(`MEMORY-TEST: ${msg}\n`); 353 }