mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-31 12:24:10 -08:00
Add decoding of stack trace in JUnit adapter
This commit is contained in:
parent
6d2815bc5c
commit
d50189ea3a
|
@ -248,6 +248,9 @@ function $rt_exception(ex) {
|
||||||
var err = ex.$jsException;
|
var err = ex.$jsException;
|
||||||
if (!err) {
|
if (!err) {
|
||||||
err = new Error("Java exception thrown");
|
err = new Error("Java exception thrown");
|
||||||
|
if (typeof Error.captureStackTrace === "function") {
|
||||||
|
Error.captureStackTrace(err);
|
||||||
|
}
|
||||||
err.$javaException = ex;
|
err.$javaException = ex;
|
||||||
ex.$jsException = err;
|
ex.$jsException = err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import net.sourceforge.htmlunit.corejs.javascript.Function;
|
import net.sourceforge.htmlunit.corejs.javascript.Function;
|
||||||
import net.sourceforge.htmlunit.corejs.javascript.NativeJavaObject;
|
import net.sourceforge.htmlunit.corejs.javascript.NativeJavaObject;
|
||||||
|
import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
class HtmlUnitRunStrategy implements TestRunStrategy {
|
class HtmlUnitRunStrategy implements TestRunStrategy {
|
||||||
|
@ -65,7 +66,9 @@ class HtmlUnitRunStrategy implements TestRunStrategy {
|
||||||
.getJavaScriptResult();
|
.getJavaScriptResult();
|
||||||
Object[] args = new Object[] { new NativeJavaObject(function, asyncResult, AsyncResult.class) };
|
Object[] args = new Object[] { new NativeJavaObject(function, asyncResult, AsyncResult.class) };
|
||||||
page.get().executeJavaScriptFunctionIfPossible(function, function, args, page.get());
|
page.get().executeJavaScriptFunctionIfPossible(function, function, args, page.get());
|
||||||
JavaScriptResultParser.parseResult((String) asyncResult.getResult(), run.getCallback());
|
|
||||||
|
RhinoResultParser.parseResult((Scriptable) asyncResult.getResult(), run.getCallback(),
|
||||||
|
new File(run.getBaseDirectory(), run.getFileName() + ".teavmdbg"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanUp() {
|
private void cleanUp() {
|
||||||
|
|
148
tools/junit/src/main/java/org/teavm/junit/RhinoResultParser.java
Normal file
148
tools/junit/src/main/java/org/teavm/junit/RhinoResultParser.java
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.junit;
|
||||||
|
|
||||||
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
|
||||||
|
import org.teavm.debugging.information.DebugInformation;
|
||||||
|
import org.teavm.debugging.information.SourceLocation;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
|
final class RhinoResultParser {
|
||||||
|
private static Pattern pattern = Pattern.compile("(([A-Za-z_$]+)\\(\\))?@.+:([0-9]+)");
|
||||||
|
private static Pattern lineSeparator = Pattern.compile("\\r\\n|\r|\n");
|
||||||
|
|
||||||
|
private RhinoResultParser() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parseResult(Scriptable result, TestRunCallback callback, File debugFile) {
|
||||||
|
if (result == null) {
|
||||||
|
callback.complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String status = result.get("status", result).toString();
|
||||||
|
switch (status) {
|
||||||
|
case "ok":
|
||||||
|
callback.complete();
|
||||||
|
break;
|
||||||
|
case "exception": {
|
||||||
|
DebugInformation debugInformation = getDebugInformation(debugFile);
|
||||||
|
|
||||||
|
String className = String.valueOf(result.get("className", result));
|
||||||
|
String decodedName = debugInformation.getClassNameByJsName(className);
|
||||||
|
if (decodedName != null) {
|
||||||
|
className = decodedName;
|
||||||
|
}
|
||||||
|
String message = String.valueOf(result.get("message", result));
|
||||||
|
|
||||||
|
String stack = result.get("stack", result).toString();
|
||||||
|
String[] script = getScript(new File(debugFile.getParentFile(),
|
||||||
|
debugFile.getName().substring(0, debugFile.getName().length() - 9)));
|
||||||
|
stack = decodeStack(stack, script, debugInformation);
|
||||||
|
|
||||||
|
if (className.equals("java.lang.AssertionError")) {
|
||||||
|
callback.error(new AssertionError(message + stack));
|
||||||
|
} else {
|
||||||
|
callback.error(new RuntimeException(className + ": " + message + stack));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String decodeStack(String stack, String[] script, DebugInformation debugInformation) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (String line : lineSeparator.split(stack)) {
|
||||||
|
sb.append("\n\tat ");
|
||||||
|
Matcher matcher = pattern.matcher(line);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
sb.append(line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String functionName = matcher.group(2);
|
||||||
|
int lineNumber = Integer.parseInt(matcher.group(3)) - 1;
|
||||||
|
|
||||||
|
String scriptLine = script[lineNumber];
|
||||||
|
int column = firstNonSpace(scriptLine);
|
||||||
|
MethodReference method = debugInformation.getMethodAt(lineNumber, column);
|
||||||
|
|
||||||
|
if (method != null) {
|
||||||
|
sb.append(method.getClassName()).append(".").append(method.getName());
|
||||||
|
} else {
|
||||||
|
sb.append(functionName != null ? functionName : "<unknown_function>");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append("(");
|
||||||
|
SourceLocation location = debugInformation.getSourceLocation(lineNumber, column);
|
||||||
|
if (location != null && location.getFileName() != null) {
|
||||||
|
String fileName = location.getFileName();
|
||||||
|
fileName = fileName.substring(fileName.lastIndexOf('/') + 1);
|
||||||
|
sb.append(fileName).append(":").append(location.getLine());
|
||||||
|
} else {
|
||||||
|
sb.append("test.js:").append(lineNumber + 1);
|
||||||
|
}
|
||||||
|
sb.append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DebugInformation getDebugInformation(File debugFile) {
|
||||||
|
try (InputStream input = new FileInputStream(debugFile)) {
|
||||||
|
return DebugInformation.read(input);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String[] getScript(File file) {
|
||||||
|
List<String> lines = new ArrayList<>();
|
||||||
|
try (InputStream input = new FileInputStream(file);
|
||||||
|
Reader reader = new InputStreamReader(input, UTF_8);
|
||||||
|
BufferedReader bufferedReader = new BufferedReader(reader)) {
|
||||||
|
while (true) {
|
||||||
|
String line = bufferedReader.readLine();
|
||||||
|
if (line == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lines.add(line);
|
||||||
|
}
|
||||||
|
return lines.toArray(new String[0]);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int firstNonSpace(String s) {
|
||||||
|
int i = 0;
|
||||||
|
while (i < s.length() && s.charAt(i) == ' ') {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
|
@ -571,6 +571,7 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
||||||
CompilePostProcessor postBuild = (vm, file) -> {
|
CompilePostProcessor postBuild = (vm, file) -> {
|
||||||
DebugInformation debugInfo = debugEmitter.getDebugInformation();
|
DebugInformation debugInfo = debugEmitter.getDebugInformation();
|
||||||
File sourceMapsFile = new File(file.getPath() + ".map");
|
File sourceMapsFile = new File(file.getPath() + ".map");
|
||||||
|
File debugFile = new File(file.getPath() + ".teavmdbg");
|
||||||
try {
|
try {
|
||||||
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file, true), UTF_8)) {
|
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file, true), UTF_8)) {
|
||||||
writer.write("\n//# sourceMappingURL=");
|
writer.write("\n//# sourceMappingURL=");
|
||||||
|
@ -578,7 +579,11 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
||||||
}
|
}
|
||||||
|
|
||||||
try (Writer sourceMapsOut = new OutputStreamWriter(new FileOutputStream(sourceMapsFile), UTF_8)) {
|
try (Writer sourceMapsOut = new OutputStreamWriter(new FileOutputStream(sourceMapsFile), UTF_8)) {
|
||||||
debugInfo.writeAsSourceMaps(sourceMapsOut, "src", file.getPath());
|
debugInfo.writeAsSourceMaps(sourceMapsOut, "", file.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
try (OutputStream out = new FileOutputStream(debugFile)) {
|
||||||
|
debugInfo.write(out);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
|
|
@ -6,17 +6,19 @@ function runMain(callback) {
|
||||||
} else {
|
} else {
|
||||||
message.status = "ok";
|
message.status = "ok";
|
||||||
}
|
}
|
||||||
callback.complete(JSON.stringify(message));
|
callback.complete(message);
|
||||||
});
|
});
|
||||||
|
|
||||||
function makeErrorMessage(message, e) {
|
function makeErrorMessage(message, e) {
|
||||||
message.status = "exception";
|
message.status = "exception";
|
||||||
var stack = "";
|
if (e.$javaException) {
|
||||||
if (e.$javaException && e.$javaException.constructor.$meta) {
|
message.className = e.$javaException.constructor.name;
|
||||||
stack = e.$javaException.constructor.$meta.name + ": ";
|
message.message = e.$javaException.getMessage();
|
||||||
stack += e.$javaException.getMessage() || "";
|
} else {
|
||||||
stack += "\n";
|
message.className = Object.getPrototypeOf(e).name;
|
||||||
|
message.message = e.message;
|
||||||
}
|
}
|
||||||
message.stack = stack + e.stack;
|
message.exception = e;
|
||||||
|
message.stack = e.stack;
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user