Bug 1249453 - Add arrows from parent to children in census trees; r=jsantell
authorNick Fitzgerald <fitzgen@gmail.com>
Tue, 23 Feb 2016 14:14:37 -0800
changeset 321604 7e648af1885dfbb6959476efb5fad6504a5e1c86
parent 321603 385e0938172e2c9799de8ab42d0b052ae65495ee
child 321605 b3175dd140e73e6d4875a99d4299a15539571f01
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjsantell
bugs1249453
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1249453 - Add arrows from parent to children in census trees; r=jsantell MozReview-Commit-ID: LFo4jJot2Sr
devtools/client/memory/components/census-tree-item.js
devtools/client/memory/components/census.js
devtools/client/memory/test/browser/browser_memory_no_auto_expand.js
devtools/client/memory/test/browser/head.js
devtools/client/memory/test/chrome/chrome.ini
devtools/client/memory/test/chrome/head.js
devtools/client/memory/test/chrome/test_CensusTreeItem_01.html
devtools/client/themes/memory.css
--- a/devtools/client/memory/components/census-tree-item.js
+++ b/devtools/client/memory/components/census-tree-item.js
@@ -20,51 +20,59 @@ const CensusTreeItem = module.exports = 
   },
 
   render() {
     let {
       item,
       depth,
       arrow,
       focused,
-      toolbox,
       getPercentBytes,
       getPercentCount,
       showSign,
       onViewSourceInDebugger,
+      inverted,
     } = this.props;
 
     const bytes = formatNumber(item.bytes, showSign);
     const percentBytes = formatPercent(getPercentBytes(item.bytes), showSign);
 
     const count = formatNumber(item.count, showSign);
     const percentCount = formatPercent(getPercentCount(item.count), showSign);
 
     const totalBytes = formatNumber(item.totalBytes, showSign);
     const percentTotalBytes = formatPercent(getPercentBytes(item.totalBytes), showSign);
 
     const totalCount = formatNumber(item.totalCount, showSign);
     const percentTotalCount = formatPercent(getPercentCount(item.totalCount), showSign);
 
-    return dom.div({ className: `heap-tree-item ${focused ? "focused" :""}` },
+    let pointer;
+    if (inverted && depth > 0) {
+      pointer = dom.span({ className: "children-pointer" }, "↖");
+    } else if (!inverted && item.children && item.children.length) {
+      pointer = dom.span({ className: "children-pointer" }, "↘");
+    }
+
+    return dom.div({ className: `heap-tree-item ${focused ? "focused" : ""}` },
       dom.span({ className: "heap-tree-item-field heap-tree-item-bytes" },
                dom.span({ className: "heap-tree-number" }, bytes),
                dom.span({ className: "heap-tree-percent" }, percentBytes)),
       dom.span({ className: "heap-tree-item-field heap-tree-item-count" },
                dom.span({ className: "heap-tree-number" }, count),
                dom.span({ className: "heap-tree-percent" }, percentCount)),
       dom.span({ className: "heap-tree-item-field heap-tree-item-total-bytes" },
                dom.span({ className: "heap-tree-number" }, totalBytes),
                dom.span({ className: "heap-tree-percent" }, percentTotalBytes)),
       dom.span({ className: "heap-tree-item-field heap-tree-item-total-count" },
                dom.span({ className: "heap-tree-number" }, totalCount),
                dom.span({ className: "heap-tree-percent" }, percentTotalCount)),
                dom.span({ className: "heap-tree-item-field heap-tree-item-name",
                           style: { marginLeft: depth * TREE_ROW_HEIGHT }},
         arrow,
+        pointer,
         this.toLabel(item.name, onViewSourceInDebugger)
       )
     );
   },
 
   toLabel(name, linkToDebugger) {
     if (isSavedFrame(name)) {
       return Frame({
--- a/devtools/client/memory/components/census.js
+++ b/devtools/client/memory/components/census.js
@@ -61,15 +61,16 @@ const Census = module.exports = createCl
           item,
           depth,
           focused,
           arrow,
           expanded,
           getPercentBytes,
           getPercentCount,
           showSign: !!diffing,
+          inverted: census.inverted,
         }),
       getRoots: () => report.children || [],
       getKey: node => node.id,
       itemHeight: TREE_ROW_HEIGHT,
     });
   }
 });
--- a/devtools/client/memory/test/browser/browser_memory_no_auto_expand.js
+++ b/devtools/client/memory/test/browser/browser_memory_no_auto_expand.js
@@ -21,18 +21,27 @@ this.test = makeMemoryTest(TEST_URL, fun
 
   is(getState().allocations.recording, false);
   const recordingCheckbox = doc.getElementById("record-allocation-stacks-checkbox");
   EventUtils.synthesizeMouseAtCenter(recordingCheckbox, {}, panel.panelWin);
   is(getState().allocations.recording, true);
 
   const nameElems = [...doc.querySelectorAll(".heap-tree-item-field.heap-tree-item-name")];
   is(nameElems.length, 4, "Should get 4 items, one for each coarse type");
-  ok(nameElems.some(e => e.textContent.trim() === "objects"), "One for coarse type 'objects'");
-  ok(nameElems.some(e => e.textContent.trim() === "scripts"), "One for coarse type 'scripts'");
-  ok(nameElems.some(e => e.textContent.trim() === "strings"), "One for coarse type 'strings'");
-  ok(nameElems.some(e => e.textContent.trim() === "other"), "One for coarse type 'other'");
+
+  for (let el of nameElems) {
+    dumpn(`Found ${el.textContent.trim()}`);
+  }
+
+  ok(nameElems.some(e => e.textContent.indexOf("objects") >= 0),
+     "One for coarse type 'objects'");
+  ok(nameElems.some(e => e.textContent.indexOf("scripts") >= 0),
+     "One for coarse type 'scripts'");
+  ok(nameElems.some(e => e.textContent.indexOf("strings") >= 0),
+     "One for coarse type 'strings'");
+  ok(nameElems.some(e => e.textContent.indexOf("other") >= 0),
+     "One for coarse type 'other'");
 
   for (let e of nameElems) {
     is(e.style.marginLeft, "0px",
        "None of the elements should be an indented/expanded child");
   }
 });
