summaryrefslogtreecommitdiffstats
path: root/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers')
-rw-r--r--trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/JsDriver.java838
-rw-r--r--trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/ShellTest.java346
-rw-r--r--trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/StandardTests.java212
-rw-r--r--trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/results.html105
4 files changed, 1501 insertions, 0 deletions
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/JsDriver.java b/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/JsDriver.java
new file mode 100644
index 0000000..8bae79f
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/JsDriver.java
@@ -0,0 +1,838 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Java port of jsDriver.pl.
+ *
+ * The Initial Developer of the Original Code is
+ * David P. Caldwell.
+ * Portions created by David P. Caldwell are Copyright (C)
+ * 2007 David P. Caldwell. All Rights Reserved.
+ *
+ *
+ * Contributor(s):
+ * David P. Caldwell <inonit@inonit.com>
+ * Norris Boyd <norrisboyd@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.drivers;
+
+import java.io.*;
+import java.util.*;
+
+import org.w3c.dom.*;
+
+import org.mozilla.javascript.tools.shell.*;
+
+/**
+ * @version $Id: JsDriver.java,v 1.5 2007/10/11 19:44:10 szegedia%freemail.hu Exp $
+ */
+public class JsDriver {
+ private JsDriver() {
+ }
+
+ private static String join(String[] list) {
+ String rv = "";
+ for (int i=0; i<list.length; i++) {
+ rv += list[i];
+ if (i+1 != list.length) {
+ rv += ",";
+ }
+ }
+ return rv;
+ }
+
+ private static class Tests {
+ private File testDirectory;
+ private String[] list;
+ private String[] skip;
+
+ Tests(File testDirectory, String[] list, String[] skip) {
+ this.testDirectory = testDirectory;
+ this.list = getTestList(list);
+ this.skip = getTestList(skip);
+ }
+
+ private String[] getTestList(String[] tests) {
+ ArrayList list = new ArrayList();
+ for (int i=0; i < tests.length; i++) {
+ if (tests[i].startsWith("@"))
+ addTestsFromFile(tests[i].substring(1), list);
+ else
+ list.add(tests[i]);
+ }
+ return (String[])list.toArray(new String[0]);
+ }
+
+ private void addTestsFromFile(String filename, ArrayList list) {
+ try {
+ Properties props = new Properties();
+ props.load(new FileInputStream(new File(filename)));
+ list.addAll(props.keySet());
+ } catch (IOException e) {
+ throw new RuntimeException("Could not read file '" + filename + "'", e);
+ }
+ }
+
+ private boolean matches(String[] patterns, String path) {
+ for (int i=0; i<patterns.length; i++) {
+ if (path.startsWith(patterns[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean matches(String path) {
+ if (list.length == 0) return true;
+ return matches(list, path);
+ }
+
+ private boolean excluded(String path) {
+ if (skip.length == 0) return false;
+ return matches(skip, path);
+ }
+
+ private void addFiles(List rv, String prefix, File directory) {
+ File[] files = directory.listFiles();
+ if (files == null) throw new RuntimeException("files null for " + directory);
+ for (int i=0; i<files.length; i++) {
+ String path = prefix + files[i].getName();
+ if (ShellTest.DIRECTORY_FILTER.accept(files[i])) {
+ addFiles(rv, path + "/", files[i]);
+ } else {
+ boolean isTopLevel = prefix.length() == 0;
+ if (ShellTest.TEST_FILTER.accept(files[i]) && matches(path) && !excluded(path) && !isTopLevel) {
+ rv.add(new Script(path, files[i]));
+ }
+ }
+ }
+ }
+
+ static class Script {
+ private String path;
+ private File file;
+
+ Script(String path, File file) {
+ this.path = path;
+ this.file = file;
+ }
+
+ String getPath() {
+ return path;
+ }
+
+ File getFile() {
+ return file;
+ }
+ }
+
+ Script[] getFiles() {
+ ArrayList rv = new ArrayList();
+ addFiles(rv, "", testDirectory);
+ return (Script[])rv.toArray(new Script[0]);
+ }
+ }
+
+ private static class ConsoleStatus extends ShellTest.Status {
+ private File jsFile;
+
+ private Arguments.Console console;
+ private boolean trace;
+
+ private boolean failed;
+
+ ConsoleStatus(Arguments.Console console, boolean trace) {
+ this.console = console;
+ this.trace = trace;
+ }
+
+ void running(File jsFile) {
+ try {
+ console.println("Running: " + jsFile.getCanonicalPath());
+ this.jsFile = jsFile;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void failed(String s) {
+ console.println("Failed: " + jsFile + ": " + s);
+ failed = true;
+ }
+
+ void threw(Throwable t) {
+ console.println("Failed: " + jsFile + " with exception.");
+ console.println(ShellTest.getStackTrace(t));
+ failed = true;
+ }
+
+ void timedOut() {
+ console.println("Failed: " + jsFile + ": timed out.");
+ failed = true;
+ }
+
+ void exitCodesWere(int expected, int actual) {
+ if (expected != actual) {
+ console.println("Failed: " + jsFile + " expected " + expected + " actual " + actual);
+ failed = true;
+ }
+ }
+
+ void outputWas(String s) {
+ if (!failed) {
+ console.println("Passed: " + jsFile);
+ if (trace) {
+ console.println(s);
+ }
+ }
+ }
+ }
+
+ // returns true if node was found, false otherwise
+ private static boolean setContent(Element node, String id, String content) {
+ if (node.getAttribute("id").equals(id)) {
+ node.setTextContent(node.getTextContent() + "\n" + content);
+ return true;
+ } else {
+ NodeList children = node.getChildNodes();
+ for (int i=0; i<children.getLength(); i++) {
+ if (children.item(i) instanceof Element) {
+ Element e = (Element)children.item(i);
+ boolean rv = setContent( e, id, content );
+ if (rv) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private static Element getElementById(Element node, String id) {
+ if (node.getAttribute("id").equals(id)) {
+ return node;
+ } else {
+ NodeList children = node.getChildNodes();
+ for (int i=0; i<children.getLength(); i++) {
+ if (children.item(i) instanceof Element) {
+ Element rv = getElementById( (Element)children.item(i), id );
+ if (rv != null) {
+ return rv;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private static String newlineLineEndings(String s) {
+ StringBuffer rv = new StringBuffer();
+ for (int i=0; i<s.length(); i++) {
+ if (s.charAt(i) == '\r') {
+ if (i+1<s.length() && s.charAt(i+1) == '\n') {
+ // just skip \r
+ } else {
+ // Macintosh, substitute \n
+ rv.append('\n');
+ }
+ } else {
+ rv.append(s.charAt(i));
+ }
+ }
+ return rv.toString();
+ }
+
+ private static class HtmlStatus extends ShellTest.Status {
+ private String testPath;
+ private String bugUrl;
+ private String lxrUrl;
+ private Document html;
+ private Element failureHtml;
+ private boolean failed;
+
+ private String output;
+
+ HtmlStatus(String lxrUrl, String bugUrl, String testPath, Document html, Element failureHtml) {
+ this.testPath = testPath;
+ this.bugUrl = bugUrl;
+ this.lxrUrl = lxrUrl;
+ this.html = html;
+ this.failureHtml = failureHtml;
+ }
+
+ void running(File file) {
+ }
+
+ void failed(String s) {
+ failed = true;
+ setContent(failureHtml, "failureDetails.reason", "Failure reason: \n" + s);
+ }
+
+ void exitCodesWere(int expected, int actual) {
+ if (expected != actual) {
+ failed = true;
+ setContent(failureHtml, "failureDetails.reason", "expected exit code " + expected + " but got " + actual);
+ }
+ }
+
+ void threw(Throwable e) {
+ failed = true;
+ setContent(failureHtml, "failureDetails.reason", "Threw Java exception:\n" + newlineLineEndings(ShellTest.getStackTrace(e)));
+ }
+
+ void timedOut() {
+ failed = true;
+ setContent(failureHtml, "failureDetails.reason", "Timed out.");
+ }
+
+ void outputWas(String s) {
+ this.output = s;
+ }
+
+ private String getLinesStartingWith(String prefix) {
+ BufferedReader r = new BufferedReader(new StringReader(output));
+ String line = null;
+ String rv = "";
+ try {
+ while( (line = r.readLine()) != null ) {
+ if (line.startsWith(prefix)) {
+ if (rv.length() > 0) {
+ rv += "\n";
+ }
+ rv += line;
+ }
+ }
+ return rv;
+ } catch (IOException e) {
+ throw new RuntimeException("Can't happen.");
+ }
+ }
+
+ boolean failed() {
+ return failed;
+ }
+
+ void finish() {
+ if (failed) {
+ getElementById(failureHtml, "failureDetails.status").setTextContent(getLinesStartingWith("STATUS:"));
+
+ String bn = getLinesStartingWith("BUGNUMBER:");
+ Element bnlink = getElementById(failureHtml, "failureDetails.bug.href");
+ if (bn.length() > 0) {
+ String number = bn.substring("BUGNUMBER: ".length());
+ if (!number.equals("none")) {
+ bnlink.setAttribute("href", bugUrl + number);
+ getElementById(bnlink, "failureDetails.bug.number").setTextContent(number);
+ } else {
+ bnlink.getParentNode().removeChild(bnlink);
+ }
+ } else {
+ bnlink.getParentNode().removeChild(bnlink);
+ }
+
+ getElementById(failureHtml, "failureDetails.lxr").setAttribute("href", lxrUrl + testPath);
+ getElementById(failureHtml, "failureDetails.lxr.text").setTextContent(testPath);
+
+ getElementById(html.getDocumentElement(), "retestList.text").setTextContent(
+ getElementById(html.getDocumentElement(), "retestList.text").getTextContent()
+ + testPath
+ + "\n"
+ );
+
+ getElementById(html.getDocumentElement(), "failureDetails").appendChild(failureHtml);
+ }
+ }
+ }
+
+ private static class XmlStatus extends ShellTest.Status {
+ private Element target;
+ private Date start;
+
+ XmlStatus(String path, Element root) {
+ this.target = root.getOwnerDocument().createElement("test");
+ this.target.setAttribute("path", path);
+ root.appendChild(target);
+ }
+
+ void running(File file) {
+ this.start = new Date();
+ }
+
+ private Element createElement(Element parent, String name) {
+ Element rv = parent.getOwnerDocument().createElement(name);
+ parent.appendChild(rv);
+ return rv;
+ }
+
+ private void finish() {
+ Date end = new Date();
+ long elapsed = end.getTime() - start.getTime();
+ this.target.setAttribute("elapsed", String.valueOf(elapsed));
+ }
+
+ private void setTextContent(Element e, String content) {
+ e.setTextContent( newlineLineEndings(content) );
+ }
+
+ void exitCodesWere(int expected, int actual) {
+ finish();
+ Element exit = createElement(target, "exit");
+ exit.setAttribute("expected", String.valueOf(expected));
+ exit.setAttribute("actual", String.valueOf(actual));
+ }
+
+ void timedOut() {
+ finish();
+ createElement(target, "timedOut");
+ }
+
+ void failed(String s) {
+ finish();
+ Element failed = createElement(target, "failed");
+ setTextContent(failed, s);
+ }
+
+ void outputWas(String message) {
+ finish();
+ Element output = createElement(target, "output");
+ setTextContent(output, message);
+ }
+
+ void threw(Throwable t) {
+ finish();
+ Element threw = createElement(target, "threw");
+ setTextContent(threw, ShellTest.getStackTrace(t));
+ }
+ }
+
+ private static class Results {
+ private ShellContextFactory factory;
+ private Arguments arguments;
+ private File output;
+ private boolean trace;
+
+ private Document html;
+ private Element failureHtml;
+
+ private Document xml;
+
+ private Date start;
+ private int tests;
+ private int failures;
+
+ Results(ShellContextFactory factory, Arguments arguments, boolean trace) {
+ this.factory = factory;
+ this.arguments = arguments;
+
+ File output = arguments.getOutputFile();
+ if (output == null) {
+ output = new File("rhino-test-results." + new java.text.SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(new Date()) + ".html");
+ }
+ this.output = output;
+
+ this.trace = trace;
+ }
+
+ private Document parse(InputStream in) {
+ try {
+ javax.xml.parsers.DocumentBuilderFactory factory = javax.xml.parsers.DocumentBuilderFactory.newInstance();
+ factory.setValidating(false);
+ javax.xml.parsers.DocumentBuilder dom = factory.newDocumentBuilder();
+ return dom.parse(in);
+ } catch (Throwable t) {
+ throw new RuntimeException("Parser failure", t);
+ }
+ }
+
+ private Document getTemplate() {
+ return parse(getClass().getResourceAsStream("results.html"));
+ }
+
+ private void write(Document template, boolean xml) {
+ try {
+ File output = this.output;
+ javax.xml.transform.TransformerFactory factory = javax.xml.transform.TransformerFactory.newInstance();
+ javax.xml.transform.Transformer xform = factory.newTransformer();
+ if (xml) {
+ xform.setOutputProperty(javax.xml.transform.OutputKeys.METHOD, "xml");
+ xform.setOutputProperty(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
+ output = new File(output.getCanonicalPath() + ".xml");
+ }
+ xform.transform(
+ new javax.xml.transform.dom.DOMSource(template),
+ new javax.xml.transform.stream.StreamResult( new FileOutputStream(output) )
+ );
+ } catch (IOException e) {
+ arguments.getConsole().println("Could not write results file to " + output + ": ");
+ e.printStackTrace(System.err);
+ } catch (javax.xml.transform.TransformerConfigurationException e) {
+ throw new RuntimeException("Parser failure", e);
+ } catch (javax.xml.transform.TransformerException e) {
+ throw new RuntimeException("Parser failure", e);
+ }
+ }
+
+ void start() {
+ this.html = getTemplate();
+ this.failureHtml = getElementById(html.getDocumentElement(), "failureDetails.prototype");
+ if (this.failureHtml == null) {
+ try {
+ javax.xml.transform.TransformerFactory.newInstance().newTransformer().transform(
+ new javax.xml.transform.dom.DOMSource(html),
+ new javax.xml.transform.stream.StreamResult(System.err)
+ );
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ throw new RuntimeException("No");
+ }
+ this.failureHtml.getParentNode().removeChild(this.failureHtml);
+
+ try {
+ this.xml = javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder()
+ .getDOMImplementation().createDocument(null, "results", null)
+ ;
+ xml.getDocumentElement().setAttribute("timestamp", String.valueOf(new Date().getTime()));
+ xml.getDocumentElement().setAttribute("optimization", String.valueOf(arguments.getOptimizationLevel()));
+ xml.getDocumentElement().setAttribute("strict", String.valueOf(arguments.isStrict()));
+ xml.getDocumentElement().setAttribute("timeout", String.valueOf(arguments.getTimeout()));
+ } catch (javax.xml.parsers.ParserConfigurationException e) {
+ throw new RuntimeException(e);
+ }
+
+ this.start = new Date();
+ }
+
+ void run(Tests.Script script, ShellTest.Parameters parameters) {
+ String path = script.getPath();
+ File test = script.getFile();
+ ConsoleStatus cStatus = new ConsoleStatus(arguments.getConsole(), trace);
+ HtmlStatus hStatus = new HtmlStatus(arguments.getLxrUrl(), arguments.getBugUrl(), path, html, (Element)failureHtml.cloneNode(true));
+ XmlStatus xStatus = new XmlStatus(path, this.xml.getDocumentElement());
+ ShellTest.Status status = ShellTest.Status.compose(new ShellTest.Status[] { cStatus, hStatus, xStatus });
+ try {
+ ShellTest.run(factory, test, parameters, status);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ tests++;
+ if (hStatus.failed()) {
+ failures++;
+ }
+ hStatus.finish();
+ }
+
+ private void set(Document document, String id, String value) {
+ getElementById(document.getDocumentElement(), id).setTextContent(value);
+ }
+
+ void finish() {
+ Date end = new Date();
+ long elapsedMs = end.getTime() - start.getTime();
+ set(html, "results.testlist", join(arguments.getTestList()));
+ set(html, "results.skiplist", join(arguments.getSkipList()));
+ String pct = new java.text.DecimalFormat("##0.00").format( (double)failures / (double)tests * 100.0 );
+ set(html, "results.results", "Tests attempted: " + tests + " Failures: " + failures + " (" + pct + "%)");
+ set(html, "results.platform", "java.home=" + System.getProperty("java.home")
+ + "\n" + "java.version=" + System.getProperty("java.version")
+ + "\n" + "os.name=" + System.getProperty("os.name")
+ );
+ set(html, "results.classpath", System.getProperty("java.class.path").replace(File.pathSeparatorChar, ' '));
+ int elapsedSeconds = (int)(elapsedMs / 1000);
+ int elapsedMinutes = elapsedSeconds / 60;
+ elapsedSeconds = elapsedSeconds % 60;
+ String elapsed = "" + elapsedMinutes + " minutes, " + elapsedSeconds + " seconds";
+ set(html, "results.elapsed", elapsed);
+ set(html, "results.time", new java.text.SimpleDateFormat("MMMM d yyyy h:mm:ss aa").format(new java.util.Date()));
+ write(html, false);
+ write(xml, true);
+ }
+ }
+
+ private static class ShellTestParameters extends ShellTest.Parameters {
+ private int timeout;
+
+ ShellTestParameters(int timeout) {
+ this.timeout = timeout;
+ }
+
+ int getTimeoutMilliseconds() {
+ return timeout;
+ }
+ }
+
+ void run(Arguments arguments) throws Throwable {
+ if (arguments.help()) {
+ System.out.println("See mozilla/js/tests/README-jsDriver.html; note that some options are not supported.");
+ System.out.println("Consult the Java source code at testsrc/org/mozilla/javascript/JsDriver.java for details.");
+ System.exit(0);
+ }
+
+ ShellContextFactory factory = new ShellContextFactory();
+ factory.setOptimizationLevel(arguments.getOptimizationLevel());
+ factory.setStrictMode(arguments.isStrict());
+
+ File path = arguments.getTestsPath();
+ if (path == null) {
+ path = new File("../tests");
+ }
+ if (!path.exists()) {
+ throw new RuntimeException("JavaScript tests not found at " + path.getCanonicalPath());
+ }
+ Tests tests = new Tests(path, arguments.getTestList(), arguments.getSkipList());
+ Tests.Script[] all = tests.getFiles();
+ arguments.getConsole().println("Running " + all.length + " tests.");
+
+ Results results = new Results(factory, arguments, arguments.trace());
+
+ results.start();
+ for (int i=0; i<all.length; i++) {
+ results.run(all[i], new ShellTestParameters(arguments.getTimeout()));
+ }
+ results.finish();
+ }
+
+ public static void main(Arguments arguments) throws Throwable {
+ JsDriver driver = new JsDriver();
+ driver.run(arguments);
+ }
+
+ private static class Arguments {
+ private ArrayList options = new ArrayList();
+
+ private Option bugUrl = new Option("b", "bugurl", false, false, "http://bugzilla.mozilla.org/show_bug.cgi?id=");
+ private Option optimizationLevel = new Option("o", "optimization", false, false, "-1");
+ private Option strict = new Option(null, "strict", false, true, null);
+ private Option outputFile = new Option("f", "file", false, false, null);
+ private Option help = new Option("h", "help", false, true, null);
+ private Option logFailuresToConsole = new Option("k", "confail", false, true, null);
+ private Option testList = new Option("l", "list", true, false, null);
+ private Option skipList = new Option("L", "neglist", true, false, null);
+ private Option testsPath = new Option("p", "testpath", false, false, null);
+ private Option trace = new Option("t", "trace", false, true, null);
+ private Option lxrUrl = new Option("u", "lxrurl", false, false, "http://lxr.mozilla.org/mozilla/source/js/tests/");
+ private Option timeout = new Option(null, "timeout", false, false, "60000");
+
+ public static class Console {
+ public void print(String message) {
+ System.out.print(message);
+ }
+ public void println(String message) {
+ System.out.println(message);
+ }
+ }
+ private Console console = new Console();
+
+ private class Option {
+ private String letterOption;
+ private String wordOption;
+ private boolean array;
+ private boolean flag;
+ private boolean ignored;
+
+ private ArrayList values = new ArrayList();
+
+ // array: can this option have multiple values?
+ // flag: is this option a simple true/false switch?
+ Option(String letterOption, String wordOption, boolean array, boolean flag, String unspecified) {
+ this.letterOption = letterOption;
+ this.wordOption = wordOption;
+ this.flag = flag;
+ this.array = array;
+ if (!flag && !array) {
+ this.values.add(unspecified);
+ }
+ options.add(this);
+ }
+
+ Option ignored() {
+ this.ignored = true;
+ return this;
+ }
+
+ int getInt() {
+ return Integer.parseInt( getValue() );
+ }
+
+ String getValue() {
+ return (String)values.get(0);
+ }
+
+ boolean getSwitch() {
+ return values.size() > 0;
+ }
+
+ File getFile() {
+ if (getValue() == null) return null;
+ return new File(getValue());
+ }
+
+ String[] getValues() {
+ return (String[])values.toArray(new String[0]);
+ }
+
+ void process(List arguments) {
+ String option = (String)arguments.get(0);
+ String dashLetter = (letterOption == null) ? (String)null : "-" + letterOption;
+ if (option.equals(dashLetter) || option.equals("--" + wordOption)) {
+ arguments.remove(0);
+ if (flag) {
+ values.add(0, (String)null );
+ } else if (array) {
+ while( arguments.size() > 0 && !( (String)arguments.get(0) ).startsWith("-") ) {
+ values.add(arguments.remove(0));
+ }
+ } else {
+ values.set(0, arguments.remove(0));
+ }
+ if (ignored) {
+ System.err.println("WARNING: " + option + " is ignored in the Java version of the test driver.");
+ }
+ }
+ }
+ }
+
+ // -b URL, --bugurl=URL
+ public String getBugUrl() {
+ return bugUrl.getValue();
+ }
+
+ // -c PATH, --classpath=PATH
+ // Does not apply; we will use the VM's classpath
+
+ // -e TYPE ..., --engine=TYPE ...
+ // Does not apply; was used to select between SpiderMonkey and Rhino
+
+ // Not in jsDriver.pl
+ public int getOptimizationLevel() {
+ return optimizationLevel.getInt();
+ }
+
+ // --strict
+ public boolean isStrict() {
+ return strict.getSwitch();
+ }
+
+ // -f FILE, --file=FILE
+ public File getOutputFile() {
+ return outputFile.getFile();
+ }
+
+ // -h, --help
+ public boolean help() {
+ return help.getSwitch();
+ }
+
+ // -j PATH, --javapath=PATH
+ // Does not apply; we will use this JVM
+
+ // -k, --confail
+ // TODO Currently this is ignored; not clear precisely what it means (perhaps we should not be logging ordinary
+ // pass/fail to the console currently?)
+ public boolean logFailuresToConsole() {
+ return logFailuresToConsole.getSwitch();
+ }
+
+ // -l FILE,... or --list=FILE,...
+ public String[] getTestList() {
+ return testList.getValues();
+ }
+
+ // -L FILE,... or --neglist=FILE,...
+ public String[] getSkipList() {
+ return skipList.getValues();
+ }
+
+ // -p PATH, --testpath=PATH
+ public File getTestsPath() {
+ return testsPath.getFile();
+ }
+
+ // -s PATH, --shellpath=PATH
+ // Does not apply; we will use the Rhino shell with any classes given on the classpath
+
+ // -t, --trace
+ public boolean trace() {
+ return trace.getSwitch();
+ }
+
+ // -u URL, --lxrurl=URL
+ public String getLxrUrl() {
+ return lxrUrl.getValue();
+ }
+
+ //
+ // New arguments
+ //
+
+ // --timeout
+ // Milliseconds to wait for each test
+ public int getTimeout() {
+ return timeout.getInt();
+ }
+
+ public Console getConsole() {
+ return console;
+ }
+
+ void process(List arguments) {
+ while(arguments.size() > 0) {
+ String option = (String)arguments.get(0);
+ if (option.startsWith("--")) {
+ // preprocess --name=value options into --name value
+ if (option.indexOf("=") != -1) {
+ arguments.set(0, option.substring(option.indexOf("=")));
+ arguments.add(1, option.substring(option.indexOf("=") + 1));
+ }
+ } else if (option.startsWith("-")) {
+ // could be multiple single-letter options, e.g. -kht, so preprocess them into -k -h -t
+ if (option.length() > 2) {
+ for (int i=2; i<option.length(); i++) {
+ arguments.add(1, "-" + option.substring(i,i+1));
+ }
+ arguments.set(0, option.substring(0,2));
+ }
+ }
+ int lengthBefore = arguments.size();
+ for (int i=0; i<options.size(); i++) {
+ if (arguments.size() > 0) {
+ ((Option)options.get(i)).process(arguments);
+ }
+ }
+
+ if (arguments.size() == lengthBefore) {
+ System.err.println("WARNING: ignoring unrecognized option " + arguments.remove(0));
+ }
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Throwable {
+ ArrayList arguments = new ArrayList();
+ arguments.addAll(Arrays.asList(args));
+ Arguments clArguments = new Arguments();
+ clArguments.process(arguments);
+ main(clArguments);
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/ShellTest.java b/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/ShellTest.java
new file mode 100644
index 0000000..9acf64e
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/ShellTest.java
@@ -0,0 +1,346 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Java port of jsDriver.pl.
+ *
+ * The Initial Developer of the Original Code is
+ * David P. Caldwell.
+ * Portions created by David P. Caldwell are Copyright (C)
+ * 2007 David P. Caldwell. All Rights Reserved.
+ *
+ *
+ * Contributor(s):
+ * David P. Caldwell <inonit@inonit.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.drivers;
+
+import org.mozilla.javascript.*;
+import java.io.*;
+import java.util.*;
+
+import org.mozilla.javascript.tools.shell.*;
+
+/**
+ * @version $Id: ShellTest.java,v 1.5 2007/10/11 19:44:10 szegedia%freemail.hu Exp $
+ */
+class ShellTest {
+ static final FileFilter DIRECTORY_FILTER = new FileFilter() {
+ public boolean accept(File pathname)
+ {
+ return pathname.isDirectory() && !pathname.getName().equals("CVS");
+ }
+ };
+
+ static final FileFilter TEST_FILTER = new FileFilter() {
+ public boolean accept(File pathname)
+ {
+ return pathname.getName().endsWith(".js") && !pathname.getName().equals("shell.js") && !pathname.getName().equals("browser.js") && !pathname.getName().equals("template.js");
+ }
+ };
+
+ static String getStackTrace(Throwable t) {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ t.printStackTrace(new PrintStream(bytes));
+ return new String(bytes.toByteArray());
+ }
+
+ private static void runFileIfExists(Context cx, Scriptable global, File f)
+ {
+ if(f.isFile())
+ {
+ Main.processFile(cx, global, f.getPath());
+ }
+ }
+
+ private static class TestState
+ {
+ boolean finished;
+ ErrorReporterWrapper errors;
+ int exitCode = 0;
+ }
+
+ static abstract class Status {
+ private boolean negative;
+
+ final void setNegative() {
+ this.negative = true;
+ }
+
+ final boolean isNegative() {
+ return this.negative;
+ }
+
+ final void hadErrors(JsError[] errors) {
+ if (!negative && errors.length > 0) {
+ failed("JavaScript errors:\n" + JsError.toString(errors));
+ } else if (negative && errors.length == 0) {
+ failed("Should have produced runtime error.");
+ }
+ }
+
+ abstract void running(File jsFile);
+
+ abstract void failed(String s);
+ abstract void threw(Throwable t);
+ abstract void timedOut();
+ abstract void exitCodesWere(int expected, int actual);
+ abstract void outputWas(String s);
+
+ static Status compose(final Status[] array) {
+ return new Status() {
+ void running(File file) {
+ for (int i=0; i<array.length; i++) {
+ array[i].running(file);
+ }
+ }
+ void threw(Throwable t) {
+ for (int i=0; i<array.length; i++) {
+ array[i].threw(t);
+ }
+ }
+ void failed(String s) {
+ for (int i=0; i<array.length; i++) {
+ array[i].failed(s);
+ }
+ }
+ void exitCodesWere(int expected, int actual) {
+ for (int i=0; i<array.length; i++) {
+ array[i].exitCodesWere(expected, actual);
+ }
+ }
+ void outputWas(String s) {
+ for (int i=0; i<array.length; i++) {
+ array[i].outputWas(s);
+ }
+ }
+ void timedOut() {
+ for (int i=0; i<array.length; i++) {
+ array[i].timedOut();
+ }
+ }
+ };
+ }
+
+ static class JsError {
+ static String toString(JsError[] e) {
+ String rv = "";
+ for (int i=0; i<e.length; i++) {
+ rv += e[i].toString();
+ if (i+1 != e.length) {
+ rv += "\n";
+ }
+ }
+ return rv;
+ }
+
+ private String message;
+ private String sourceName;
+ private int line;
+ private String lineSource;
+ private int lineOffset;
+
+ JsError(String message, String sourceName, int line, String lineSource, int lineOffset) {
+ this.message = message;
+ this.sourceName = sourceName;
+ this.line = line;
+ this.lineSource = lineSource;
+ this.lineOffset = lineOffset;
+ }
+
+ public String toString() {
+ String locationLine = sourceName + ":" + line + ": " + message;
+ String sourceLine = this.lineSource;
+ String errCaret = null;
+ if (lineSource != null) {
+ errCaret = "";
+ for (int i=0; i<lineSource.length(); i++) {
+ char c = lineSource.charAt(i);
+ if (i < lineOffset-1) {
+ if (c == '\t') {
+ errCaret += "\t";
+ } else {
+ errCaret += " ";
+ }
+ } else if (i == lineOffset-1) {
+ errCaret += "^";
+ }
+ }
+ }
+ String rv = locationLine;
+ if (sourceLine != null) {
+ rv += "\n" + sourceLine;
+ }
+ if (errCaret != null) {
+ rv += "\n" + errCaret;
+ }
+ return rv;
+ }
+
+ String getMessage() {
+ return message;
+ }
+
+ String getSourceName() {
+ return sourceName;
+ }
+
+ int getLine() {
+ return line;
+ }
+
+ String getLineSource() {
+ return lineSource;
+ }
+
+ int getLineOffset() {
+ return lineOffset;
+ }
+ }
+ }
+
+ private static class ErrorReporterWrapper implements ErrorReporter {
+ private ErrorReporter original;
+ private ArrayList errors = new ArrayList();
+
+ ErrorReporterWrapper(ErrorReporter original) {
+ this.original = original;
+ }
+
+ private void addError(String string, String string0, int i, String string1, int i0) {
+ errors.add( new Status.JsError(string, string0, i, string1, i0) );
+ }
+
+ public void warning(String string, String string0, int i, String string1, int i0) {
+ original.warning(string, string0, i, string1, i0);
+ }
+
+ public EvaluatorException runtimeError(String string, String string0, int i, String string1, int i0) {
+ return original.runtimeError(string, string0, i, string1, i0);
+ }
+
+ public void error(String string, String string0, int i, String string1, int i0) {
+ addError(string, string0, i, string1, i0);
+ }
+ }
+
+ static abstract class Parameters {
+ abstract int getTimeoutMilliseconds();
+ }
+
+ static void run(final ShellContextFactory shellContextFactory, final File jsFile, final Parameters parameters, final Status status) throws Exception {
+ final Global global = new Global();
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final PrintStream p = new PrintStream(out);
+ global.setOut(p);
+ global.setErr(p);
+ final TestState testState = new TestState();
+ if (jsFile.getName().endsWith("-n.js")) {
+ status.setNegative();
+ }
+ Thread t = new Thread(new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ shellContextFactory.call(new ContextAction()
+ {
+ public Object run(Context cx)
+ {
+ System.out.println("Running " + jsFile);
+ status.running(jsFile);
+ testState.errors = new ErrorReporterWrapper(cx.getErrorReporter());
+ cx.setErrorReporter( testState.errors );
+ global.init(cx);
+ try {
+ runFileIfExists(cx, global, new File(jsFile.getParentFile().getParentFile().getParentFile(), "shell.js"));
+ runFileIfExists(cx, global, new File(jsFile.getParentFile().getParentFile(), "shell.js"));
+ runFileIfExists(cx, global, new File(jsFile.getParentFile(), "shell.js"));
+ runFileIfExists(cx, global, jsFile);
+ // Emulate SpiderMonkey enum value from mozilla/js/src/js.c
+ for (int i=0; i<testState.errors.errors.size(); i++) {
+ Status.JsError thisOne = (Status.JsError)testState.errors.errors.get(i);
+ if (thisOne.getMessage().indexOf("java.lang.OutOfMemoryError") != -1) {
+ testState.exitCode = 5;
+ testState.errors.errors.remove(thisOne);
+ }
+ }
+ status.hadErrors( (Status.JsError[])testState.errors.errors.toArray(new Status.JsError[0]) );
+ } catch (ThreadDeath e) {
+ } catch (Throwable t) {
+ status.threw(t);
+ }
+ return null;
+ }
+ });
+ } finally {
+ synchronized(testState)
+ {
+ testState.finished = true;
+ }
+ }
+ }
+ }, jsFile.getPath());
+ t.setDaemon(true);
+ t.start();
+ t.join(parameters.getTimeoutMilliseconds());
+ synchronized(testState)
+ {
+ if(!testState.finished)
+ {
+ t.stop();
+ status.timedOut();
+ }
+ }
+ int expectedExitCode = 0;
+ p.flush();
+ status.outputWas(new String(out.toByteArray()));
+ BufferedReader r = new BufferedReader(new InputStreamReader(
+ new ByteArrayInputStream(out.toByteArray())));
+ String failures = "";
+ for(;;)
+ {
+ String s = r.readLine();
+ if(s == null)
+ {
+ break;
+ }
+ if(s.indexOf("FAILED!") != -1)
+ {
+ failures += s + '\n';
+ }
+ int expex = s.indexOf("EXPECT EXIT CODE ");
+ if(expex != -1)
+ {
+ expectedExitCode = s.charAt(expex + "EXPECT EXIT CODE ".length()) - '0';
+ }
+ }
+ status.exitCodesWere(expectedExitCode, testState.exitCode);
+ if(failures != "")
+ {
+ status.failed(failures);
+ }
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/StandardTests.java b/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/StandardTests.java
new file mode 100644
index 0000000..9c05df6
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/StandardTests.java
@@ -0,0 +1,212 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Attila Szegedi
+ * David P. Caldwell <inonit@inonit.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.drivers;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Properties;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.mozilla.javascript.tools.shell.ShellContextFactory;
+
+/**
+ * Executes the tests in the js/tests directory, much like jsDriver.pl does.
+ * Excludes tests found in the js/tests/rhino-n.tests file.
+ * @author Attila Szegedi
+ * @version $Id: StandardTests.java,v 1.6.2.2 2008/02/11 16:57:16 nboyd%atg.com Exp $
+ */
+public class StandardTests extends TestSuite
+{
+ public static TestSuite suite() throws Exception
+ {
+ TestSuite suite = new TestSuite("Standard JavaScript tests");
+
+ File testDir = null;
+ if (System.getProperty("mozilla.js.tests") != null) {
+ testDir = new File(System.getProperty("mozilla.js.tests"));
+ } else {
+ URL url = StandardTests.class.getResource(".");
+ String path = url.getFile();
+ int jsIndex = path.lastIndexOf("/js");
+ if(jsIndex == -1)
+ {
+ throw new IllegalStateException("You aren't running the tests from within the standard mozilla/js directory structure");
+ }
+ path = path.substring(0, jsIndex + 3).replace('/', File.separatorChar);
+ testDir = new File(path, "tests");
+ }
+ if(!testDir.isDirectory())
+ {
+ throw new FileNotFoundException(testDir + " is not a directory");
+ }
+ Properties excludes = new Properties();
+ loadExcludes(excludes, "/base.skip");
+ Properties opt1Excludes = new Properties();
+ loadExcludes(opt1Excludes, "/opt1.skip");
+ opt1Excludes.putAll(excludes);
+ for(int i = -1; i < 2; ++i)
+ {
+ TestSuite optimizationLevelSuite = new TestSuite("Optimization level " + i);
+ addSuites(optimizationLevelSuite, testDir, i == -1 ? excludes : opt1Excludes, i);
+ suite.addTest(optimizationLevelSuite);
+ }
+ return suite;
+ }
+
+ private static void loadExcludes(Properties excludes, String excludeFileName) throws IOException
+ {
+ InputStream in = StandardTests.class.getResourceAsStream(excludeFileName);
+ try
+ {
+ excludes.load(in);
+ }
+ finally
+ {
+ in.close();
+ }
+ }
+
+ private static void addSuites(TestSuite topLevel, File testDir, Properties excludes, int optimizationLevel)
+ {
+ File[] subdirs = testDir.listFiles(ShellTest.DIRECTORY_FILTER);
+ Arrays.sort(subdirs);
+ for (int i = 0; i < subdirs.length; i++)
+ {
+ File subdir = subdirs[i];
+ String name = subdir.getName();
+ TestSuite testSuite = new TestSuite(name);
+ addCategories(testSuite, subdir, name + "/", excludes, optimizationLevel);
+ topLevel.addTest(testSuite);
+ }
+ }
+
+ private static void addCategories(TestSuite suite, File suiteDir, String prefix, Properties excludes, int optimizationLevel)
+ {
+ File[] subdirs = suiteDir.listFiles(ShellTest.DIRECTORY_FILTER);
+ Arrays.sort(subdirs);
+ for (int i = 0; i < subdirs.length; i++)
+ {
+ File subdir = subdirs[i];
+ String name = subdir.getName();
+ TestSuite testCategory = new TestSuite(name);
+ addTests(testCategory, subdir, prefix + name + "/", excludes, optimizationLevel);
+ suite.addTest(testCategory);
+ }
+ }
+
+ private static void addTests(TestSuite suite, File suiteDir, String prefix, Properties excludes, int optimizationLevel)
+ {
+ File[] jsFiles = suiteDir.listFiles(ShellTest.TEST_FILTER);
+ Arrays.sort(jsFiles);
+ for (int i = 0; i < jsFiles.length; i++)
+ {
+ File jsFile = jsFiles[i];
+ String name = jsFile.getName();
+ if(!excludes.containsKey(prefix + name))
+ {
+ suite.addTest(new JsTestCase(jsFile, optimizationLevel));
+ }
+ }
+ }
+
+ private static class JunitStatus extends ShellTest.Status {
+ final void running(File jsFile) {
+ // do nothing
+ }
+
+ final void failed(String s) {
+ Assert.fail(s);
+ }
+
+ final void exitCodesWere(int expected, int actual) {
+ Assert.assertEquals("Unexpected exit code", expected, actual);
+ }
+
+ final void outputWas(String s) {
+ System.out.print(s);
+ }
+
+ final void threw(Throwable t) {
+ Assert.fail(ShellTest.getStackTrace(t));
+ }
+
+ final void timedOut() {
+ failed("Timed out.");
+ }
+ }
+
+ private static final class JsTestCase extends TestCase
+ {
+ private final File jsFile;
+ private final int optimizationLevel;
+
+ JsTestCase(File jsFile, int optimizationLevel)
+ {
+ super(jsFile.getName() + (optimizationLevel == 1 ? "-compiled" : "-interpreted"));
+ this.jsFile = jsFile;
+ this.optimizationLevel = optimizationLevel;
+ }
+
+ public int countTestCases()
+ {
+ return 1;
+ }
+
+ private static class ShellTestParameters extends ShellTest.Parameters {
+ int getTimeoutMilliseconds() {
+ if (System.getProperty("mozilla.js.tests.timeout") != null) {
+ return Integer.parseInt(System.getProperty("mozilla.js.tests.timeout"));
+ }
+ return 60000;
+ }
+ }
+
+ public void runBare() throws Exception
+ {
+ final ShellContextFactory shellContextFactory = new ShellContextFactory();
+ shellContextFactory.setOptimizationLevel(optimizationLevel);
+ ShellTest.run(shellContextFactory, jsFile, new ShellTestParameters(), new JunitStatus());
+ }
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/results.html b/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/results.html
new file mode 100644
index 0000000..36bd729
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/results.html
@@ -0,0 +1,105 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Rhino: Test Results</title>
+</head>
+<body>
+ <a name="top"><span /></a>
+ <h1>Results of JavaScript Test Library for Rhino</h1>
+ <div id="summary">
+ <h2>Summary</h2>
+ <p>
+ <table>
+ <tr>
+ <td>
+ Test List
+ </td>
+ <td>
+ <span id="results.testlist">
+ </span>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Skip List
+ </td>
+ <td>
+ <span id="results.skiplist">
+ </span>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Results
+ </td>
+ <td>
+ <span id="results.results">
+ </span>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Platform, JRE
+ </td>
+ <td>
+ <!--
+ Should include os.name, java.home, java.version, java.class.path
+ -->
+ <span id="results.platform"></span>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Classpath
+ </td>
+ <td>
+ <span id="results.classpath"></span>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Time
+ </td>
+ <td>
+ Execution took <span id="results.elapsed"></span>, ending at <span id="results.time"></span>
+ </td>
+ </tr>
+ </table>
+ </p>
+ <p>
+ <a href="#failureDetails">Failure Details</a>
+ <a href="#retestList">Retest List</a>
+ </p>
+ </div>
+ <div id="failureDetails">
+ <a name="failureDetails"><span /></a>
+ <h2>Failure Details</h2>
+ <div id="failureDetails.prototype">
+ <h3>
+ Testcase <a id="failureDetails.lxr" href=""><span id="failureDetails.lxr.text">path</span></a> failed
+ <a id="failureDetails.bug.href" href="">Bug Number <span id="failureDetails.bug.number">XXX</span></a>
+ </h3>
+ <div>
+ <pre id="failureDetails.status">
+ </pre>
+ <pre id="failureDetails.reason">
+ </pre>
+ <pre id="failureDetails.output">
+ </pre>
+ </div>
+ <div>
+ <a href="#top">Top of Page</a>
+ </div>
+ </div>
+ </div>
+ <div>
+ <a href="#failureDetails">Top of Failures</a>
+ </div>
+ <div>
+ <a name="retestList"><span /></a>
+ <h2>Retest List</h2>
+ <pre id="retestList.text"></pre>
+ <a href="#top">Top of Page</a>
+ <a href="#retestList">Top of Retest List</a>
+ </div>
+</body>
+</html>