Alters JUnit plugin. Now it doesn't stop when dependency problems found,

but puts warning into log and into execution report of test
This commit is contained in:
konsoletyper 2014-02-19 11:15:22 +04:00
parent be89d16e88
commit 2c08f75b0a
6 changed files with 99 additions and 9 deletions

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.dependency; package org.teavm.dependency;
import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
@ -375,9 +376,23 @@ public class DependencyChecker implements DependencyInfo {
} }
public void checkForMissingItems() { public void checkForMissingItems() {
if (missingClasses.isEmpty() && missingMethods.isEmpty() && missingFields.isEmpty()) { if (!hasMissingItems()) {
return; return;
} }
StringBuilder sb = new StringBuilder();
try {
showMissingItems(sb);
} catch (IOException e) {
throw new AssertionError("StringBuilder should not throw IOException");
}
throw new IllegalStateException(sb.toString());
}
public boolean hasMissingItems() {
return !missingClasses.isEmpty() || !missingMethods.isEmpty() || !missingFields.isEmpty();
}
public void showMissingItems(Appendable sb) throws IOException {
List<String> items = new ArrayList<>(); List<String> items = new ArrayList<>();
Map<String, DependencyStack> stackMap = new HashMap<>(); Map<String, DependencyStack> stackMap = new HashMap<>();
for (String cls : missingClasses.keySet()) { for (String cls : missingClasses.keySet()) {
@ -393,7 +408,6 @@ public class DependencyChecker implements DependencyInfo {
items.add(field.toString()); items.add(field.toString());
} }
Collections.sort(items); Collections.sort(items);
StringBuilder sb = new StringBuilder();
sb.append("Can't compile due to the following items missing:\n"); sb.append("Can't compile due to the following items missing:\n");
for (String item : items) { for (String item : items) {
sb.append(" ").append(item).append("\n"); sb.append(" ").append(item).append("\n");
@ -407,6 +421,5 @@ public class DependencyChecker implements DependencyInfo {
} }
sb.append('\n'); sb.append('\n');
} }
throw new IllegalStateException(sb.toString());
} }
} }

View File