--- a/devtools/client/memory/test/browser/head.js
+++ b/devtools/client/memory/test/browser/head.js
@@ -67,16 +67,20 @@ function makeMemoryTest(url, generator) 
 
     yield closeMemoryPanel(tab);
     yield removeTab(tab);
 
     finish();
   });
 }
 
+function dumpn(msg) {
+  dump(`MEMORY-TEST: ${msg}\n`);
+}
+
 /**
  * Returns a promise that will resolve when the provided store matches
  * the expected array. expectedStates is an array of dominatorTree states.
  * Expectations :
  * - store.getState().snapshots.length == expected.length
  * - snapshots[i].dominatorTree.state == expected[i]
  *
  * @param  {Store} store
--- a/devtools/client/memory/test/chrome/chrome.ini
+++ b/devtools/client/memory/test/chrome/chrome.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 support-files =
   head.js
 
+[test_CensusTreeItem_01.html]
 [test_DominatorTree_01.html]
 [test_DominatorTree_02.html]
 [test_DominatorTree_03.html]
 [test_DominatorTreeItem_01.html]
 [test_Heap_01.html]
 [test_Heap_02.html]
 [test_Heap_03.html]
 [test_Heap_04.html]
--- a/devtools/client/memory/test/chrome/head.js
+++ b/devtools/client/memory/test/chrome/head.js
@@ -30,25 +30,53 @@ const {
   getDominatorTreeBreakdownDisplayData,
 } = require("devtools/client/memory/utils");
 
 var models = require("devtools/client/memory/models");
 
 var React = require("devtools/client/shared/vendor/react");
 var ReactDOM = require("devtools/client/shared/vendor/react-dom");
 var Heap = React.createFactory(require("devtools/client/memory/components/heap"));
+var CensusTreeItem = React.createFactory(require("devtools/client/memory/components/census-tree-item"));
 var DominatorTreeComponent = React.createFactory(require("devtools/client/memory/components/dominator-tree"));
 var DominatorTreeItem = React.createFactory(require("devtools/client/memory/components/dominator-tree-item"));
 var Toolbar = React.createFactory(require("devtools/client/memory/components/toolbar"));
 
 // 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
new file mode 100644
--- /dev/null
+++ b/devtools/client/memory/test/chrome/test_CensusTreeItem_01.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that children pointers show up at the correct times.
+-->
+<head>
+    <meta charset="utf-8">
+    <title>Tree component test</title>
+    <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+    <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+    <!-- Give the container height so that the whole tree is rendered. -->
+    <div id="container" style="height: 900px;"></div>
+
+    <pre id="test">
+        <script src="head.js" type="application/javascript;version=1.8"></script>
+        <script type="application/javascript;version=1.8">
+         window.onload = Task.async(function* () {
+           try {
+             const container = document.getElementById("container");
+
+             yield renderComponent(CensusTreeItem(immutableUpdate(TEST_CENSUS_TREE_ITEM_PROPS, {
+               inverted: true,
+               depth: 0,
+             })), container);
+
+             ok(!container.querySelector(".children-pointer"),
+                "Don't show children pointer for roots when we are inverted");
+
+             yield renderComponent(CensusTreeItem(immutableUpdate(TEST_CENSUS_TREE_ITEM_PROPS, {
+               inverted: true,
+               depth: 1,
+             })), container);
+
+             ok(container.querySelector(".children-pointer"),
+                "Do show children pointer for non-roots when we are inverted");
+
+             yield renderComponent(CensusTreeItem(immutableUpdate(TEST_CENSUS_TREE_ITEM_PROPS, {
+               inverted: false,
+               item: immutableUpdate(TEST_CENSUS_TREE_ITEM_PROPS.item, { children: undefined }),
+             })), container);
+
+             ok(!container.querySelector(".children-pointer"),
+                "Don't show children pointer when non-inverted and no children");
+
+             yield renderComponent(CensusTreeItem(immutableUpdate(TEST_CENSUS_TREE_ITEM_PROPS, {
+               inverted: false,
+               depth: 0,
+               item: immutableUpdate(TEST_CENSUS_TREE_ITEM_PROPS.item, { children: [{}] }),
+             })), container);
+
+             ok(container.querySelector(".children-pointer"),
+                "Do show children pointer when non-inverted and have children");
+
+           } catch(e) {
+             ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+           } finally {
+             SimpleTest.finish();
+           }
+         });
+        </script>
+    </pre>
+</body>
+</html>
--- a/devtools/client/themes/memory.css
+++ b/devtools/client/themes/memory.css
@@ -324,16 +324,20 @@ html, body, #app, #memory-tool {
   background-color: var(--theme-body-background);
 }
 
 .tree-node {
   height: var(--heap-tree-row-height);
   line-height: var(--heap-tree-row-height);
 }
 
+.children-pointer {
+  padding-inline-end: 5px;
+}
+
 /**
  * Heap tree view columns
  */
 
 .heap-tree-item {
   /**
    * Flex: contains several span columns, all of which need to be laid out
    * horizontally. All columns except the last one have percentage widths, and