Improves junit-support.js. Starts to rewrite generator

This commit is contained in:
Alexey Andreev 2013-12-11 17:40:17 +04:00
parent 231c5a43ee
commit 03018a8f40
3 changed files with 189 additions and 185 deletions

View File

@ -1,9 +1,6 @@
package org.teavm.classlibgen;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.*;
import java.util.*;
import org.apache.commons.io.IOUtils;
import org.teavm.codegen.*;
@ -20,7 +17,7 @@ import org.teavm.optimization.ClassSetOptimizer;
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ClasslibTestGenerator {
private static PrintStream out;
private static File outputDir;
private static ClasspathClassHolderSource classSource;
private static Decompiler decompiler;
private static AliasProvider aliasProvider;
@ -34,11 +31,28 @@ public class ClasslibTestGenerator {
"java.lang.VMTests" };
public static void main(String[] args) throws IOException {
out = System.out;
if (args.length > 0) {
out = new PrintStream(new FileOutputStream(args[0]));
}
outputDir = new File(args[0]);
outputDir.mkdirs();
resourceToFile("org/teavm/javascript/runtime.js", "runtime.js");
resourceToFile("org/teavm/classlib/junit-support.js", "junit-support.js");
resourceToFile("org/teavm/classlib/junit.css", "junit.css");
classSource = new ClasspathClassHolderSource();
for (int i = 0; i < testClasses.length; ++i) {
testClasses[i] = "org.teavm.classlib." + testClasses[i];
}
for (String testClass : testClasses) {
ClassHolder classHolder = classSource.getClassHolder(testClass);
findTests(classHolder);
}
writer.append("runTests = function() {").newLine().indent();
writer.append("document.getElementById(\"start-button\").style.display = 'none';").newLine();
for (String testClass : testClasses) {
renderClassTest(classSource.getClassHolder(testClass));
}
writer.outdent().append("}").newLine();
}
private static void decompileClassesForTest(MethodReference methodRef, String targetName) throws IOException {
decompiler = new Decompiler(classSource);
aliasProvider = new MinifyingAliasProvider();
naming = new DefaultNamingStrategy(aliasProvider, classSource);
@ -47,41 +61,21 @@ public class ClasslibTestGenerator {
builder.setMinified(true);
writer = builder.build();
renderer = new Renderer(writer, classSource);
renderer.renderRuntime();
DependencyChecker dependencyChecker = new DependencyChecker(classSource);
for (int i = 0; i < testClasses.length; ++i) {
testClasses[i] = "org.teavm.classlib." + testClasses[i];
}
for (String testClass : testClasses) {
ClassHolder classHolder = classSource.getClassHolder(testClass);
findTests(classHolder);
MethodReference cons = new MethodReference(testClass, new MethodDescriptor("<init>", ValueType.VOID));
MethodReference cons = new MethodReference(methodRef.getClassName(),
new MethodDescriptor("<init>", ValueType.VOID));
dependencyChecker.addEntryPoint(cons);
}
for (MethodReference methodRef : testMethods) {
dependencyChecker.addEntryPoint(methodRef);
}
dependencyChecker.checkDependencies();
ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses();
ClassSetOptimizer optimizer = new ClassSetOptimizer();
optimizer.optimizeAll(classSet);
decompileClasses(classSet.getClassNames());
renderHead();
ClassLoader classLoader = ClasslibTestGenerator.class.getClassLoader();
try (InputStream input = classLoader.getResourceAsStream("org/teavm/classlib/junit-support.js")) {
out.println(IOUtils.toString(input));
}
try (InputStream input = classLoader.getResourceAsStream("org/teavm/javascript/runtime.js")) {
out.println(IOUtils.toString(input));
}
renderer.renderRuntime();
writer.append("runTests = function() {").newLine().indent();
writer.append("document.getElementById(\"start-button\").style.display = 'none';").newLine();
for (String testClass : testClasses) {
renderClassTest(classSource.getClassHolder(testClass));
decompileClasses(classSet.getClassNames());
try (Writer out = new OutputStreamWriter(new FileOutputStream(new File(outputDir, targetName)), "UTF-8")) {
out.write(writer.toString());
}
writer.outdent().append("}").newLine();
out.println(writer);
renderFoot();
}
private static void decompileClasses(Collection<String> classNames) {
@ -91,39 +85,6 @@ public class ClasslibTestGenerator {
}
}
private static void renderHead() {
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println(" <head>");
out.println(" <title>TeaVM JUnit tests</title>");
out.println(" <meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\"/>");
out.println(" <title>TeaVM JUnit tests</title>");
out.println(" <style type=\"text/css\">");
out.println(" table {");
out.println(" border-collapse: collapse;");
out.println(" border: 2px solid black;");
out.println(" margin: 2em 1em 2em 1em;");
out.println(" }");
out.println(" table td, table th {");
out.println(" border: 1px solid gray;");
out.println(" padding: 0.1em 0.5em 0.2em 0.5em;");
out.println(" }");
out.println(" table thead, table tfoot {");
out.println(" border: 2px solid black;");
out.println(" }");
out.println(" </style>");
out.println(" </head>");
out.println(" <body>");
out.println(" <script type=\"text/javascript\">");
}
private static void renderFoot() {
out.println(" </script>");
out.println(" <button id=\"start-button\" onclick=\"runTests()\">Run tests</button>");
out.println(" </body>");
out.println("</html>");
}
private static void renderClassTest(ClassHolder cls) {
List<MethodReference> methods = groupedMethods.get(cls.getName());
writer.append("testClass(\"" + cls.getName() + "\", function() {").newLine().indent();
@ -159,4 +120,12 @@ public class ClasslibTestGenerator {
}
}
}
private static void resourceToFile(String resource, String fileName) throws IOException {
try (InputStream input = ClasslibTestGenerator.class.getClassLoader().getResourceAsStream(resource)) {
try (OutputStream output = new FileOutputStream(new File(outputDir, fileName))) {
IOUtils.copy(input, output);
}
}
}
}

View File

@ -1,114 +1,135 @@
currentTestReportBody = null;
currentTimeSpent = 0;
totalTimeSpent = 0;
currentMethodCount = 0;
currentStatusCell = null;
currentExceptionCell = null;
currentTimeCell = null;
currentStartTime = 0;
currentExpectedExceptions = [];
currentFrame = null;
window.addEventListener("message", function(event) {
endTime = new Date().getTime();
var message = JSON.parse(event.data);
if (message.status == "ok") {
if (currentExpectedExceptions.length > 0) {
currentStatusCell.appendChild(document.createTextNode("expected exception not thrown"));
currentStatusCell.style.color = 'yellow';
} else {
currentStatusCell.appendChild(document.createTextNode("ok"));
currentStatusCell.style.color = 'green';
}
} else if (message.status == "exception") {
if (isExpectedException(e)) {
currentStatusCell.appendChild(document.createTextNode("ok"));
currentStatusCell.style.color = 'green';
} else {
currentStatusCell.appendChild(document.createTextNode("unexpected exception"));
var exceptionText = document.createElement("pre");
exceptionText.appendChild(document.createTextNode(e.stack));
currentExceptionCell.appendChild(exceptionText);
currentStatusCell.style.color = 'red';
}
}
++currentMethodCount;
var timeSpent = (endTime - currentStartTime) / 1000;
currentTimeSpent += timeSpent;
currentTimeCell.appendChild(document.createTextNode(timeSpent.toFixed(3)));
document.body.removeChild(currentFrame);
}, false);
runTestCase = function(methodName, path, expectedExceptions) {
var row = document.createElement("tr");
currentTestReportBody.appendChild(row);
var nameCell = document.createElement("td");
row.appendChild(nameCell);
nameCell.appendChild(document.createTextNode(methodName));
currentStatusCell = document.createElement("td");
row.appendChild(currentStatusCell);
currentExceptionCell = document.createElement("td");
row.appendChild(currentExceptionCell);
currentTimeCell = document.createElement("td");
row.appendChild(currentTimeCell);
currentStartTime = new Date().getTime();
currentExpectedExceptions = expectedExceptions;
var frame = document.createElement("iframe");
cirremtFrame = frame;
document.body.appendChild(frame);
var frameDoc = frame.contentWindow.document;
var frameScript = frameDoc.createElement("script");
frameScript.src = path;
frameDoc.body.appendChild(frameScript);
endTime = new Date().getTime();
if (expectedExceptions.length > 0) {
statusCell.appendChild(document.createTextNode("expected exception not thrown"));
statusCell.style.color = 'yellow';
} else {
statusCell.appendChild(document.createTextNode("ok"));
statusCell.style.color = 'green';
}
} catch (e) {
endTime = new Date().getTime();
if (isExpectedException(e, expectedExceptions)) {
statusCell.appendChild(document.createTextNode("ok"));
statusCell.style.color = 'green';
} else {
statusCell.appendChild(document.createTextNode("unexpected exception"));
var exceptionText = document.createElement("pre");
exceptionText.appendChild(document.createTextNode(e.stack));
exceptionCell.appendChild(exceptionText);
statusCell.style.color = 'red';
}
}
++currentMethodCount;
var timeSpent = (endTime - startTime) / 1000;
currentTimeSpent += timeSpent;
timeCell.appendChild(document.createTextNode(timeSpent.toFixed(3)));
JUnitServer = function(container) {
this.container = container;
this.timeSpent = 0;
this.totalTimeSpent = 0;
this.methodCount = 0;
this.statusCell = null;
this.exceptionCell = null;
this.timeCell = null;
this.startTime = 0;
this.expectedExceptions = [];
this.table = null;
this.tableBody = null;
this.frame = null;
}
isExpectedException = function(e) {
if (e.javaException !== undefined) {
for (var i = 0; i < currentExpectedExceptions.length; ++i) {
if (currentExpectedExceptions[i] === e.javaException) {
return true;
JUnitServer.prototype = new Object();
JUnitServer.prototype.handleEvent = function(message, callback) {
endTime = new Date().getTime();
if (message.status === "ok") {
if (this.expectedExceptions.length > 0) {
this.statusCell.appendChild(document.createTextNode("expected exception not thrown"));
this.statusCell.style.color = 'yellow';
} else {
this.statusCell.appendChild(document.createTextNode("ok"));
this.statusCell.style.color = 'green';
}
} else if (message.status === "exception") {
if (message.exception && this.isExpectedException(message.exception)) {
this.statusCell.appendChild(document.createTextNode("ok"));
this.statusCell.style.color = 'green';
} else {
this.statusCell.appendChild(document.createTextNode("unexpected exception"));
var exceptionText = document.createElement("pre");
exceptionText.appendChild(document.createTextNode(message.stack));
this.exceptionCell.appendChild(exceptionText);
this.statusCell.style.color = 'red';
}
}
++this.methodCount;
var timeSpent = (endTime - this.startTime) / 1000;
this.timeSpent += timeSpent;
this.timeCell.appendChild(document.createTextNode(timeSpent.toFixed(3)));
document.body.removeChild(this.frame);
self.frame = null;
callback();
}
JUnitServer.prototype.isExpectedException = function(ex) {
for (var i = 0; i < this.expectedExceptions.length; ++i) {
if (this.expectedExceptions[i] === ex) {
return true;
}
}
return false;
}
testClass = function(className, classTests) {
currentTimeSpent = 0;
currentMethodCount = 0;
var table = document.createElement("table");
document.body.appendChild(table);
JUnitServer.prototype.runTestCase = function(methodName, path, expectedExceptions, callback) {
this.createRow(methodName);
this.startTime = new Date().getTime();
this.expectedExceptions = expectedExceptions;
var self = this;
this.loadCode(path, function() {
messageHandler = function(event) {
window.removeEventListener("message", messageHandler);
self.handleEvent(JSON.parse(event.data), callback);
};
window.addEventListener("message", messageHandler);
self.frame.contentWindow.postMessage("runTest", "*");
});
}
JUnitServer.prototype.createRow = function(methodName) {
var row = document.createElement("tr");
this.tableBody.appendChild(row);
var nameCell = document.createElement("td");
row.appendChild(nameCell);
nameCell.appendChild(document.createTextNode(methodName));
this.statusCell = document.createElement("td");
row.appendChild(this.statusCell);
this.exceptionCell = document.createElement("td");
row.appendChild(this.exceptionCell);
this.timeCell = document.createElement("td");
row.appendChild(this.timeCell);
}
JUnitServer.prototype.loadCode = function(path, callback) {
this.frame = document.createElement("iframe");
document.body.appendChild(this.frame);
var frameDoc = this.frame.contentWindow.document;
var self = this;
this.loadScript("junit-support.js", function() {
self.loadScript("runtime.js", function() {
self.loadScript(path, callback);
});
});
}
JUnitServer.prototype.loadScript = function(name, callback) {
var doc = this.frame.contentWindow.document;
var script = doc.createElement("script");
script.src = name;
doc.body.appendChild(script);
script.onload = function() {
callback();
}
}
JUnitServer.prototype.runTest = function(test, callback) {
this.timeSpent = 0;
this.methodCount = 0;
this.createTable(test.name);
this.runMethodFromList(test.methods, 0, function() {
callback();
});
}
JUnitServer.prototype.runMethodFromList = function(methods, index, callback) {
if (index < methods.length) {
var method = methods[index];
var self = this;
this.runTestCase(method.name, method.script, method.expected, function() {
self.runMethodFromList(methods, index + 1, callback);
});
} else {
callback();
}
}
JUnitServer.prototype.createTable = function(name) {
this.table = document.createElement("table");
this.container.appendChild(this.table);
var caption = document.createElement("caption");
table.appendChild(caption);
caption.appendChild(document.createTextNode(className));
this.table.appendChild(caption);
this.createHeader();
caption.appendChild(document.createTextNode(name));
this.tableBody = document.createElement("tbody");
this.table.appendChild(this.tableBody);
}
JUnitServer.prototype.createHeader = function() {
var head = document.createElement("thead");
table.appendChild(head);
this.table.appendChild(head);
var headRow = document.createElement("tr");
head.appendChild(headRow);
var headCell = document.createElement("th");
@ -123,14 +144,11 @@ testClass = function(className, classTests) {
headCell = document.createElement("th");
headRow.appendChild(headCell);
headCell.appendChild(document.createTextNode("Time spent, s"));
var tbody = document.createElement("tbody");
table.appendChild(tbody);
currentTestReportBody = tbody;
classTests();
this.table.appendChild(head);
}
JUnitServer.prototype.createFooter = function() {
var foot = document.createElement("tfoot");
table.appendChild(foot);
this.table.appendChild(foot);
var footRow = document.createElement("tr");
foot.appendChild(footRow);
var footName = document.createElement("td");
@ -138,14 +156,30 @@ testClass = function(className, classTests) {
footName.appendChild(document.createTextNode("---"));
var footMethods = document.createElement("td");
footRow.appendChild(footMethods);
footMethods.appendChild(document.createTextNode(currentMethodCount));
footMethods.appendChild(document.createTextNode(this.methodCount));
var footSpace = document.createElement("td");
footRow.appendChild(footSpace);
footSpace.appendChild(document.createTextNode("---"));
var footTime = document.createElement("td");
footRow.appendChild(footTime);
footTime.appendChild(document.createTextNode(currentTimeSpent.toFixed(3)));
totalTimeSpent += currentTimeSpent;
currentTestReportBody = null;
footTime.appendChild(document.createTextNode(this.timeSpent.toFixed(3)));
}
JUnitClient = {};
JUnitClient.run = function(runner) {
var handler = window.addEventListener("message", function() {
window.removeEventListener("message", handler);
var message = {};
try {
runner();
message.status = "ok";
} catch (e) {
message.status = "exception";
if (e.$javaException && e.$javaException.$class && e.$javaException.$class.$meta) {
message.exception = e.$javaException.$class.$meta.name;
}
message.stack = e.stack;
}
window.parent.postMessage(JSON.stringify(message), "*");
});
}

View File

@ -11,6 +11,7 @@
<script type="text/javascript">
function runTests() {
document.getElementById("start-button").style.display = "none";
doRunTests();
}
</script>
<button id="start-button" onclick="runTests()">Run tests</button>