/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; var { BrowserLoader } = ChromeUtils.import( "resource://devtools/shared/loader/browser-loader.js" ); var { require } = BrowserLoader({ baseURI: "resource://devtools/client/memory/", window, }); var { Assert } = ChromeUtils.importESModule( "resource://testing-common/Assert.sys.mjs" ); var EXPECTED_DTU_ASSERT_FAILURE_COUNT = 0; SimpleTest.registerCleanupFunction(function () { if ( DevToolsUtils.assertionFailureCount !== EXPECTED_DTU_ASSERT_FAILURE_COUNT ) { ok( false, "Should have had the expected number of DevToolsUtils.assert() failures." + "Expected " + EXPECTED_DTU_ASSERT_FAILURE_COUNT + ", got " + DevToolsUtils.assertionFailureCount ); } }); var DevToolsUtils = require("resource://devtools/shared/DevToolsUtils.js"); var { immutableUpdate } = DevToolsUtils; var constants = require("resource://devtools/client/memory/constants.js"); var { censusDisplays, diffingState, labelDisplays, dominatorTreeState, snapshotState, viewState, censusState, } = constants; const { L10N } = require("resource://devtools/client/memory/utils.js"); var models = require("resource://devtools/client/memory/models.js"); var Immutable = require("resource://devtools/client/shared/vendor/immutable.js"); var React = require("resource://devtools/client/shared/vendor/react.js"); const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); var ReactDOM = require("resource://devtools/client/shared/vendor/react-dom.js"); var { createFactory } = React; var Heap = createFactory( require("resource://devtools/client/memory/components/Heap.js") ); var CensusTreeItem = createFactory( require("resource://devtools/client/memory/components/CensusTreeItem.js") ); var DominatorTreeComponent = createFactory( require("resource://devtools/client/memory/components/DominatorTree.js") ); var DominatorTreeItem = createFactory( require("resource://devtools/client/memory/components/DominatorTreeItem.js") ); var ShortestPaths = createFactory( require("resource://devtools/client/memory/components/ShortestPaths.js") ); var TreeMap = createFactory( require("resource://devtools/client/memory/components/TreeMap.js") ); var SnapshotListItem = createFactory( require("resource://devtools/client/memory/components/SnapshotListItem.js") ); var List = createFactory( require("resource://devtools/client/memory/components/List.js") ); var Toolbar = createFactory( require("resource://devtools/client/memory/components/Toolbar.js") ); // All tests are asynchronous. SimpleTest.waitForExplicitFinish(); var noop = () => {}; var TEST_CENSUS_TREE_ITEM_PROPS = Object.freeze({ item: Object.freeze({ bytes: 10, count: 1, totalBytes: 10, totalCount: 1, name: "foo", children: [ Object.freeze({ bytes: 10, count: 1, totalBytes: 10, totalCount: 1, name: "bar", }), ], }), depth: 0, arrow: ">", focused: true, getPercentBytes: () => 50, getPercentCount: () => 50, showSign: false, onViewSourceInDebugger: noop, inverted: false, }); // Counter for mock DominatorTreeNode ids. var TEST_NODE_ID_COUNTER = 0; /** * Create a mock DominatorTreeNode for testing, with sane defaults. Override any * property by providing it on `opts`. Optionally pass child nodes as well. * * @param {Object} opts * @param {Array?} children * * @returns {DominatorTreeNode} */ function makeTestDominatorTreeNode(opts, children) { const nodeId = TEST_NODE_ID_COUNTER++; const node = Object.assign( { nodeId, label: ["other", "SomeType"], shallowSize: 1, retainedSize: (children || []).reduce( (size, c) => size + c.retainedSize, 1 ), parentId: undefined, children, moreChildrenAvailable: true, }, opts ); if (children && children.length) { children.map(c => { c.parentId = node.nodeId; }); } return node; } var TEST_DOMINATOR_TREE = Object.freeze({ dominatorTreeId: 666, root: (function makeTree(depth = 0) { let children; if (depth <= 3) { children = [ makeTree(depth + 1), makeTree(depth + 1), makeTree(depth + 1), ]; } return makeTestDominatorTreeNode({}, children); })(), expanded: new Set(), focused: null, error: null, display: labelDisplays.coarseType, activeFetchRequestCount: null, state: dominatorTreeState.LOADED, }); var TEST_DOMINATOR_TREE_PROPS = Object.freeze({ dominatorTree: TEST_DOMINATOR_TREE, onLoadMoreSiblings: noop, onViewSourceInDebugger: noop, onExpand: noop, onCollapse: noop, }); var TEST_SHORTEST_PATHS_PROPS = Object.freeze({ graph: Object.freeze({ nodes: [ { id: 1, label: ["other", "SomeType"] }, { id: 2, label: ["other", "SomeType"] }, { id: 3, label: ["other", "SomeType"] }, ], edges: [ { from: 1, to: 2, name: "1->2" }, { from: 1, to: 3, name: "1->3" }, { from: 2, to: 3, name: "2->3" }, ], }), }); var TEST_SNAPSHOT = Object.freeze({ id: 1337, selected: true, path: "/fake/path/to/snapshot", census: Object.freeze({ report: Object.freeze({ objects: Object.freeze({ count: 4, bytes: 400 }), scripts: Object.freeze({ count: 3, bytes: 300 }), strings: Object.freeze({ count: 2, bytes: 200 }), other: Object.freeze({ count: 1, bytes: 100 }), }), display: Object.freeze({ displayName: "Test Display", tooltip: "Test display tooltup", inverted: false, breakdown: Object.freeze({ by: "coarseType", objects: Object.freeze({ by: "count", count: true, bytes: true }), scripts: Object.freeze({ by: "count", count: true, bytes: true }), strings: Object.freeze({ by: "count", count: true, bytes: true }), other: Object.freeze({ by: "count", count: true, bytes: true }), }), }), state: censusState.SAVED, inverted: false, filter: null, expanded: new Set(), focused: null, parentMap: Object.freeze(Object.create(null)), }), dominatorTree: TEST_DOMINATOR_TREE, error: null, imported: false, creationTime: 0, state: snapshotState.READ, }); var TEST_HEAP_PROPS = Object.freeze({ onSnapshotClick: noop, onLoadMoreSiblings: noop, onCensusExpand: noop, onCensusCollapse: noop, onDominatorTreeExpand: noop, onDominatorTreeCollapse: noop, onCensusFocus: noop, onDominatorTreeFocus: noop, onViewSourceInDebugger: noop, diffing: null, view: { state: viewState.CENSUS }, snapshot: TEST_SNAPSHOT, sizes: Object.freeze({ shortestPathsSize: 0.5 }), onShortestPathsResize: noop, }); var TEST_TOOLBAR_PROPS = Object.freeze({ censusDisplays: [ censusDisplays.coarseType, censusDisplays.allocationStack, censusDisplays.invertedAllocationStack, ], censusDisplay: censusDisplays.coarseType, onTakeSnapshotClick: noop, onImportClick: noop, onCensusDisplayChange: noop, onToggleRecordAllocationStacks: noop, allocations: models.allocations, onToggleInverted: noop, inverted: false, filterString: null, setFilterString: noop, diffing: null, onToggleDiffing: noop, view: { state: viewState.CENSUS }, onViewChange: noop, labelDisplays: [labelDisplays.coarseType, labelDisplays.allocationStack], labelDisplay: labelDisplays.coarseType, onLabelDisplayChange: noop, snapshots: [], }); function makeTestCensusNode() { return { name: "Function", bytes: 100, totalBytes: 100, count: 100, totalCount: 100, children: [], }; } var TEST_TREE_MAP_PROPS = Object.freeze({ treeMap: Object.freeze({ report: { name: null, bytes: 0, totalBytes: 400, count: 0, totalCount: 400, children: [ { name: "objects", bytes: 0, totalBytes: 200, count: 0, totalCount: 200, children: [makeTestCensusNode(), makeTestCensusNode()], }, { name: "other", bytes: 0, totalBytes: 200, count: 0, totalCount: 200, children: [makeTestCensusNode(), makeTestCensusNode()], }, ], }, }), }); var TEST_SNAPSHOT_LIST_ITEM_PROPS = Object.freeze({ onClick: noop, onSave: noop, onDelete: noop, item: TEST_SNAPSHOT, index: 1234, }); function onNextAnimationFrame(fn) { return () => requestAnimationFrame(() => requestAnimationFrame(fn)); } /** * Render the provided ReactElement in the provided HTML container. * Returns a Promise that will resolve the rendered element as a React * component. */ function renderComponent(element, container) { return new Promise(resolve => { const component = ReactDOM.render( element, container, onNextAnimationFrame(() => { dumpn("Rendered = " + container.innerHTML); resolve(component); }) ); }); } function dumpn(msg) { dump(`MEMORY-TEST: ${msg}\n`); }