зеркало из https://github.com/mozilla/pjs.git
Test driver now also emits results in XML format for possible postprocessing (includes things like performance data, complete output for all tests, etc.)
This commit is contained in:
Родитель
0b72084958
Коммит
c8a4947b56
|
@ -354,6 +354,63 @@ public class JsDriver {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class XmlStatus extends ShellTest.Status {
|
||||
private String path;
|
||||
|
||||
private Element target;
|
||||
private Date start;
|
||||
|
||||
XmlStatus(String path, Element root) {
|
||||
this.path = path;
|
||||
this.target = root.getOwnerDocument().createElement("test");
|
||||
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));
|
||||
}
|
||||
|
||||
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");
|
||||
failed.setTextContent(s);
|
||||
}
|
||||
|
||||
void outputWas(String message) {
|
||||
finish();
|
||||
Element output = createElement(target, "output");
|
||||
output.setTextContent(message);
|
||||
}
|
||||
|
||||
void threw(Throwable t) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private static class Results {
|
||||
private ShellContextFactory factory;
|
||||
|
@ -363,10 +420,26 @@ public class JsDriver {
|
|||
|
||||
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();
|
||||
|
@ -382,12 +455,31 @@ public class JsDriver {
|
|||
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;
|
||||
|
||||
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");
|
||||
}
|
||||
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 start() {
|
||||
this.html = getTemplate();
|
||||
this.failureHtml = getElementById(html.getDocumentElement(), "failureDetails.prototype");
|
||||
if (this.failureHtml == null) {
|
||||
|
@ -402,28 +494,28 @@ public class JsDriver {
|
|||
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("timeout", String.valueOf(arguments.getTimeout()));
|
||||
} catch (javax.xml.parsers.ParserConfigurationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
this.start = new Date();
|
||||
}
|
||||
|
||||
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) {
|
||||
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));
|
||||
ShellTest.Status status = ShellTest.Status.compose(cStatus, hStatus);
|
||||
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) {
|
||||
|
@ -435,12 +527,13 @@ public class JsDriver {
|
|||
}
|
||||
hStatus.finish();
|
||||
}
|
||||
|
||||
|
||||
private void set(Document document, String id, String value) {
|
||||
getElementById(document.getDocumentElement(), id).setTextContent(value);
|
||||
}
|
||||
|
||||
void finish(Date start, Date end) {
|
||||
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()));
|
||||
|
@ -457,7 +550,8 @@ public class JsDriver {
|
|||
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);
|
||||
write(html, false);
|
||||
write(xml, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -494,18 +588,13 @@ public class JsDriver {
|
|||
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();
|
||||
Results results = new Results(factory, arguments, arguments.trace());
|
||||
|
||||
results.start();
|
||||
for (int i=0; i<all.length; i++) {
|
||||
results.run(all[i].getPath(), all[i].getFile(), new ShellTestParameters(arguments.getTimeout()));
|
||||
results.run(all[i], new ShellTestParameters(arguments.getTimeout()));
|
||||
}
|
||||
Date end = new Date();
|
||||
results.finish(start, end);
|
||||
results.finish();
|
||||
}
|
||||
|
||||
public static void main(Arguments arguments) throws Throwable {
|
||||
|
|
|
@ -1,333 +0,0 @@
|
|||
/* ***** 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;
|
||||
|
||||
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;
|
||||
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 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);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
t.join(parameters.getTimeoutMilliseconds());
|
||||
synchronized(testState)
|
||||
{
|
||||
if(!testState.finished)
|
||||
{
|
||||
status.timedOut();
|
||||
t.stop();
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче