425 lines
10 KiB
JavaScript
425 lines
10 KiB
JavaScript
/* import-globals-from ../attributes.js */
|
|
/* import-globals-from ../common.js */
|
|
/* import-globals-from ../events.js */
|
|
/* import-globals-from ../name.js */
|
|
|
|
// //////////////////////////////////////////////////////////////////////////////
|
|
// Name tests described by "markuprules.xml" file.
|
|
|
|
var gNameRulesFileURL = "markuprules.xml";
|
|
|
|
var gRuleDoc = null;
|
|
|
|
// Debuggin stuff.
|
|
var gDumpToConsole = false;
|
|
|
|
/**
|
|
* Start name tests. Run through markup elements and test names for test
|
|
* element (see namerules.xml for details).
|
|
*/
|
|
function testNames() {
|
|
// enableLogging("tree,stack"); // debugging
|
|
|
|
var request = new XMLHttpRequest();
|
|
request.open("get", gNameRulesFileURL, false);
|
|
request.send();
|
|
|
|
gRuleDoc = request.responseXML;
|
|
|
|
var markupElms = evaluateXPath(gRuleDoc, "//rules/rulesample/markup");
|
|
gTestIterator.iterateMarkups(markupElms);
|
|
}
|
|
|
|
// //////////////////////////////////////////////////////////////////////////////
|
|
// Private section.
|
|
|
|
/**
|
|
* Helper class to interate through name tests.
|
|
*/
|
|
var gTestIterator = {
|
|
iterateMarkups: function gTestIterator_iterateMarkups(aMarkupElms) {
|
|
this.markupElms = aMarkupElms;
|
|
|
|
this.iterateNext();
|
|
},
|
|
|
|
iterateRules: function gTestIterator_iterateRules(
|
|
aElm,
|
|
aContainer,
|
|
aRuleSetElm,
|
|
aRuleElms,
|
|
aTestID
|
|
) {
|
|
this.ruleSetElm = aRuleSetElm;
|
|
this.ruleElms = aRuleElms;
|
|
this.elm = aElm;
|
|
this.container = aContainer;
|
|
this.testID = aTestID;
|
|
|
|
this.iterateNext();
|
|
},
|
|
|
|
iterateNext: function gTestIterator_iterateNext() {
|
|
if (this.markupIdx == -1) {
|
|
this.markupIdx++;
|
|
testNamesForMarkup(this.markupElms[this.markupIdx]);
|
|
return;
|
|
}
|
|
|
|
this.ruleIdx++;
|
|
if (this.ruleIdx == this.ruleElms.length) {
|
|
// When test is finished then name is empty and no explict-name.
|
|
var defaultName = this.ruleSetElm.hasAttribute("defaultName")
|
|
? this.ruleSetElm.getAttribute("defaultName")
|
|
: null;
|
|
testName(
|
|
this.elm,
|
|
defaultName,
|
|
"Default name test (" + gTestIterator.testID + "). "
|
|
);
|
|
testAbsentAttrs(this.elm, { "explicit-name": "true" });
|
|
|
|
this.markupIdx++;
|
|
if (this.markupIdx == this.markupElms.length) {
|
|
// disableLogging("tree"); // debugging
|
|
SimpleTest.finish();
|
|
return;
|
|
}
|
|
|
|
this.ruleIdx = -1;
|
|
|
|
if (gDumpToConsole) {
|
|
dump(
|
|
"\nPend next markup processing. Wait for reorder event on " +
|
|
prettyName(document) +
|
|
"'\n"
|
|
);
|
|
}
|
|
waitForEvent(
|
|
EVENT_REORDER,
|
|
document,
|
|
testNamesForMarkup,
|
|
null,
|
|
this.markupElms[this.markupIdx]
|
|
);
|
|
|
|
document.body.removeChild(this.container);
|
|
return;
|
|
}
|
|
|
|
testNameForRule(this.elm, this.ruleElms[this.ruleIdx]);
|
|
},
|
|
|
|
markupElms: null,
|
|
markupIdx: -1,
|
|
rulesetElm: null,
|
|
ruleElms: null,
|
|
ruleIdx: -1,
|
|
elm: null,
|
|
container: null,
|
|
testID: "",
|
|
};
|
|
|
|
/**
|
|
* Process every 'markup' element and test names for it. Used by testNames
|
|
* function.
|
|
*/
|
|
function testNamesForMarkup(aMarkupElm) {
|
|
if (gDumpToConsole) {
|
|
dump("\nProcessing markup '" + aMarkupElm.getAttribute("id") + "'\n");
|
|
}
|
|
|
|
var div = document.createElement("div");
|
|
div.setAttribute("id", "test");
|
|
|
|
var child = aMarkupElm.firstChild;
|
|
while (child) {
|
|
var newChild = document.importNode(child, true);
|
|
div.appendChild(newChild);
|
|
child = child.nextSibling;
|
|
}
|
|
|
|
if (gDumpToConsole) {
|
|
dump(
|
|
"\nProcessing markup. Wait for reorder event on " +
|
|
prettyName(document) +
|
|
"'\n"
|
|
);
|
|
}
|
|
waitForEvent(
|
|
EVENT_REORDER,
|
|
document,
|
|
testNamesForMarkupRules,
|
|
null,
|
|
aMarkupElm,
|
|
div
|
|
);
|
|
|
|
document.body.appendChild(div);
|
|
}
|
|
|
|
function testNamesForMarkupRules(aMarkupElm, aContainer) {
|
|
var testID = aMarkupElm.getAttribute("id");
|
|
if (gDumpToConsole) {
|
|
dump("\nProcessing markup rules '" + testID + "'\n");
|
|
}
|
|
|
|
var expr = "//html/body/div[@id='test']/" + aMarkupElm.getAttribute("ref");
|
|
var elm = evaluateXPath(document, expr, htmlDocResolver)[0];
|
|
|
|
var ruleId = aMarkupElm.getAttribute("ruleset");
|
|
var ruleElm = gRuleDoc.querySelector("[id='" + ruleId + "']");
|
|
var ruleElms = getRuleElmsByRulesetId(ruleId);
|
|
|
|
var processMarkupRules = gTestIterator.iterateRules.bind(
|
|
gTestIterator,
|
|
elm,
|
|
aContainer,
|
|
ruleElm,
|
|
ruleElms,
|
|
testID
|
|
);
|
|
|
|
// Images may be recreated after we append them into subtree. We need to wait
|
|
// in this case. If we are on profiling enabled build then stack tracing
|
|
// works and thus let's log instead. Note, that works if you enabled logging
|
|
// (refer to testNames() function).
|
|
if (isAccessible(elm) || isLogged("stack")) {
|
|
processMarkupRules();
|
|
} else {
|
|
waitForEvent(EVENT_SHOW, elm, processMarkupRules);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test name for current rule and current 'markup' element. Used by
|
|
* testNamesForMarkup function.
|
|
*/
|
|
function testNameForRule(aElm, aRuleElm) {
|
|
if (aRuleElm.hasAttribute("attr")) {
|
|
if (gDumpToConsole) {
|
|
dump(
|
|
"\nProcessing rule { attr: " + aRuleElm.getAttribute("attr") + " }\n"
|
|
);
|
|
}
|
|
|
|
testNameForAttrRule(aElm, aRuleElm);
|
|
} else if (aRuleElm.hasAttribute("elm")) {
|
|
if (gDumpToConsole) {
|
|
dump(
|
|
"\nProcessing rule { elm: " +
|
|
aRuleElm.getAttribute("elm") +
|
|
", elmattr: " +
|
|
aRuleElm.getAttribute("elmattr") +
|
|
" }\n"
|
|
);
|
|
}
|
|
|
|
testNameForElmRule(aElm, aRuleElm);
|
|
} else if (aRuleElm.getAttribute("fromsubtree") == "true") {
|
|
if (gDumpToConsole) {
|
|
dump(
|
|
"\nProcessing rule { fromsubtree: " +
|
|
aRuleElm.getAttribute("fromsubtree") +
|
|
" }\n"
|
|
);
|
|
}
|
|
|
|
testNameForSubtreeRule(aElm, aRuleElm);
|
|
}
|
|
}
|
|
|
|
function testNameForAttrRule(aElm, aRule) {
|
|
var name = "";
|
|
|
|
var attr = aRule.getAttribute("attr");
|
|
var attrValue = aElm.getAttribute(attr);
|
|
|
|
var type = aRule.getAttribute("type");
|
|
if (type == "string") {
|
|
name = attrValue;
|
|
} else if (type == "ref" && attrValue) {
|
|
var ids = attrValue.split(/\s+/);
|
|
for (var idx = 0; idx < ids.length; idx++) {
|
|
var labelElm = getNode(ids[idx]);
|
|
if (name != "") {
|
|
name += " ";
|
|
}
|
|
|
|
name += labelElm.getAttribute("textequiv");
|
|
}
|
|
}
|
|
|
|
var msg = "Attribute '" + attr + "' test (" + gTestIterator.testID + "). ";
|
|
testName(aElm, name, msg);
|
|
|
|
if (aRule.getAttribute("explict-name") != "false") {
|
|
testAttrs(aElm, { "explicit-name": "true" }, true);
|
|
} else {
|
|
testAbsentAttrs(aElm, { "explicit-name": "true" });
|
|
}
|
|
|
|
waitForEvent(
|
|
EVENT_NAME_CHANGE,
|
|
aElm,
|
|
gTestIterator.iterateNext,
|
|
gTestIterator
|
|
);
|
|
|
|
aElm.removeAttribute(attr);
|
|
}
|
|
|
|
function testNameForElmRule(aElm, aRule) {
|
|
var labelElm;
|
|
|
|
var tagname = aRule.getAttribute("elm");
|
|
var attrname = aRule.getAttribute("elmattr");
|
|
if (attrname) {
|
|
var filter = {
|
|
acceptNode: function filter_acceptNode(aNode) {
|
|
if (
|
|
aNode.localName == this.mLocalName &&
|
|
aNode.getAttribute(this.mAttrName) == this.mAttrValue
|
|
) {
|
|
return NodeFilter.FILTER_ACCEPT;
|
|
}
|
|
|
|
return NodeFilter.FILTER_SKIP;
|
|
},
|
|
|
|
mLocalName: tagname,
|
|
mAttrName: attrname,
|
|
mAttrValue: aElm.getAttribute("id"),
|
|
};
|
|
|
|
var treeWalker = document.createTreeWalker(
|
|
document.body,
|
|
NodeFilter.SHOW_ELEMENT,
|
|
filter
|
|
);
|
|
labelElm = treeWalker.nextNode();
|
|
} else {
|
|
// if attrname is empty then look for the element in subtree.
|
|
labelElm = aElm.getElementsByTagName(tagname)[0];
|
|
if (!labelElm) {
|
|
labelElm = aElm.getElementsByTagName("html:" + tagname)[0];
|
|
}
|
|
}
|
|
|
|
if (!labelElm) {
|
|
ok(false, msg + " Failed to find '" + tagname + "' element.");
|
|
gTestIterator.iterateNext();
|
|
return;
|
|
}
|
|
|
|
var msg = "Element '" + tagname + "' test (" + gTestIterator.testID + ").";
|
|
testName(aElm, labelElm.getAttribute("textequiv"), msg);
|
|
testAttrs(aElm, { "explicit-name": "true" }, true);
|
|
|
|
var parentNode = labelElm.parentNode;
|
|
|
|
if (gDumpToConsole) {
|
|
dump(
|
|
"\nProcessed elm rule. Wait for name change event on " +
|
|
prettyName(aElm) +
|
|
"\n"
|
|
);
|
|
}
|
|
waitForEvent(
|
|
EVENT_NAME_CHANGE,
|
|
aElm,
|
|
gTestIterator.iterateNext,
|
|
gTestIterator
|
|
);
|
|
|
|
parentNode.removeChild(labelElm);
|
|
}
|
|
|
|
function testNameForSubtreeRule(aElm) {
|
|
var msg = "From subtree test (" + gTestIterator.testID + ").";
|
|
testName(aElm, aElm.getAttribute("textequiv"), msg);
|
|
testAbsentAttrs(aElm, { "explicit-name": "true" });
|
|
|
|
if (gDumpToConsole) {
|
|
dump(
|
|
"\nProcessed from subtree rule. Wait for name change event on " +
|
|
prettyName(aElm) +
|
|
"\n"
|
|
);
|
|
}
|
|
waitForEvent(
|
|
EVENT_NAME_CHANGE,
|
|
aElm,
|
|
gTestIterator.iterateNext,
|
|
gTestIterator
|
|
);
|
|
|
|
while (aElm.firstChild) {
|
|
aElm.firstChild.remove();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return array of 'rule' elements. Used in conjunction with
|
|
* getRuleElmsFromRulesetElm() function.
|
|
*/
|
|
function getRuleElmsByRulesetId(aRulesetId) {
|
|
var expr = "//rules/ruledfn/ruleset[@id='" + aRulesetId + "']";
|
|
var rulesetElm = evaluateXPath(gRuleDoc, expr);
|
|
return getRuleElmsFromRulesetElm(rulesetElm[0]);
|
|
}
|
|
|
|
function getRuleElmsFromRulesetElm(aRulesetElm) {
|
|
var rulesetId = aRulesetElm.getAttribute("ref");
|
|
if (rulesetId) {
|
|
return getRuleElmsByRulesetId(rulesetId);
|
|
}
|
|
|
|
var ruleElms = [];
|
|
|
|
var child = aRulesetElm.firstChild;
|
|
while (child) {
|
|
if (child.localName == "ruleset") {
|
|
ruleElms = ruleElms.concat(getRuleElmsFromRulesetElm(child));
|
|
}
|
|
if (child.localName == "rule") {
|
|
ruleElms.push(child);
|
|
}
|
|
|
|
child = child.nextSibling;
|
|
}
|
|
|
|
return ruleElms;
|
|
}
|
|
|
|
/**
|
|
* Helper method to evaluate xpath expression.
|
|
*/
|
|
function evaluateXPath(aNode, aExpr, aResolver) {
|
|
var xpe = new XPathEvaluator();
|
|
|
|
var resolver = aResolver;
|
|
if (!resolver) {
|
|
var node =
|
|
aNode.ownerDocument == null
|
|
? aNode.documentElement
|
|
: aNode.ownerDocument.documentElement;
|
|
resolver = xpe.createNSResolver(node);
|
|
}
|
|
|
|
var result = xpe.evaluate(aExpr, aNode, resolver, 0, null);
|
|
var found = [];
|
|
var res;
|
|
while ((res = result.iterateNext())) {
|
|
found.push(res);
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
function htmlDocResolver(aPrefix) {
|
|
var ns = {
|
|
html: "http://www.w3.org/1999/xhtml",
|
|
};
|
|
return ns[aPrefix] || null;
|
|
}
|