Fix for #353501: Add Java port of jsDriver.pl; catch some additional failure cases in JUnit test driver

This commit is contained in:
inonit%inonit.com 2007-01-24 22:15:00 +00:00
Родитель 79721b17ea
Коммит db0cc5fc09
6 изменённых файлов: 1280 добавлений и 149 удалений

Просмотреть файл

@ -204,7 +204,39 @@ Requires Ant version 1.2 or later
<delete quiet="true" file="${dist.file}"/>
<delete quiet="true" file="${dist.source-only-zip}"/>
</target>
<!--
The next two targets run the JavaScript Test Library tests. Note that these tests are quite extensive and take a long time
to run. They are not documented in the 'help' target for now.
-->
<!--
Run the tests using JUnit. Beware that if you are using Ant from the command-line, there are some difficulties you may
encounter setting this up correctly; see http://ant.apache.org/faq.html#delegating-classloader
IDEs that use Ant as the build system probably handle this fine.
-->
<target name="junit-all" depends="compile">
<ant antfile="testsrc/build.xml" target="junit"/>
</target>
<!--
Run the tests using the Java port of jsdriver.pl. Note that running this port from the command-line
may be superior, as it allows configuration options, such as running with a non-default optimization level or running only
a subset of the tests.
-->
<target name="jsdriver-all" depends="compile">
<ant antfile="testsrc/build.xml" target="jsdriver" />
</target>
<!--
Target just for development of the test code.
-->
<target name="_test-recompile" depends="compile">
<ant antfile="testsrc/build.xml" target="clean" />
<ant antfile="testsrc/build.xml" target="compile" />
</target>
<target name="help" depends="properties">
<echo>The following targets are available with this build file:

Просмотреть файл

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="testsrc" basedir="..">
<!--
Location of mozilla/js/tests directory
-->
<property name="test.library.dir" location="../tests" />
<!--
Destination to which testing classes should be built
-->
<property name="test.classes" value="${build.dir}/test/classes" />
<!--
Output directory for HTML files generated by jsdriver
-->
<property name="test.output" value="${build.dir}/test/output" />
<!--
Timeout in milliseconds for tests
-->
<property name="test.timeout" value="60000" />
<!--
Maximum heap size for VM executing test cases.
-->
<property name="test.vm.mx" value="256m" />
<!--
TODO Currently JUnit is required in order to compile the test code, which ought not be necessary
-->
<target name="compile">
<mkdir dir="${test.classes}" />
<javac destdir="${test.classes}" debug="true"
target="${target-jvm}"
source="${source-level}"
>
<classpath>
<pathelement path="${classes}" />
</classpath>
<src path="testsrc" />
</javac>
<copy todir="${test.classes}/org/mozilla/javascript">
<fileset dir="testsrc/org/mozilla/javascript">
<include name="*.html"/>
</fileset>
</copy>
</target>
<target name="clean">
<delete dir="${test.classes}" />
</target>
<target name="junit" depends="compile">
<junit printsummary="on" fork="true" forkmode="once" maxmemory="${test.vm.mx}" showoutput="true">
<sysproperty key="mozilla.js.tests" value="${test.library.dir}" />
<sysproperty key="mozilla.js.tests.timeout" value="${test.timeout}" />
<classpath>
<pathelement location="${xbean.jar}"/>
<pathelement location="${jsr173.jar}"/>
<pathelement path="${classes}" />
<pathelement path="${test.classes}" />
</classpath>
<test name="org.mozilla.javascript.StandardTests" />
<formatter type="plain" usefile="false" />
</junit>
</target>
<target name="jsdriver" depends="compile">
<tstamp>
<format property="test.timestamp" pattern="yyyy.MM.dd.HH.mm.ss" />
</tstamp>
<mkdir dir="${test.output}" />
<java
fork="true"
classname="org.mozilla.javascript.JsDriver"
maxmemory="${test.vm.mx}"
>
<classpath>
<pathelement location="${xbean.jar}"/>
<pathelement location="${jsr173.jar}"/>
<pathelement path="${classes}" />
<pathelement path="${test.classes}" />
</classpath>
<arg value="-p" />
<arg file="${test.library.dir}" />
<arg value="-f" />
<arg value="${test.output}/rhino-test-results.${test.timestamp}.html" />
<arg value="--timeout" />
<arg value="${test.timeout}" />
</java>
</target>
</project>

