mirror of
https://github.com/roytam1/UXP.git
synced 2026-05-27 12:08:55 +00:00
8c395520d9
Since these are just interpreted comments, there's 0 impact on actual code. This removes all lines that match /* vim: set(.*)tw=80: */ with S&R -- there are a few others scattered around which will be removed manually in a second part.
253 lines
8.0 KiB
JavaScript
253 lines
8.0 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
/**
|
|
* Make sure that the variables view remains responsive when faced with
|
|
* huge ammounts of data.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const TAB_URL = EXAMPLE_URL + "doc_large-array-buffer.html";
|
|
const {ELLIPSIS} = require("devtools/shared/l10n");
|
|
|
|
|
|
var gTab, gPanel, gDebugger, gVariables;
|
|
|
|
function test() {
|
|
// this test does a lot of work on large objects, default 45s is not enough
|
|
requestLongerTimeout(4);
|
|
|
|
let options = {
|
|
source: TAB_URL,
|
|
line: 1
|
|
};
|
|
initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
|
|
gTab = aTab;
|
|
gPanel = aPanel;
|
|
gDebugger = gPanel.panelWin;
|
|
gVariables = gDebugger.DebuggerView.Variables;
|
|
|
|
waitForCaretAndScopes(gPanel, 28, 1)
|
|
.then(() => performTests())
|
|
.then(() => resumeDebuggerThenCloseAndFinish(gPanel))
|
|
.then(null, error => {
|
|
ok(false, "Got an error: " + error.message + "\n" + error.stack);
|
|
});
|
|
|
|
generateMouseClickInTab(gTab, "content.document.querySelector('button')");
|
|
});
|
|
}
|
|
|
|
const VARS_TO_TEST = [
|
|
{
|
|
varName: "buffer",
|
|
stringified: "ArrayBuffer",
|
|
doNotExpand: true
|
|
},
|
|
{
|
|
varName: "largeArray",
|
|
stringified: "Int8Array[10000]",
|
|
extraProps: [
|
|
[ "buffer", "ArrayBuffer" ],
|
|
[ "byteLength", "10000" ],
|
|
[ "byteOffset", "0" ],
|
|
[ "length", "10000" ],
|
|
[ "__proto__", "Int8ArrayPrototype" ]
|
|
]
|
|
},
|
|
{
|
|
varName: "largeObject",
|
|
stringified: "Object[10000]",
|
|
extraProps: [
|
|
[ "__proto__", "Object" ]
|
|
]
|
|
},
|
|
{
|
|
varName: "largeMap",
|
|
stringified: "Map[10000]",
|
|
hasEntries: true,
|
|
extraProps: [
|
|
[ "size", "10000" ],
|
|
[ "__proto__", "Object" ]
|
|
]
|
|
},
|
|
{
|
|
varName: "largeSet",
|
|
stringified: "Set[10000]",
|
|
hasEntries: true,
|
|
extraProps: [
|
|
[ "size", "10000" ],
|
|
[ "__proto__", "Object" ]
|
|
]
|
|
}
|
|
];
|
|
|
|
const PAGE_RANGES = [
|
|
[0, 2499], [2500, 4999], [5000, 7499], [7500, 9999]
|
|
];
|
|
|
|
function toPageNames(ranges) {
|
|
return ranges.map(([ from, to ]) => "[" + from + ELLIPSIS + to + "]");
|
|
}
|
|
|
|
function performTests() {
|
|
let localScope = gVariables.getScopeAtIndex(0);
|
|
|
|
return promise.all(VARS_TO_TEST.map(spec => {
|
|
let { varName, stringified, doNotExpand } = spec;
|
|
|
|
let variable = localScope.get(varName);
|
|
ok(variable,
|
|
`There should be a '${varName}' variable present in the scope.`);
|
|
|
|
is(variable.target.querySelector(".name").getAttribute("value"), varName,
|
|
`Should have the right property name for '${varName}'.`);
|
|
is(variable.target.querySelector(".value").getAttribute("value"), stringified,
|
|
`Should have the right property value for '${varName}'.`);
|
|
ok(variable.target.querySelector(".value").className.includes("token-other"),
|
|
`Should have the right token class for '${varName}'.`);
|
|
|
|
is(variable.expanded, false,
|
|
`The '${varName}' variable shouldn't be expanded.`);
|
|
|
|
if (doNotExpand) {
|
|
return promise.resolve();
|
|
}
|
|
|
|
return variable.expand()
|
|
.then(() => verifyFirstLevel(variable, spec));
|
|
}));
|
|
}
|
|
|
|
// In objects and arrays, the sliced pages are at the top-level of
|
|
// the expanded object, but with Maps and Sets, we have to expand
|
|
// <entries> first and look there.
|
|
function getExpandedPages(variable, hasEntries) {
|
|
let expandedPages = promise.defer();
|
|
if (hasEntries) {
|
|
let entries = variable.get("<entries>");
|
|
ok(entries, "<entries> retrieved");
|
|
entries.expand().then(() => expandedPages.resolve(entries));
|
|
} else {
|
|
expandedPages.resolve(variable);
|
|
}
|
|
|
|
return expandedPages.promise;
|
|
}
|
|
|
|
function verifyFirstLevel(variable, spec) {
|
|
let { varName, hasEntries, extraProps } = spec;
|
|
|
|
let enums = variable._enum.childNodes;
|
|
let nonEnums = variable._nonenum.childNodes;
|
|
|
|
is(enums.length, hasEntries ? 1 : 4,
|
|
`The '${varName}' contains the right number of enumerable elements.`);
|
|
is(nonEnums.length, extraProps.length,
|
|
`The '${varName}' contains the right number of non-enumerable elements.`);
|
|
|
|
// the sliced pages begin after <entries> row
|
|
let pagesOffset = hasEntries ? 1 : 0;
|
|
let expandedPages = getExpandedPages(variable, hasEntries);
|
|
|
|
return expandedPages.then((pagesList) => {
|
|
toPageNames(PAGE_RANGES).forEach((pageName, i) => {
|
|
let index = i + pagesOffset;
|
|
|
|
is(pagesList.target.querySelectorAll(".variables-view-property .name")[index].getAttribute("value"),
|
|
pageName, `The page #${i + 1} in the '${varName}' is named correctly.`);
|
|
is(pagesList.target.querySelectorAll(".variables-view-property .value")[index].getAttribute("value"),
|
|
"", `The page #${i + 1} in the '${varName}' should not have a corresponding value.`);
|
|
});
|
|
}).then(() => {
|
|
extraProps.forEach(([ propName, propValue ], i) => {
|
|
// the extra props start after the 4 pages
|
|
let index = i + pagesOffset + 4;
|
|
|
|
is(variable.target.querySelectorAll(".variables-view-property .name")[index].getAttribute("value"),
|
|
propName, `The other properties in '${varName}' are named correctly.`);
|
|
is(variable.target.querySelectorAll(".variables-view-property .value")[index].getAttribute("value"),
|
|
propValue, `The other properties in '${varName}' have the correct value.`);
|
|
});
|
|
}).then(() => verifyNextLevels(variable, spec));
|
|
}
|
|
|
|
function verifyNextLevels(variable, spec) {
|
|
let { varName, hasEntries } = spec;
|
|
|
|
// the entries are already expanded in verifyFirstLevel
|
|
let pagesList = hasEntries ? variable.get("<entries>") : variable;
|
|
|
|
let lastPage = pagesList.get(toPageNames(PAGE_RANGES)[3]);
|
|
ok(lastPage, `The last page in the 1st level of '${varName}' was retrieved successfully.`);
|
|
|
|
return lastPage.expand()
|
|
.then(() => verifyNextLevels2(lastPage, varName));
|
|
}
|
|
|
|
function verifyNextLevels2(lastPage1, varName) {
|
|
const PAGE_RANGES_IN_LAST_PAGE = [
|
|
[7500, 8124], [8125, 8749], [8750, 9374], [9375, 9999]
|
|
];
|
|
|
|
let pageEnums1 = lastPage1._enum.childNodes;
|
|
let pageNonEnums1 = lastPage1._nonenum.childNodes;
|
|
is(pageEnums1.length, 4,
|
|
`The last page in the 1st level of '${varName}' should contain all the created enumerable elements.`);
|
|
is(pageNonEnums1.length, 0,
|
|
`The last page in the 1st level of '${varName}' should not contain any non-enumerable elements.`);
|
|
|
|
let pageNames = toPageNames(PAGE_RANGES_IN_LAST_PAGE);
|
|
pageNames.forEach((pageName, i) => {
|
|
is(lastPage1._enum.querySelectorAll(".variables-view-property .name")[i].getAttribute("value"),
|
|
pageName, `The page #${i + 1} in the 2nd level of '${varName}' is named correctly.`);
|
|
});
|
|
|
|
let lastPage2 = lastPage1.get(pageNames[3]);
|
|
ok(lastPage2, "The last page in the 2nd level was retrieved successfully.");
|
|
|
|
return lastPage2.expand()
|
|
.then(() => verifyNextLevels3(lastPage2, varName));
|
|
}
|
|
|
|
function verifyNextLevels3(lastPage2, varName) {
|
|
let pageEnums2 = lastPage2._enum.childNodes;
|
|
let pageNonEnums2 = lastPage2._nonenum.childNodes;
|
|
is(pageEnums2.length, 625,
|
|
`The last page in the 3rd level of '${varName}' should contain all the created enumerable elements.`);
|
|
is(pageNonEnums2.length, 0,
|
|
`The last page in the 3rd level of '${varName}' shouldn't contain any non-enumerable elements.`);
|
|
|
|
const LEAF_ITEMS = [
|
|
[0, 9375, 624],
|
|
[1, 9376, 623],
|
|
[623, 9998, 1],
|
|
[624, 9999, 0]
|
|
];
|
|
|
|
function expectedValue(name, value) {
|
|
switch (varName) {
|
|
case "largeArray": return 0;
|
|
case "largeObject": return value;
|
|
case "largeMap": return name + " \u2192 " + value;
|
|
case "largeSet": return value;
|
|
}
|
|
}
|
|
|
|
LEAF_ITEMS.forEach(([index, name, value]) => {
|
|
is(lastPage2._enum.querySelectorAll(".variables-view-property .name")[index].getAttribute("value"),
|
|
name, `The properties in the leaf level of '${varName}' are named correctly.`);
|
|
is(lastPage2._enum.querySelectorAll(".variables-view-property .value")[index].getAttribute("value"),
|
|
expectedValue(name, value), `The properties in the leaf level of '${varName}' have the correct value.`);
|
|
});
|
|
}
|
|
|
|
registerCleanupFunction(function () {
|
|
gTab = null;
|
|
gPanel = null;
|
|
gDebugger = null;
|
|
gVariables = null;
|
|
});
|