| function TestFlame() { |
| const PADDING = 2; // Matches PADDING in stackViewer |
| |
| const test = new TestFixture(); |
| const chart = document.getElementById("stack-chart"); |
| if (!chart) { |
| test.err("could not find stack-chart"); |
| return; |
| } |
| const chartRect = chart.getBoundingClientRect(); |
| |
| // Create map from box text to DOM element. |
| // TODO: Generalize to support multiple boxes for a given piece of text. |
| let boxMap; |
| fetchBoxes(); |
| function fetchBoxes() { |
| boxMap = new Map(); |
| const boxes = document.querySelectorAll(".boxbg"); |
| for (let box of boxes) { |
| const text = box.innerText; |
| boxMap.set(text, box); |
| } |
| } |
| |
| // rect gets the bounding box for box with text t. |
| function rect(t) { |
| const elem = boxMap.get(t); |
| if (!elem) { |
| test.err("did not find", t); |
| return null; |
| } |
| return elem.getBoundingClientRect(); |
| } |
| |
| // checkCalls checks that box with text a is positioned w.r.t. box with |
| // text b to indicate a call from a to b. Expect a gap of the specified |
| // number of rows. |
| function checkCalls(a, b, gap = 0) { |
| test.setContext("checkCalls", a, b, gap); |
| const ra = rect(a); |
| const rb = rect(b); |
| if (!ra || !rb) return; |
| |
| const pixelGap = gap * rb.height; |
| if (rb.top != ra.bottom + pixelGap) { |
| test.err("not above"); |
| } |
| // TODO: Allow checking boxes above pivots. |
| if (rb.left < ra.left || rb.right > ra.right) { |
| test.err("horizontal span of", a, "is not nested inside horizontal span of", b); |
| } |
| } |
| |
| // checkWidth checks that the width of the box with text t is approximately |
| // the specified fraction of the total width. |
| function checkWidth(t, fraction) { |
| test.setContext("checkWidth", t, fraction); |
| const r = rect(t); |
| if (!r) return; |
| const expect = (chartRect.width - 2*PADDING) * fraction; |
| if (r.width < expect*0.95 || r.width > expect*1.05) { |
| test.err("bad width", r.width, "expecting ~", expect); |
| } |
| } |
| |
| // Fake profile has the following stacks: |
| // 100 F1 F2 F3 |
| // 200 F1 F2 |
| test.run("initial", function() { |
| checkCalls("root", "F1"); |
| checkCalls("F1", "F2"); |
| checkCalls("F2", "F3"); |
| checkWidth("root", 300/300); |
| checkWidth("F1", 300/300); |
| checkWidth("F2", 300/300); |
| checkWidth("F3", 100/300); |
| }); |
| |
| test.run("Pivot F3", function() { |
| boxMap.get("F3").click(); |
| fetchBoxes(); |
| checkCalls("root", "F1"); |
| checkCalls("F1", "F2"); |
| checkCalls("F2", "F3", 1); |
| checkWidth("root", 100/100); |
| checkWidth("F1", 100/100); |
| checkWidth("F2", 100/100); |
| checkWidth("F3", 100/100); |
| }); |
| |
| test.run("NavigateWithoutPivot", function() { |
| // Clear pivot |
| boxMap.get("root").click(); |
| |
| // Trigger link update. |
| const btn = document.getElementById("graphbtn"); |
| if (!btn) { |
| test.err("no graph button on page"); |
| return; |
| } |
| const event = new Event("mouseenter"); |
| btn.dispatchEvent(event); |
| |
| // Check that URL does not contain a focus parameter. |
| test.log(btn.href); |
| const url = new URL(btn.href); |
| if (url.searchParams.has('f')) { |
| test.err("unexpected focus parameter in URL", btn.href); |
| } |
| }); |
| |
| test.run("Units", function() { |
| function checkUnitText(unit, v, expect) { |
| const result = pprofUnitText(v, unit); |
| if (result != expect) { |
| test.err("bad text for", v, unit, ":", result, "expecting:", expect); |
| } |
| } |
| |
| // Time units, plus logic tests. |
| checkUnitText("s", 0.51e-9, "0.51ns"); |
| checkUnitText("s", 3e-9, "3ns"); |
| checkUnitText("s", 1.23e-6, "1.23us"); |
| checkUnitText("s", 0.04, "40ms"); |
| checkUnitText("s", 1, "1s"); |
| checkUnitText("s", 3599, "3599s"); |
| checkUnitText("s", 3600, "1hrs"); |
| |
| // Sanity check for byte units. |
| checkUnitText("B", 2*1048576, "2MB"); |
| |
| // Unknown unit. |
| checkUnitText("cm", 100, "100cm"); |
| }); |
| |
| return test.result; |
| } |
| TestFlame(); |