Просмотреть файл

@ -0,0 +1,770 @@
/* ***** 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
*
* 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;
import java.io.*;
import java.lang.reflect.Array;
import java.util.*;
import org.w3c.dom.*;
import org.mozilla.javascript.tools.shell.*;
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, boolean skipRhinoN) {
this.testDirectory = testDirectory;
this.list = list;
ArrayList skips = new ArrayList();
skips.addAll(Arrays.asList(skip));
if (skipRhinoN) {
try {
Properties rhinoN = new Properties();
rhinoN.load( new FileInputStream( new File(testDirectory, "rhino-n.tests") ) );
skips.addAll( rhinoN.keySet() );
} catch (IOException e) {
throw new RuntimeException("Could not read rhino-n.tests", e);
}
}
this.skip = (String[])skips.toArray(new String[0]);
}
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 class HtmlStatus extends ShellTest.Status {
private String testPath;
private String bugUrl;
private String lxrUrl;
private Document html;
private Element failureHtml;
private File file;
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) {
this.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);
}
}
private 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();
}
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 Results {
private ShellContextFactory factory;
private Arguments arguments;
private File output;
private boolean trace;
private Document html;
private Element failureHtml;
private int tests;
private int failures;
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"));
}
Results(ShellContextFactory factory, Arguments arguments, File output, boolean trace) {
this.factory = factory;
this.arguments = arguments;
this.output = output;
this.trace = trace;
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);
}
private void write(Document template) {
try {
javax.xml.transform.TransformerFactory.newInstance().newTransformer().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 run(String path, File test, ShellTest.Parameters parameters) {
ConsoleStatus cStatus = new ConsoleStatus(arguments.getConsole(), trace);
HtmlStatus hStatus = new HtmlStatus(arguments.getLxrUrl(), arguments.getBugUrl(), path, html, (Element)failureHtml.cloneNode(true));
ShellTest.Status status = ShellTest.Status.compose(cStatus, hStatus);
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 start, Date end) {
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);
}
}
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 {
// TODO Allow rhino-n tests to be skipped
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());
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(), !arguments.ignoreRhinoSkipList());
Tests.Script[] all = tests.getFiles();
arguments.getConsole().println("Running " + all.length + " tests.");
File output = new File("rhino-test-results." + new java.text.SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(new Date()) + ".html");
if (arguments.getOutputFile() != null) {
output = arguments.getOutputFile();
}
Results results = new Results(factory, arguments, output, arguments.trace());
Date start = new Date();
for (int i=0; i<all.length; i++) {
results.run(all[i].getPath(), all[i].getFile(), new ShellTestParameters(arguments.getTimeout()));
}
Date end = new Date();
results.finish(start, end);
}
public static void main(Arguments arguments) throws Throwable {
JsDriver driver = new JsDriver();
driver.run(arguments);
}
public static abstract class Arguments {
// List of jsDriver.pl arguments
// -b URL, --bugurl=URL
public abstract String getBugUrl();
// -c PATH, --classpath=PATH
// Does not apply; we will use the VM's classpath
// -e TYPE ..., --engine=TYPE ...
// Does not apply, but we should provide the ability to test various optimization levels
public abstract int getOptimizationLevel();
// -f FILE, --file=FILE
public abstract File getOutputFile();
// -h, --help
public abstract boolean help();
// -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 abstract boolean logFailuresToConsole();
// -l FILE ..., --list=FILE ...
public abstract String[] getTestList();
// -L FILE ..., --neglist=FILE ...
public abstract String[] getSkipList();
// -p PATH, --testpath=PATH
public abstract File getTestsPath();
// -s PATH, --shellpath=PATH
// Does not apply; we will use the Rhino shell with any classes given on the classpath
// -t, --trace
public abstract boolean trace();
// -u URL, --lxrurl=URL
public abstract String getLxrUrl();
//
// New arguments
//
// --ignore-rhino-n
public abstract boolean ignoreRhinoSkipList();
// --timeoutms
public abstract int getTimeout();
public static abstract class Console {
public abstract void print(String message);
public abstract void println(String message);
}
public abstract Console getConsole();
}
private static class CommandLineArguments extends 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 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 ignoreRhinoN = new Option(null, "ignore-rhino-n", false, true, null);
private Option timeout = new Option(null, "timeout", false, false, "60000");
private Option classpath = new Option("c", "classpath", false, false, null).ignored();
private Option engine = new Option("e", "engine", false, false, null).ignored();
private Option javapath = new Option("j", "javapath", false, false, null).ignored();
private Option shellpath = new Option("s", "shellpath", false, false, null).ignored();
private Console console = new Console() {
public void print(String s) {
System.out.print(s);
}
public void println(String s) {
System.out.println(s);
}
};
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( (String)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.");
}
}
}
}
public String getBugUrl() {
return bugUrl.getValue();
}
public int getOptimizationLevel() {
return optimizationLevel.getInt();
}
public File getOutputFile() {
return outputFile.getFile();
}
public boolean help() {
return help.getSwitch();
}
public boolean logFailuresToConsole() {
return logFailuresToConsole.getSwitch();
}
public String[] getTestList() {
return testList.getValues();
}
public String[] getSkipList() {
return skipList.getValues();
}
public File getTestsPath() {
return testsPath.getFile();
}
public boolean trace() {
return trace.getSwitch();
}
public String getLxrUrl() {
return lxrUrl.getValue();
}
public boolean ignoreRhinoSkipList() {
return ignoreRhinoN.getSwitch();
}
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));
CommandLineArguments clArguments = new CommandLineArguments();
clArguments.process(arguments);
main(clArguments);
}
}

Просмотреть файл

@ -0,0 +1,324 @@
/* ***** 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
*
* 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;
import java.io.*;
import java.util.*;
import org.mozilla.javascript.tools.shell.*;
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");
}
};
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;
}
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 one, final Status two) {
return new Status() {
void running(File file) {
one.running(file);
two.running(file);
}
void threw(Throwable t) {
one.threw(t);
two.threw(t);
}
void failed(String s) {
one.failed(s);
two.failed(s);
}
void exitCodesWere(int expected, int actual) {
one.exitCodesWere(expected, actual);
two.exitCodesWere(expected, actual);
}
void outputWas(String s) {
one.outputWas(s);
two.outputWas(s);
}
void timedOut() {
one.timedOut();
two.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)
{
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(), "shell.js"));
runFileIfExists(cx, global, new File(jsFile.getParentFile(), "shell.js"));
runFileIfExists(cx, global, jsFile);
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;
}
}
}
});
t.start();
t.join(parameters.getTimeoutMilliseconds());
synchronized(testState)
{
if(!testState.finished)
{
status.timedOut();
t.stop();
}
}
int exitCode = 0;
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 ");
if(expex != -1)
{
expectedExitCode = s.charAt(expex + "EXPECT EXIT ".length()) - '0';
}
}
status.exitCodesWere(expectedExitCode, exitCode);
if(failures != "")
{
status.failed(failures);
}
}
}

Просмотреть файл

@ -19,6 +19,8 @@
* 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
@ -60,22 +62,28 @@ 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.4 2006-11-10 15:27:38 gerv%gerv.net Exp $
* @version $Id: StandardTests.java,v 1.5 2007-01-24 22:14:59 inonit%inonit.com Exp $
*/
public class StandardTests extends TestSuite
{
public static TestSuite suite() throws Exception
{
TestSuite suite = new TestSuite("Standard JavaScript tests");
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);
File testDir = new File(path, "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");
@ -101,16 +109,12 @@ public class StandardTests extends TestSuite
private static void addSuites(TestSuite topLevel, File testDir, Properties excludes, int optimizationLevel)
{
File[] subdirs = testDir.listFiles(new DirectoryFilter());
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();
if(name.equals("CVS"))
{
continue;
}
TestSuite testSuite = new TestSuite(name);
addCategories(testSuite, subdir, name + "/", excludes, optimizationLevel);
topLevel.addTest(testSuite);
@ -119,16 +123,12 @@ public class StandardTests extends TestSuite
private static void addCategories(TestSuite suite, File suiteDir, String prefix, Properties excludes, int optimizationLevel)
{
File[] subdirs = suiteDir.listFiles(new DirectoryFilter());
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();
if(name.equals("CVS"))
{
continue;
}
TestSuite testCategory = new TestSuite(name);
addTests(testCategory, subdir, prefix + name + "/", excludes, optimizationLevel);
suite.addTest(testCategory);
@ -137,20 +137,46 @@ public class StandardTests extends TestSuite
private static void addTests(TestSuite suite, File suiteDir, String prefix, Properties excludes, int optimizationLevel)
{
File[] jsFiles = suiteDir.listFiles(new JsFilter());
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(name.equals("shell.js") || name.equals("browser.js") || excludes.containsKey(prefix + name))
if(excludes.containsKey(prefix + name))
{
continue;
}
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;
@ -168,133 +194,20 @@ public class StandardTests extends TestSuite
return 1;
}
private static class TestState
{
boolean finished;
Exception e;
}
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 Global global = new Global();
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream p = new PrintStream(out);
global.setOut(p);
global.setErr(p);
final ShellContextFactory shellContextFactory = new ShellContextFactory();
shellContextFactory.setOptimizationLevel(optimizationLevel);
final TestState testState = new TestState();
Thread t = new Thread(new Runnable()
{
public void run()
{
try
{
shellContextFactory.call(new ContextAction()
{
public Object run(Context cx)
{
global.init(cx);
runFileIfExists(cx, global, new File(jsFile.getParentFile().getParentFile(), "shell.js"));
runFileIfExists(cx, global, new File(jsFile.getParentFile(), "shell.js"));
runFileIfExists(cx, global, jsFile);
return null;
}
});
}
catch(Exception e)
{
synchronized(testState)
{
testState.e = e;
}
}
synchronized(testState)
{
testState.finished = true;
}
}
});
t.start();
t.join(60000);
boolean isNegativeTest = jsFile.getName().endsWith("-n.js");
synchronized(testState)
{
if(!testState.finished)
{
t.stop();
Assert.fail("Timed out");
}
if(testState.e != null)
{
if(isNegativeTest)
{
if(testState.e instanceof EvaluatorException)
{
// Expected to bomb
return;
}
}
throw testState.e;
}
}
if(isNegativeTest)
{
Assert.fail("Test was expected to produce a runtime error");
}
int exitCode = 0;
int expectedExitCode = 0;
p.flush();
System.out.print(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 ");
if(expex != -1)
{
expectedExitCode = s.charAt(expex + "EXPECT EXIT ".length()) - '0';
}
}
Assert.assertEquals("Unexpected exit code", expectedExitCode, exitCode);
if(failures != "")
{
Assert.fail(failures);
}
}
}
private static void runFileIfExists(Context cx, Scriptable global, File f)
{
if(f.isFile())
{
Main.processFile(cx, global, f.getPath());
}
}
private static class DirectoryFilter implements FileFilter
{
public boolean accept(File pathname)
{
return pathname.isDirectory();
}
}
private static class JsFilter implements FileFilter
{
public boolean accept(File pathname)
{
return pathname.getName().endsWith(".js");
final ShellContextFactory shellContextFactory = new ShellContextFactory();
shellContextFactory.setOptimizationLevel(optimizationLevel);
ShellTest.run(shellContextFactory, jsFile, new ShellTestParameters(), new JunitStatus());
}
}
}

Просмотреть файл