@ -112,6 +112,18 @@ public class JavascriptBuilder implements JavascriptBuilderHost {
dependencyChecker.startListeners(); dependencyChecker.startListeners();
} }
public boolean hasMissingItems() {
return dependencyChecker.hasMissingItems();
}
public void showMissingItems(Appendable target) throws IOException {
dependencyChecker.showMissingItems(target);
}
public void checkForMissingItems() {
dependencyChecker.checkForMissingItems();
}
public void build(Appendable writer, JavascriptBuildTarget target) throws RenderingException { public void build(Appendable writer, JavascriptBuildTarget target) throws RenderingException {
AliasProvider aliasProvider = minifying ? new MinifyingAliasProvider() : new DefaultAliasProvider(); AliasProvider aliasProvider = minifying ? new MinifyingAliasProvider() : new DefaultAliasProvider();
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, classSource); DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, classSource);
@ -124,7 +136,9 @@ public class JavascriptBuilder implements JavascriptBuilderHost {
dependencyChecker.linkMethod(new MethodReference("java.lang.String", new MethodDescriptor("<init>", dependencyChecker.linkMethod(new MethodReference("java.lang.String", new MethodDescriptor("<init>",
ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), DependencyStack.ROOT).use(); ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), DependencyStack.ROOT).use();
executor.complete(); executor.complete();
dependencyChecker.checkForMissingItems(); if (hasMissingItems()) {
return;
}
ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses(classSource); ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses(classSource);
Decompiler decompiler = new Decompiler(classSet, classLoader, executor); Decompiler decompiler = new Decompiler(classSet, classLoader, executor);
devirtualize(classSet, dependencyChecker); devirtualize(classSet, dependencyChecker);

View File

@ -91,6 +91,9 @@ public class JavaScriptBodyDependency implements DependencyListener {
private static MethodReader findMethod(ClassReaderSource classSource, String clsName, MethodDescriptor desc) { private static MethodReader findMethod(ClassReaderSource classSource, String clsName, MethodDescriptor desc) {
while (clsName != null) { while (clsName != null) {
ClassReader cls = classSource.get(clsName); ClassReader cls = classSource.get(clsName);
if (cls == null) {
return null;
}
for (MethodReader method : cls.getMethods()) { for (MethodReader method : cls.getMethods()) {
if (method.getName().equals(desc.getName()) && sameParams(method.getDescriptor(), desc)) { if (method.getName().equals(desc.getName()) && sameParams(method.getDescriptor(), desc)) {
return method; return method;
@ -121,7 +124,7 @@ public class JavaScriptBodyDependency implements DependencyListener {
} }
@Override protected CharSequence callMethod(String ident, String fqn, String method, String params) { @Override protected CharSequence callMethod(String ident, String fqn, String method, String params) {
MethodDescriptor desc = MethodDescriptor.parse(method + params + "V"); MethodDescriptor desc = MethodDescriptor.parse(method + params + "V");
MethodReader reader = findMethod(dependencyChecker.getClassSource(), params, desc); MethodReader reader = findMethod(dependencyChecker.getClassSource(), fqn, desc);
MethodReference ref = reader != null ? reader.getReference() : new MethodReference(fqn, desc); MethodReference ref = reader != null ? reader.getReference() : new MethodReference(fqn, desc);
MethodDependency methodDep = dependencyChecker.linkMethod(ref, caller.getStack()); MethodDependency methodDep = dependencyChecker.linkMethod(ref, caller.getStack());
if (!methodDep.isMissing()) { if (!methodDep.isMissing()) {
@ -170,7 +173,7 @@ public class JavaScriptBodyDependency implements DependencyListener {
if (subtype == null) { if (subtype == null) {
return false; return false;
} }
if (isAssignableFrom(supertype, subtype.getParent())) { if (subtype.getParent() != null && isAssignableFrom(supertype, subtype.getParent())) {
return true; return true;
} }
for (String iface : subtype.getInterfaces()) { for (String iface : subtype.getInterfaces()) {

View File

@ -245,11 +245,63 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo {
builder.entryPoint("runTest", methodRef).withValue(0, cons.getClassName()); builder.entryPoint("runTest", methodRef).withValue(0, cons.getClassName());
builder.exportType("TestClass", cons.getClassName()); builder.exportType("TestClass", cons.getClassName());
builder.build(innerWriter, new DirectoryBuildTarget(outputDir)); builder.build(innerWriter, new DirectoryBuildTarget(outputDir));
if (!builder.hasMissingItems()) {
innerWriter.append("\n"); innerWriter.append("\n");
innerWriter.append("\nJUnitClient.run();"); innerWriter.append("\nJUnitClient.run();");
innerWriter.close(); innerWriter.close();
} else {
innerWriter.append("JUnitClient.reportError(\n");
StringBuilder sb = new StringBuilder();
builder.showMissingItems(sb);
escapeStringLiteral(sb.toString(), innerWriter);
innerWriter.append(");");
getLog().warn("Error building test " + methodRef);
getLog().warn(sb);
} }
} }
}
private void escapeStringLiteral(String text, Writer writer) throws IOException {
int index = 0;
while (true) {
int next = text.indexOf('\n', index);
if (next < 0) {
break;
}
escapeString(text.substring(index, next + 1), writer);
writer.append(" +\n");
index = next + 1;
}
escapeString(text.substring(index), writer);
}
private void escapeString(String string, Writer writer) throws IOException {
writer.append('\"');
for (int i = 0; i < string.length(); ++i) {
char c = string.charAt(i);
switch (c) {
case '"':
writer.append("\\\"");
break;
case '\\':
writer.append("\\\\");
break;
case '\n':
writer.append("\\n");
break;
case '\r':
writer.append("\\r");
break;
case '\t':
writer.append("\\t");
break;
default:
writer.append(c);
break;
}
}
writer.append('\"');
}
private void findTestClasses(ClassLoader classLoader, File folder, String prefix) { private void findTestClasses(ClassLoader classLoader, File folder, String prefix) {
Class<? extends Annotation> testAnnot; Class<? extends Annotation> testAnnot;

View File

@ -140,6 +140,7 @@ public class BuildJavascriptMojo extends AbstractMojo {
.withValue(1, "java.lang.String"); .withValue(1, "java.lang.String");
targetDirectory.mkdirs(); targetDirectory.mkdirs();
builder.build(targetDirectory, targetFileName); builder.build(targetDirectory, targetFileName);
builder.checkForMissingItems();
log.info("JavaScript file successfully built"); log.info("JavaScript file successfully built");
if (!runtimeSuppressed) { if (!runtimeSuppressed) {
resourceToFile("org/teavm/javascript/runtime.js", "runtime.js"); resourceToFile("org/teavm/javascript/runtime.js", "runtime.js");

View File

@ -216,3 +216,10 @@ JUnitClient.run = function() {
window.parent.postMessage(JSON.stringify(message), "*"); window.parent.postMessage(JSON.stringify(message), "*");
}); });
} }
JUnitClient.reportError = function(error) {
var handler = window.addEventListener("message", function() {
window.removeEventListener("message", handler);
var message = { status : "exception", stack : error };
window.parent.postMessage(JSON.stringify(message), "*");
});
}