mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-01 04:47:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
488
dom/xul/templates/tests/chrome/templates_shared.js
Normal file
488
dom/xul/templates/tests/chrome/templates_shared.js
Normal file
|
|
@ -0,0 +1,488 @@
|
|||
/**
|
||||
* This script is used for testing XUL templates. Call test_template within
|
||||
* a load event handler.
|
||||
*
|
||||
* A test should have a root node with the datasources attribute with the
|
||||
* id 'root', and a few global variables defined in the test's XUL file:
|
||||
*
|
||||
* testid: the testid, used when outputting test results
|
||||
* expectedOutput: e4x data containing the expected output. It can optionally
|
||||
* be enclosed in an <output> element as most tests generate
|
||||
* more than one node of output.
|
||||
* isTreeBuilder: true for dont-build-content trees, false otherwise
|
||||
* queryType: 'rdf', 'xml', etc.
|
||||
* needsOpen: true for menu tests where the root menu must be opened before
|
||||
* comparing results
|
||||
* notWorkingYet: true if this test isn't working yet, outputs todo results
|
||||
* notWorkingYetDynamic: true if the dynamic changes portion of the test
|
||||
* isn't working yet, outputs todo results
|
||||
* changes: an array of functions to perform in sequence to test dynamic changes
|
||||
* to the datasource.
|
||||
*
|
||||
* If the <output> element has an unordered attribute set to true, the
|
||||
* children within it must all appear to match, but may appear in any order.
|
||||
* If the unordered attribute is not set, the children must appear in the same
|
||||
* order.
|
||||
*
|
||||
* If the 'changes' array is used, it should be an array of functions. Each
|
||||
* function will be called in order and a comparison of the output will be
|
||||
* performed. This allows changes to be made to the datasource to ensure that
|
||||
* the generated template output has been updated. Within the expected output
|
||||
* XML, the step attribute may be set to a number on an element to indicate
|
||||
* that an element only applies before or after a particular change. If step
|
||||
* is set to a positive number, that element will only exist after that step in
|
||||
* the list of changes made. If step is set to a negative number, that element
|
||||
* will only exist until that step. Steps are numbered starting at 1. For
|
||||
* example:
|
||||
* <label value="Cat"/>
|
||||
* <label step="2" value="Dog"/>
|
||||
* <label step="-5" value="Mouse"/>
|
||||
* The first element will always exist. The second element will only appear
|
||||
* after the second change is made. The third element will only appear until
|
||||
* the fifth change and it will no longer be present at later steps.
|
||||
*
|
||||
* If the anyid attribute is set to true on an element in the expected output,
|
||||
* then the value of the id attribute on that element is not compared for a
|
||||
* match. This is used, for example, for xml datasources, where the ids set on
|
||||
* the generated output are pseudo-random.
|
||||
*/
|
||||
|
||||
const ZOO_NS = "http://www.some-fictitious-zoo.com/";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
const debug = false;
|
||||
|
||||
var expectedConsoleMessages = [];
|
||||
var expectLoggedMessages = null;
|
||||
|
||||
function get_RDF() {
|
||||
try {
|
||||
return Components.classes["@mozilla.org/rdf/rdf-service;1"].
|
||||
getService(Components.interfaces.nsIRDFService);
|
||||
} catch (ex) { }
|
||||
}
|
||||
|
||||
function get_ContainerUtils()
|
||||
{
|
||||
try {
|
||||
return Components.classes["@mozilla.org/rdf/container-utils;1"].
|
||||
getService(Components.interfaces.nsIRDFContainerUtils);
|
||||
} catch(ex) { }
|
||||
}
|
||||
|
||||
const RDF = get_RDF();
|
||||
const ContainerUtils = get_ContainerUtils();
|
||||
|
||||
var xmlDoc;
|
||||
|
||||
function test_template()
|
||||
{
|
||||
var root = document.getElementById("root");
|
||||
|
||||
var ds;
|
||||
if (queryType == "rdf" && RDF) {
|
||||
var ioService = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
|
||||
var src = window.location.href.replace(/test_tmpl.*xul/, "animals.rdf");
|
||||
ds = RDF.GetDataSourceBlocking(src);
|
||||
|
||||
if (expectLoggedMessages) {
|
||||
Components.classes["@mozilla.org/consoleservice;1"].
|
||||
getService(Components.interfaces.nsIConsoleService).reset();
|
||||
}
|
||||
|
||||
if (root.getAttribute("datasources") == "rdf:null")
|
||||
root.setAttribute("datasources", "animals.rdf");
|
||||
}
|
||||
else if (queryType == "xml") {
|
||||
var src = window.location.href.replace(/test_tmpl.*xul/, "animals.xml");
|
||||
xmlDoc = new XMLHttpRequest();
|
||||
xmlDoc.open("get", src, false);
|
||||
xmlDoc.send(null);
|
||||
}
|
||||
|
||||
// open menus if necessary
|
||||
if (needsOpen)
|
||||
root.open = true;
|
||||
|
||||
if (expectLoggedMessages)
|
||||
expectLoggedMessages();
|
||||
|
||||
checkResults(root, 0);
|
||||
|
||||
if (changes.length) {
|
||||
var usedds = ds;
|
||||
// within these chrome tests, RDF datasources won't be modifiable unless
|
||||
// an in-memory datasource is used instead. Call copyRDFDataSource to
|
||||
// copy the datasource.
|
||||
if (queryType == "rdf")
|
||||
usedds = copyRDFDataSource(root, ds);
|
||||
if (needsOpen)
|
||||
root.open = true;
|
||||
setTimeout(iterateChanged, 0, root, usedds);
|
||||
}
|
||||
else {
|
||||
if (needsOpen)
|
||||
root.open = false;
|
||||
if (expectedConsoleMessages.length)
|
||||
compareConsoleMessages();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
function iterateChanged(root, ds)
|
||||
{
|
||||
Components.classes["@mozilla.org/consoleservice;1"].
|
||||
getService(Components.interfaces.nsIConsoleService).reset();
|
||||
|
||||
for (var c = 0; c < changes.length; c++) {
|
||||
changes[c](ds, root);
|
||||
checkResults(root, c + 1);
|
||||
}
|
||||
|
||||
if (needsOpen)
|
||||
root.open = false;
|
||||
if (expectedConsoleMessages.length)
|
||||
compareConsoleMessages();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function checkResults(root, step)
|
||||
{
|
||||
var output = expectedOutput.cloneNode(true);
|
||||
setForCurrentStep(output, step);
|
||||
|
||||
var error;
|
||||
var actualoutput = root;
|
||||
if (isTreeBuilder) {
|
||||
// convert the tree's view data into the equivalent DOM structure
|
||||
// for easier comparison
|
||||
actualoutput = treeViewToDOM(root);
|
||||
var treechildrenElements = [...output.children].filter((e) => e.localName === "treechildren");
|
||||
error = compareOutput(actualoutput, treechildrenElements[0], false);
|
||||
}
|
||||
else {
|
||||
error = compareOutput(actualoutput, output, true);
|
||||
}
|
||||
|
||||
var adjtestid = testid;
|
||||
if (step > 0)
|
||||
adjtestid += " dynamic step " + step;
|
||||
|
||||
var stilltodo = ((step == 0 && notWorkingYet) || (step > 0 && notWorkingYetDynamic));
|
||||
if (stilltodo)
|
||||
todo(false, adjtestid);
|
||||
else
|
||||
ok(!error, adjtestid);
|
||||
|
||||
if ((!stilltodo && error) || debug) {
|
||||
// for debugging, serialize the XML output
|
||||
var serializedXML = "";
|
||||
var rootNodes = actualoutput.childNodes;
|
||||
for (var n = 0; n < rootNodes.length; n++) {
|
||||
var node = rootNodes[n];
|
||||
if (node.localName != "template")
|
||||
serializedXML += ((new XMLSerializer()).serializeToString(node));
|
||||
}
|
||||
|
||||
// remove the XUL namespace declarations to make the output more readable
|
||||
const nsrepl = new RegExp("xmlns=\"" + XUL_NS + "\" ", "g");
|
||||
serializedXML = serializedXML.replace(nsrepl, "");
|
||||
if (debug)
|
||||
dump("-------- " + adjtestid + " " + error + ":\n" + serializedXML + "\n");
|
||||
if (!stilltodo && error)
|
||||
is(serializedXML, "Same", "Error is: " + error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the expected output to acccount for any step attributes.
|
||||
*/
|
||||
function setForCurrentStep(content, currentStep)
|
||||
{
|
||||
var todelete = [];
|
||||
for (var child of content.childNodes) {
|
||||
if (child.nodeType === Node.ELEMENT_NODE) {
|
||||
var stepstr = child.getAttribute("step") || "";
|
||||
var stepsarr = stepstr.split(",");
|
||||
for (var s = 0; s < stepsarr.length; s++) {
|
||||
var step = parseInt(stepsarr[s]);
|
||||
if ((step > 0 && step > currentStep) ||
|
||||
(step < 0 && -step <= currentStep)) {
|
||||
todelete.push(child);
|
||||
}
|
||||
}
|
||||
} else if (child.nodeType === Node.TEXT_NODE) {
|
||||
// Drop empty text nodes.
|
||||
if (child.nodeValue.trim() === "")
|
||||
todelete.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
for (var e of todelete)
|
||||
content.removeChild(e);
|
||||
|
||||
for (var child of content.children) {
|
||||
child.removeAttribute("step");
|
||||
setForCurrentStep(child, currentStep);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the 'actual' DOM output with the 'expected' output. This function
|
||||
* is called recursively, with isroot true if actual refers to the root of the
|
||||
* template. Returns a null string if they are equal and an error string if
|
||||
* they are not equal. This function is called recursively as it iterates
|
||||
* through each node in the DOM tree.
|
||||
*/
|
||||
function compareOutput(actual, expected, isroot)
|
||||
{
|
||||
if (isroot && expected.localName != "data")
|
||||
return "expected must be a <data> element";
|
||||
|
||||
var t;
|
||||
|
||||
// compare text nodes
|
||||
if (expected.nodeType == Node.TEXT_NODE) {
|
||||
if (actual.nodeValue !== expected.nodeValue.trim())
|
||||
return "Text " + actual.nodeValue + " doesn't match " + expected.nodeValue;
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!isroot) {
|
||||
var anyid = false;
|
||||
// make sure that the tags match
|
||||
if (actual.localName != expected.localName)
|
||||
return "Tag name " + expected.localName + " not found";
|
||||
|
||||
// loop through the attributes in the expected node and compare their
|
||||
// values with the corresponding attribute on the actual node
|
||||
|
||||
var expectedAttrs = expected.attributes;
|
||||
for (var a = 0; a < expectedAttrs.length; a++) {
|
||||
var attr = expectedAttrs[a];
|
||||
var expectval = attr.value;
|
||||
// skip checking the id when anyid="true", however make sure to
|
||||
// ensure that the id is actually present.
|
||||
if (attr.name == "anyid" && expectval == "true") {
|
||||
anyid = true;
|
||||
if (!actual.hasAttribute("id"))
|
||||
return "expected id attribute";
|
||||
}
|
||||
else if (actual.getAttribute(attr.name) != expectval) {
|
||||
return "attribute " + attr.name + " is '" +
|
||||
actual.getAttribute(attr.name) + "' instead of '" + expectval + "'";
|
||||
}
|
||||
}
|
||||
|
||||
// now loop through the actual attributes and make sure that there aren't
|
||||
// any extra attributes that weren't expected
|
||||
var length = actual.attributes.length;
|
||||
for (t = 0; t < length; t++) {
|
||||
var aattr = actual.attributes[t];
|
||||
var expectval = expected.getAttribute(aattr.name);
|
||||
// ignore some attributes that don't matter
|
||||
if (expectval != actual.getAttribute(aattr.name) &&
|
||||
aattr.name != "staticHint" && aattr.name != "xmlns" &&
|
||||
(aattr.name != "id" || !anyid))
|
||||
return "extra attribute " + aattr.name;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that the node has the right number of children. Subtract one for
|
||||
// the root node to account for the <template> node.
|
||||
length = actual.childNodes.length - (isroot ? 1 : 0);
|
||||
if (length != expected.childNodes.length)
|
||||
return "incorrect child node count of " + actual.localName + " " + length +
|
||||
" expected " + expected.childNodes.length;
|
||||
|
||||
// if <data unordered="true"> is used, then the child nodes may be in any order
|
||||
var unordered = (expected.localName == "data" && expected.getAttribute("unordered") == "true");
|
||||
|
||||
// next, loop over the children and call compareOutput recursively on each one
|
||||
var adj = 0;
|
||||
for (t = 0; t < actual.childNodes.length; t++) {
|
||||
var actualnode = actual.childNodes[t];
|
||||
// skip the <template> element, and add one to the indices when looking
|
||||
// at the later nodes to account for it
|
||||
if (isroot && actualnode.localName == "template") {
|
||||
adj++;
|
||||
}
|
||||
else {
|
||||
var output = "unexpected";
|
||||
if (unordered) {
|
||||
var expectedChildren = expected.childNodes;
|
||||
for (var e = 0; e < expectedChildren.length; e++) {
|
||||
output = compareOutput(actualnode, expectedChildren[e], false);
|
||||
if (!output)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
output = compareOutput(actualnode, expected.childNodes[t - adj], false);
|
||||
}
|
||||
|
||||
// an error was returned, so return early
|
||||
if (output)
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
* copy the datasource into an in-memory datasource so that it can be modified
|
||||
*/
|
||||
function copyRDFDataSource(root, sourceds)
|
||||
{
|
||||
var dsourcesArr = [];
|
||||
var composite = root.database;
|
||||
var dsources = composite.GetDataSources();
|
||||
while (dsources.hasMoreElements()) {
|
||||
sourceds = dsources.getNext().QueryInterface(Components.interfaces.nsIRDFDataSource);
|
||||
dsourcesArr.push(sourceds);
|
||||
}
|
||||
|
||||
for (var d = 0; d < dsourcesArr.length; d++)
|
||||
composite.RemoveDataSource(dsourcesArr[d]);
|
||||
|
||||
var newds = Components.classes["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"].
|
||||
createInstance(Components.interfaces.nsIRDFDataSource);
|
||||
|
||||
var sourcelist = sourceds.GetAllResources();
|
||||
while (sourcelist.hasMoreElements()) {
|
||||
var source = sourcelist.getNext();
|
||||
var props = sourceds.ArcLabelsOut(source);
|
||||
while (props.hasMoreElements()) {
|
||||
var prop = props.getNext();
|
||||
if (prop instanceof Components.interfaces.nsIRDFResource) {
|
||||
var targets = sourceds.GetTargets(source, prop, true);
|
||||
while (targets.hasMoreElements())
|
||||
newds.Assert(source, prop, targets.getNext(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
composite.AddDataSource(newds);
|
||||
root.builder.rebuild();
|
||||
|
||||
return newds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a tree view (nsITreeView) into the equivalent DOM tree.
|
||||
* Returns the treechildren
|
||||
*/
|
||||
function treeViewToDOM(tree)
|
||||
{
|
||||
var treechildren = document.createElement("treechildren");
|
||||
|
||||
if (tree.view)
|
||||
treeViewToDOMInner(tree.columns, treechildren, tree.view, tree.builder, 0, 0);
|
||||
|
||||
return treechildren;
|
||||
}
|
||||
|
||||
function treeViewToDOMInner(columns, treechildren, view, builder, start, level)
|
||||
{
|
||||
var end = view.rowCount;
|
||||
|
||||
for (var i = start; i < end; i++) {
|
||||
if (view.getLevel(i) < level)
|
||||
return i - 1;
|
||||
|
||||
var id = builder ? builder.getResourceAtIndex(i).Value : "id" + i;
|
||||
var item = document.createElement("treeitem");
|
||||
item.setAttribute("id", id);
|
||||
treechildren.appendChild(item);
|
||||
|
||||
var row = document.createElement("treerow");
|
||||
item.appendChild(row);
|
||||
|
||||
for (var c = 0; c < columns.length; c++) {
|
||||
var cell = document.createElement("treecell");
|
||||
var label = view.getCellText(i, columns[c]);
|
||||
if (label)
|
||||
cell.setAttribute("label", label);
|
||||
row.appendChild(cell);
|
||||
}
|
||||
|
||||
if (view.isContainer(i)) {
|
||||
item.setAttribute("container", "true");
|
||||
item.setAttribute("empty", view.isContainerEmpty(i) ? "true" : "false");
|
||||
|
||||
if (!view.isContainerEmpty(i) && view.isContainerOpen(i)) {
|
||||
item.setAttribute("open", "true");
|
||||
|
||||
var innertreechildren = document.createElement("treechildren");
|
||||
item.appendChild(innertreechildren);
|
||||
|
||||
i = treeViewToDOMInner(columns, innertreechildren, view, builder, i + 1, level + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
function expectConsoleMessage(ref, id, isNew, isActive, extra)
|
||||
{
|
||||
var message = "In template with id root" +
|
||||
(ref ? " using ref " + ref : "") + "\n " +
|
||||
(isNew ? "New " : "Removed ") + (isActive ? "active" : "inactive") +
|
||||
" result for query " + extra + ": " + id;
|
||||
expectedConsoleMessages.push(message);
|
||||
}
|
||||
|
||||
function compareConsoleMessages()
|
||||
{
|
||||
var consoleService = Components.classes["@mozilla.org/consoleservice;1"].
|
||||
getService(Components.interfaces.nsIConsoleService);
|
||||
var messages = consoleService.getMessageArray() || [];
|
||||
messages = messages.map(m => m.message);
|
||||
// Copy to avoid modifying expectedConsoleMessages
|
||||
var expect = expectedConsoleMessages.concat();
|
||||
for (var m = 0; m < messages.length; m++) {
|
||||
if (messages[m] == expect[0]) {
|
||||
ok(true, "found message " + expect.shift());
|
||||
}
|
||||
}
|
||||
if (expect.length != 0) {
|
||||
ok(false, "failed to find expected console messages: " + expect);
|
||||
}
|
||||
}
|
||||
|
||||
function copyToProfile(filename)
|
||||
{
|
||||
if (Cc === undefined) {
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
}
|
||||
|
||||
var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
.getService(Ci.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("chrome://mochikit/content/chrome-harness.js");
|
||||
|
||||
var file = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIProperties)
|
||||
.get("ProfD", Ci.nsIFile);
|
||||
file.append(filename);
|
||||
|
||||
var parentURI = getResolvedURI(getRootDirectory(window.location.href));
|
||||
if (parentURI.JARFile) {
|
||||
parentURI = extractJarToTmp(parentURI);
|
||||
} else {
|
||||
var fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
|
||||
getService(Ci.nsIFileProtocolHandler);
|
||||
parentURI = fileHandler.getFileFromURLSpec(parentURI.spec);
|
||||
}
|
||||
|
||||
parentURI = parentURI.QueryInterface(Ci.nsILocalFile);
|
||||
parentURI.append(filename);
|
||||
try {
|
||||
var retVal = parentURI.copyToFollowingLinks(file.parent, filename);
|
||||
} catch (ex) {
|
||||
//ignore this error as the file could exist already
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue