mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Simplify test runner, remove parallel run, remove HtmlUnit runner, fix Wasm tests
This commit is contained in:
parent
a3eb5f635f
commit
47973face1
|
@ -23,10 +23,10 @@ public class WasmSupport {
|
|||
private WasmSupport() {
|
||||
}
|
||||
|
||||
@Import(name = "putwcharsOut", module = "teavm")
|
||||
@Import(name = "putwcharsErr", module = "teavm")
|
||||
public static native void putCharsStderr(Address address, int count);
|
||||
|
||||
@Import(name = "putwcharsErr", module = "teavm")
|
||||
@Import(name = "putwcharsOut", module = "teavm")
|
||||
public static native void putCharsStdout(Address address, int count);
|
||||
|
||||
public static long currentTimeMillis() {
|
||||
|
|
|
@ -213,7 +213,12 @@ TeaVM.wasm = function() {
|
|||
|
||||
controller.resolve = resolve;
|
||||
controller.reject = reject;
|
||||
try {
|
||||
wrapExport(teavm.instance.exports.start, teavm.instance)(javaArgs);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
return;
|
||||
}
|
||||
process(controller);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ dependencies {
|
|||
|
||||
tasks.test {
|
||||
systemProperty("teavm.junit.target", layout.buildDirectory.dir("teavm-tests").get().asFile.absolutePath)
|
||||
systemProperty("teavm.junit.threads", "1")
|
||||
val browser = providers.gradleProperty("teavm.tests.browser").orElse("browser-chrome").get()
|
||||
|
||||
systemProperty("teavm.junit.js", providers.gradleProperty("teavm.tests.js").orElse("true").get())
|
||||
|
|
|
@ -33,8 +33,6 @@ dependencies {
|
|||
|
||||
implementation(project(":core"))
|
||||
implementation(project(":tools:core"))
|
||||
implementation(libs.rhino)
|
||||
implementation(libs.htmlunit)
|
||||
implementation(libs.jackson.annotations)
|
||||
implementation(libs.jackson.databind)
|
||||
implementation(libs.javax.servlet)
|
||||
|
|
|
@ -114,34 +114,24 @@ class BrowserRunStrategy implements TestRunStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeThread() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterThread() {
|
||||
}
|
||||
|
||||
static class CallbackWrapper implements TestRunCallback {
|
||||
private final CountDownLatch latch;
|
||||
private final TestRun run;
|
||||
volatile Throwable error;
|
||||
volatile boolean shouldRepeat;
|
||||
|
||||
CallbackWrapper(CountDownLatch latch, TestRun run) {
|
||||
CallbackWrapper(CountDownLatch latch) {
|
||||
this.latch = latch;
|
||||
this.run = run;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete() {
|
||||
latch.countDown();
|
||||
run.getCallback().complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Throwable e) {
|
||||
error = e;
|
||||
latch.countDown();
|
||||
run.getCallback().error(e);
|
||||
}
|
||||
|
||||
void repeat() {
|
||||
|
@ -164,14 +154,14 @@ class BrowserRunStrategy implements TestRunStrategy {
|
|||
ws = wsSessionQueue.poll(1, TimeUnit.SECONDS);
|
||||
} while (ws == null || !ws.isOpen());
|
||||
} catch (InterruptedException e) {
|
||||
run.getCallback().error(e);
|
||||
Thread.currentThread().interrupt();
|
||||
return true;
|
||||
}
|
||||
|
||||
int id = idGenerator.incrementAndGet();
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
var latch = new CountDownLatch(1);
|
||||
|
||||
CallbackWrapper callbackWrapper = new CallbackWrapper(latch, run);
|
||||
CallbackWrapper callbackWrapper = new CallbackWrapper(latch);
|
||||
awaitingRuns.put(id, callbackWrapper);
|
||||
|
||||
JsonNodeFactory nf = objectMapper.getNodeFactory();
|
||||
|
@ -215,6 +205,15 @@ class BrowserRunStrategy implements TestRunStrategy {
|
|||
wsSessionQueue.offer(ws);
|
||||
}
|
||||
|
||||
if (callbackWrapper.error != null) {
|
||||
var err = callbackWrapper.error;
|
||||
if (err instanceof RuntimeException) {
|
||||
throw (RuntimeException) err;
|
||||
} else {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
return !callbackWrapper.shouldRepeat;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,22 +33,6 @@ class CRunStrategy implements TestRunStrategy {
|
|||
this.compilerCommand = compilerCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeAll() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAll() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeThread() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterThread() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runTest(TestRun run) throws IOException {
|
||||
try {
|
||||
|
@ -60,8 +44,7 @@ class CRunStrategy implements TestRunStrategy {
|
|||
File outputFile = new File(run.getBaseDirectory(), exeName);
|
||||
boolean compilerSuccess = compile(run.getBaseDirectory());
|
||||
if (!compilerSuccess) {
|
||||
run.getCallback().error(new RuntimeException("C compiler error"));
|
||||
return;
|
||||
throw new RuntimeException("C compiler error");
|
||||
}
|
||||
|
||||
List<String> runtimeOutput = new ArrayList<>();
|
||||
|
@ -77,12 +60,11 @@ class CRunStrategy implements TestRunStrategy {
|
|||
}
|
||||
if (!stdout.isEmpty() && stdout.get(stdout.size() - 1).equals("SUCCESS")) {
|
||||
writeLines(runtimeOutput);
|
||||
run.getCallback().complete();
|
||||
} else {
|
||||
run.getCallback().error(new RuntimeException("Test failed:\n" + mergeLines(runtimeOutput)));
|
||||
throw new RuntimeException("Test failed:\n" + mergeLines(runtimeOutput));
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
run.getCallback().complete();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,204 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 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 com.gargoylesoftware.htmlunit.BrowserVersion;
|
||||
import com.gargoylesoftware.htmlunit.Page;
|
||||
import com.gargoylesoftware.htmlunit.WebClient;
|
||||
import com.gargoylesoftware.htmlunit.WebConsole;
|
||||
import com.gargoylesoftware.htmlunit.WebWindow;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import net.sourceforge.htmlunit.corejs.javascript.BaseFunction;
|
||||
import net.sourceforge.htmlunit.corejs.javascript.Context;
|
||||
import net.sourceforge.htmlunit.corejs.javascript.Function;
|
||||
import net.sourceforge.htmlunit.corejs.javascript.NativeArray;
|
||||
import net.sourceforge.htmlunit.corejs.javascript.NativeJavaObject;
|
||||
import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
class HtmlUnitRunStrategy implements TestRunStrategy {
|
||||
private ThreadLocal<WebClient> webClient = new ThreadLocal<>();
|
||||
private ThreadLocal<HtmlPage> page = new ThreadLocal<>();
|
||||
private int runs;
|
||||
|
||||
@Override
|
||||
public void beforeAll() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAll() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeThread() {
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterThread() {
|
||||
cleanUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runTest(TestRun run) throws IOException {
|
||||
if (++runs == 50) {
|
||||
runs = 0;
|
||||
cleanUp();
|
||||
init();
|
||||
}
|
||||
|
||||
try {
|
||||
page.set(webClient.get().getPage("about:blank"));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
HtmlPage pageRef = page.get();
|
||||
pageRef.executeJavaScript(readFile(new File(run.getBaseDirectory(), run.getFileName())));
|
||||
boolean decodeStack = Boolean.parseBoolean(System.getProperty(TeaVMTestRunner.JS_DECODE_STACK, "true"));
|
||||
File debugFile = decodeStack ? new File(run.getBaseDirectory(), run.getFileName() + ".teavmdbg") : null;
|
||||
RhinoResultParser resultParser = new RhinoResultParser(debugFile);
|
||||
|
||||
AsyncResult asyncResult = new AsyncResult();
|
||||
Function function = (Function) page.get().executeJavaScript(readResource("teavm-htmlunit-adapter.js"))
|
||||
.getJavaScriptResult();
|
||||
Object[] args = new Object[] {
|
||||
run.getArgument(),
|
||||
decodeStack ? createStackDecoderFunction(resultParser) : null,
|
||||
new NativeJavaObject(function, asyncResult, AsyncResult.class)
|
||||
};
|
||||
pageRef.executeJavaScriptFunction(function, function, args, page.get());
|
||||
|
||||
resultParser.parseResult((Scriptable) asyncResult.getResult(), run.getCallback());
|
||||
}
|
||||
|
||||
private Function createStackDecoderFunction(RhinoResultParser resultParser) {
|
||||
return new BaseFunction() {
|
||||
@Override
|
||||
public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
|
||||
String stack = args[0].toString();
|
||||
return new NativeArray(resultParser.decodeStack(stack));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void cleanUp() {
|
||||
Page p = page.get();
|
||||
if (p != null) {
|
||||
p.cleanUp();
|
||||
}
|
||||
for (WebWindow window : webClient.get().getWebWindows()) {
|
||||
window.getJobManager().removeAllJobs();
|
||||
}
|
||||
page.remove();
|
||||
webClient.get().close();
|
||||
webClient.remove();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
WebClient client = new WebClient(BrowserVersion.CHROME);
|
||||
client.getWebConsole().setLogger(new WebConsole.Logger() {
|
||||
@Override
|
||||
public boolean isTraceEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Object message) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Object message) {
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Object message) {
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Object message) {
|
||||
System.err.println(message);
|
||||
}
|
||||
});
|
||||
webClient.set(client);
|
||||
}
|
||||
|
||||
private String readFile(File file) throws IOException {
|
||||
try (InputStream input = new FileInputStream(file)) {
|
||||
return IOUtils.toString(input, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
private String readResource(String resourceName) throws IOException {
|
||||
try (InputStream input = HtmlUnitRunStrategy.class.getClassLoader().getResourceAsStream(resourceName)) {
|
||||
if (input == null) {
|
||||
return "";
|
||||
}
|
||||
return IOUtils.toString(input, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
public static class AsyncResult {
|
||||
private CountDownLatch latch = new CountDownLatch(1);
|
||||
private Object result;
|
||||
|
||||
public void complete(Object result) {
|
||||
this.result = result;
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
public Object getResult() {
|
||||
try {
|
||||
latch.await(5, TimeUnit.SECONDS);
|
||||
return result;
|
||||
} catch (InterruptedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,9 +40,6 @@ import java.util.Map;
|
|||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
@ -123,44 +120,21 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
|
||||
private Class<?> testClass;
|
||||
private boolean isWholeClassCompilation;
|
||||
private ClassHolderSource classSource;
|
||||
private ClassLoader classLoader;
|
||||
private static ClassHolderSource classSource;
|
||||
private static ClassLoader classLoader;
|
||||
private Description suiteDescription;
|
||||
private static Map<ClassLoader, ClassHolderSource> classSources = new WeakHashMap<>();
|
||||
private File outputDir;
|
||||
private static File outputDir;
|
||||
private Map<Method, Description> descriptions = new HashMap<>();
|
||||
private static Map<RunKind, RunnerKindInfo> runners = new HashMap<>();
|
||||
private CountDownLatch latch;
|
||||
private static Map<RunKind, TestRunStrategy> runners = new HashMap<>();
|
||||
private List<Method> filteredChildren;
|
||||
private ReferenceCache referenceCache = new ReferenceCache();
|
||||
private static ReferenceCache referenceCache = new ReferenceCache();
|
||||
private boolean classCompilationOk;
|
||||
private List<TestRun> runsInCurrentClass = new ArrayList<>();
|
||||
|
||||
static class RunnerKindInfo {
|
||||
volatile TestRunner runner;
|
||||
volatile TestRunStrategy strategy;
|
||||
}
|
||||
|
||||
static {
|
||||
for (RunKind kind : RunKind.values()) {
|
||||
runners.put(kind, new RunnerKindInfo());
|
||||
}
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
synchronized (TeaVMTestRunner.class) {
|
||||
for (RunnerKindInfo info : runners.values()) {
|
||||
if (info.runner != null) {
|
||||
info.runner.stop();
|
||||
info.runner.waitForCompletion();
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public TeaVMTestRunner(Class<?> testClass) throws InitializationError {
|
||||
this.testClass = testClass;
|
||||
classLoader = TeaVMTestRunner.class.getClassLoader();
|
||||
classSource = getClassSource(classLoader);
|
||||
|
||||
String outputPath = System.getProperty(PATH_PARAM);
|
||||
if (outputPath != null) {
|
||||
outputDir = new File(outputPath);
|
||||
|
@ -170,34 +144,31 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
if (runStrategyName != null) {
|
||||
TestRunStrategy jsRunStrategy;
|
||||
switch (runStrategyName) {
|
||||
case "htmlunit":
|
||||
jsRunStrategy = new HtmlUnitRunStrategy();
|
||||
break;
|
||||
case "browser":
|
||||
jsRunStrategy = new BrowserRunStrategy(outputDir, "JAVASCRIPT", this::customBrowser);
|
||||
jsRunStrategy = new BrowserRunStrategy(outputDir, "JAVASCRIPT", TeaVMTestRunner::customBrowser);
|
||||
break;
|
||||
case "browser-chrome":
|
||||
jsRunStrategy = new BrowserRunStrategy(outputDir, "JAVASCRIPT", this::chromeBrowser);
|
||||
jsRunStrategy = new BrowserRunStrategy(outputDir, "JAVASCRIPT", TeaVMTestRunner::chromeBrowser);
|
||||
break;
|
||||
case "browser-firefox":
|
||||
jsRunStrategy = new BrowserRunStrategy(outputDir, "JAVASCRIPT", this::firefoxBrowser);
|
||||
jsRunStrategy = new BrowserRunStrategy(outputDir, "JAVASCRIPT", TeaVMTestRunner::firefoxBrowser);
|
||||
break;
|
||||
case "none":
|
||||
jsRunStrategy = null;
|
||||
break;
|
||||
default:
|
||||
throw new InitializationError("Unknown run strategy: " + runStrategyName);
|
||||
throw new RuntimeException("Unknown run strategy: " + runStrategyName);
|
||||
}
|
||||
runners.get(RunKind.JAVASCRIPT).strategy = jsRunStrategy;
|
||||
runners.put(RunKind.JAVASCRIPT, jsRunStrategy);
|
||||
}
|
||||
|
||||
String cCommand = System.getProperty(C_COMPILER);
|
||||
if (cCommand != null) {
|
||||
runners.get(RunKind.C).strategy = new CRunStrategy(cCommand);
|
||||
runners.put(RunKind.C, new CRunStrategy(cCommand));
|
||||
}
|
||||
String wasiCommand = System.getProperty(WASI_RUNNER);
|
||||
if (wasiCommand != null) {
|
||||
runners.get(RunKind.WASI).strategy = new WasiRunStrategy(wasiCommand);
|
||||
runners.put(RunKind.WASI, new WasiRunStrategy(wasiCommand));
|
||||
}
|
||||
|
||||
runStrategyName = System.getProperty(WASM_RUNNER);
|
||||
|
@ -205,28 +176,42 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
TestRunStrategy wasmRunStrategy;
|
||||
switch (runStrategyName) {
|
||||
case "browser":
|
||||
wasmRunStrategy = new BrowserRunStrategy(outputDir, "WASM", this::customBrowser);
|
||||
wasmRunStrategy = new BrowserRunStrategy(outputDir, "WASM", TeaVMTestRunner::customBrowser);
|
||||
break;
|
||||
case "chrome":
|
||||
case "browser-chrome":
|
||||
wasmRunStrategy = new BrowserRunStrategy(outputDir, "WASM", this::chromeBrowser);
|
||||
wasmRunStrategy = new BrowserRunStrategy(outputDir, "WASM", TeaVMTestRunner::chromeBrowser);
|
||||
break;
|
||||
case "browser-firefox":
|
||||
wasmRunStrategy = new BrowserRunStrategy(outputDir, "WASM", this::firefoxBrowser);
|
||||
wasmRunStrategy = new BrowserRunStrategy(outputDir, "WASM", TeaVMTestRunner::firefoxBrowser);
|
||||
break;
|
||||
default:
|
||||
throw new InitializationError("Unknown run strategy: " + runStrategyName);
|
||||
}
|
||||
runners.get(RunKind.WASM).strategy = wasmRunStrategy;
|
||||
throw new RuntimeException("Unknown run strategy: " + runStrategyName);
|
||||
}
|
||||
runners.put(RunKind.WASM, wasmRunStrategy);
|
||||
}
|
||||
|
||||
private Process customBrowser(String url) {
|
||||
for (var strategy : runners.values()) {
|
||||
strategy.beforeAll();
|
||||
}
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
for (var strategy : runners.values()) {
|
||||
strategy.afterAll();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public TeaVMTestRunner(Class<?> testClass) throws InitializationError {
|
||||
this.testClass = testClass;
|
||||
}
|
||||
|
||||
private static Process customBrowser(String url) {
|
||||
System.out.println("Open link to run tests: " + url + "?logging=true");
|
||||
return null;
|
||||
}
|
||||
|
||||
private Process chromeBrowser(String url) {
|
||||
private static Process chromeBrowser(String url) {
|
||||
return browserTemplate("chrome", url, (profile, params) -> {
|
||||
addChromeCommand(params);
|
||||
params.addAll(Arrays.asList(
|
||||
|
@ -239,7 +224,7 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
});
|
||||
}
|
||||
|
||||
private Process firefoxBrowser(String url) {
|
||||
private static Process firefoxBrowser(String url) {
|
||||
return browserTemplate("firefox", url, (profile, params) -> {
|
||||
addFirefoxCommand(params);
|
||||
params.addAll(Arrays.asList(
|
||||
|
@ -250,7 +235,7 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
});
|
||||
}
|
||||
|
||||
private void addChromeCommand(List<String> params) {
|
||||
private static void addChromeCommand(List<String> params) {
|
||||
if (isMacos()) {
|
||||
params.add("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome");
|
||||
} else if (isWindows()) {
|
||||
|
@ -263,7 +248,7 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}
|
||||
}
|
||||
|
||||
private void addFirefoxCommand(List<String> params) {
|
||||
private static void addFirefoxCommand(List<String> params) {
|
||||
if (isMacos()) {
|
||||
params.add("/Applications/Firefox.app/Contents/MacOS/firefox");
|
||||
return;
|
||||
|
@ -276,15 +261,15 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
params.add("firefox");
|
||||
}
|
||||
|
||||
private boolean isWindows() {
|
||||
private static boolean isWindows() {
|
||||
return System.getProperty("os.name").toLowerCase().startsWith("windows");
|
||||
}
|
||||
|
||||
private boolean isMacos() {
|
||||
private static boolean isMacos() {
|
||||
return System.getProperty("os.name").toLowerCase().startsWith("mac");
|
||||
}
|
||||
|
||||
private Process browserTemplate(String name, String url, BiConsumer<String, List<String>> paramsBuilder) {
|
||||
private static Process browserTemplate(String name, String url, BiConsumer<String, List<String>> paramsBuilder) {
|
||||
File temp;
|
||||
try {
|
||||
temp = File.createTempFile("teavm", "teavm");
|
||||
|
@ -315,7 +300,7 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}
|
||||
}
|
||||
|
||||
private void logStream(InputStream stream, String name) {
|
||||
private static void logStream(InputStream stream, String name) {
|
||||
new Thread(() -> {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
|
||||
while (true) {
|
||||
|
@ -331,7 +316,7 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}).start();
|
||||
}
|
||||
|
||||
private void deleteDir(File dir) {
|
||||
private static void deleteDir(File dir) {
|
||||
for (File file : dir.listFiles()) {
|
||||
if (file.isDirectory()) {
|
||||
deleteDir(file);
|
||||
|
@ -356,9 +341,9 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
@Override
|
||||
public void run(RunNotifier notifier) {
|
||||
List<Method> children = getFilteredChildren();
|
||||
latch = new CountDownLatch(children.size());
|
||||
var description = getDescription();
|
||||
|
||||
notifier.fireTestStarted(getDescription());
|
||||
notifier.fireTestStarted(description);
|
||||
isWholeClassCompilation = testClass.isAnnotationPresent(WholeClassCompilation.class);
|
||||
if (isWholeClassCompilation) {
|
||||
classCompilationOk = compileWholeClass(children, notifier);
|
||||
|
@ -370,16 +355,7 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
writeRunsDescriptor();
|
||||
runsInCurrentClass.clear();
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
if (latch.await(1000, TimeUnit.MILLISECONDS)) {
|
||||
break;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
notifier.fireTestFinished(getDescription());
|
||||
notifier.fireTestFinished(description);
|
||||
}
|
||||
|
||||
private List<Method> getChildren() {
|
||||
|
@ -473,7 +449,7 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
|
||||
if (isIgnored(child)) {
|
||||
notifier.fireTestIgnored(description);
|
||||
latch.countDown();
|
||||
notifier.fireTestFinished(description);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -488,42 +464,38 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}
|
||||
|
||||
if (success && outputDir != null) {
|
||||
int[] configurationIndex = new int[] { 0 };
|
||||
|
||||
List<TestRun> runs = new ArrayList<>();
|
||||
Consumer<Boolean> onSuccess = runSuccess -> {
|
||||
if (runSuccess && configurationIndex[0] < runs.size()) {
|
||||
submitRun(runs.get(configurationIndex[0]++));
|
||||
} else {
|
||||
notifier.fireTestFinished(description);
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
|
||||
if (isWholeClassCompilation) {
|
||||
if (!classCompilationOk) {
|
||||
notifier.fireTestFinished(description);
|
||||
notifier.fireTestFailure(new Failure(description,
|
||||
new AssertionError("Could not compile test class")));
|
||||
latch.countDown();
|
||||
} else {
|
||||
runTestsFromWholeClass(child, notifier, runs, onSuccess);
|
||||
onSuccess.accept(true);
|
||||
prepareTestsFromWholeClass(child, runs);
|
||||
}
|
||||
} else {
|
||||
runCompiledTest(child, notifier, runs, onSuccess);
|
||||
prepareCompiledTest(child, notifier, runs);
|
||||
}
|
||||
|
||||
for (var run : runs) {
|
||||
try {
|
||||
submitRun(run);
|
||||
} catch (Throwable e) {
|
||||
notifier.fireTestFailure(new Failure(description, e));
|
||||
break;
|
||||
}
|
||||
}
|
||||
notifier.fireTestFinished(description);
|
||||
} else {
|
||||
if (!ran) {
|
||||
notifier.fireTestIgnored(description);
|
||||
}
|
||||
notifier.fireTestFinished(description);
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
private void runTestsFromWholeClass(Method child, RunNotifier notifier, List<TestRun> runs,
|
||||
Consumer<Boolean> onSuccess) {
|
||||
private void prepareTestsFromWholeClass(Method child, List<TestRun> runs) {
|
||||
File outputPath = getOutputPathForClass();
|
||||
File outputPathForMethod = getOutputPath(child);
|
||||
MethodDescriptor descriptor = getDescriptor(child);
|
||||
|
@ -533,10 +505,9 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
testFilePath.mkdirs();
|
||||
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
for (TeaVMTestConfiguration<JavaScriptTarget> configuration : getJavaScriptConfigurations()) {
|
||||
for (var configuration : getJavaScriptConfigurations()) {
|
||||
File testPath = getOutputFile(outputPath, "classTest", configuration.getSuffix(), false, ".js");
|
||||
runs.add(createTestRun(configuration, testPath, child, RunKind.JAVASCRIPT, reference.toString(),
|
||||
notifier, onSuccess));
|
||||
runs.add(createTestRun(configuration, testPath, child, RunKind.JAVASCRIPT, reference.toString()));
|
||||
File htmlPath = getOutputFile(outputPathForMethod, "test", configuration.getSuffix(), false, ".html");
|
||||
properties.put("SCRIPT", "../" + testPath.getName());
|
||||
properties.put("IDENTIFIER", reference.toString());
|
||||
|
@ -547,10 +518,9 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}
|
||||
}
|
||||
|
||||
for (TeaVMTestConfiguration<WasmTarget> configuration : getWasmConfigurations()) {
|
||||
for (var configuration : getWasmConfigurations()) {
|
||||
File testPath = getOutputFile(outputPath, "classTest", configuration.getSuffix(), false, ".wasm");
|
||||
runs.add(createTestRun(configuration, testPath, child, RunKind.WASM, reference.toString(),
|
||||
notifier, onSuccess));
|
||||
runs.add(createTestRun(configuration, testPath, child, RunKind.WASM, reference.toString()));
|
||||
File htmlPath = getOutputFile(outputPathForMethod, "test-wasm", configuration.getSuffix(), false, ".html");
|
||||
properties.put("SCRIPT", "../" + testPath.getName());
|
||||
properties.put("IDENTIFIER", reference.toString());
|
||||
|
@ -561,30 +531,28 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}
|
||||
}
|
||||
|
||||
for (TeaVMTestConfiguration<WasmTarget> configuration : getWasiConfigurations()) {
|
||||
for (var configuration : getWasiConfigurations()) {
|
||||
File testPath = getOutputFile(outputPath, "classTest", configuration.getSuffix(), false, ".wasm");
|
||||
runs.add(createTestRun(configuration, testPath, child, RunKind.WASI, reference.toString(),
|
||||
notifier, onSuccess));
|
||||
runs.add(createTestRun(configuration, testPath, child, RunKind.WASI, reference.toString()));
|
||||
File htmlPath = getOutputFile(outputPathForMethod, "test-wasm", configuration.getSuffix(), false, ".html");
|
||||
properties.put("SCRIPT", "../" + testPath.getName());
|
||||
properties.put("IDENTIFIER", reference.toString());
|
||||
}
|
||||
|
||||
for (TeaVMTestConfiguration<CTarget> configuration : getCConfigurations()) {
|
||||
for (var configuration : getCConfigurations()) {
|
||||
File testPath = getOutputFile(outputPath, "classTest", configuration.getSuffix(), true, ".c");
|
||||
runs.add(createTestRun(configuration, testPath, child, RunKind.C, reference.toString(),
|
||||
notifier, onSuccess));
|
||||
runs.add(createTestRun(configuration, testPath, child, RunKind.C, reference.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
private void runCompiledTest(Method child, RunNotifier notifier, List<TestRun> runs, Consumer<Boolean> onSuccess) {
|
||||
private void prepareCompiledTest(Method child, RunNotifier notifier, List<TestRun> runs) {
|
||||
try {
|
||||
File outputPath = getOutputPath(child);
|
||||
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
for (TeaVMTestConfiguration<JavaScriptTarget> configuration : getJavaScriptConfigurations()) {
|
||||
for (var configuration : getJavaScriptConfigurations()) {
|
||||
CompileResult compileResult = compileToJs(singleTest(child), "test", configuration, outputPath);
|
||||
TestRun run = prepareRun(configuration, child, compileResult, notifier, RunKind.JAVASCRIPT, onSuccess);
|
||||
TestRun run = prepareRun(configuration, child, compileResult, notifier, RunKind.JAVASCRIPT);
|
||||
if (run != null) {
|
||||
runs.add(run);
|
||||
|
||||
|
@ -601,18 +569,18 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}
|
||||
}
|
||||
|
||||
for (TeaVMTestConfiguration<CTarget> configuration : getCConfigurations()) {
|
||||
for (var configuration : getCConfigurations()) {
|
||||
CompileResult compileResult = compileToC(singleTest(child), "test", configuration, outputPath);
|
||||
TestRun run = prepareRun(configuration, child, compileResult, notifier, RunKind.C, onSuccess);
|
||||
TestRun run = prepareRun(configuration, child, compileResult, notifier, RunKind.C);
|
||||
if (run != null) {
|
||||
runs.add(run);
|
||||
}
|
||||
}
|
||||
|
||||
for (TeaVMTestConfiguration<WasmTarget> configuration : getWasmConfigurations()) {
|
||||
for (var configuration : getWasmConfigurations()) {
|
||||
CompileResult compileResult = compileToWasm(WasmRuntimeType.TEAVM, singleTest(child),
|
||||
"test", configuration, outputPath);
|
||||
TestRun run = prepareRun(configuration, child, compileResult, notifier, RunKind.WASM, onSuccess);
|
||||
TestRun run = prepareRun(configuration, child, compileResult, notifier, RunKind.WASM);
|
||||
if (run != null) {
|
||||
runs.add(run);
|
||||
|
||||
|
@ -629,10 +597,10 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}
|
||||
}
|
||||
|
||||
for (TeaVMTestConfiguration<WasmTarget> configuration : getWasiConfigurations()) {
|
||||
for (var configuration : getWasiConfigurations()) {
|
||||
CompileResult compileResult = compileToWasm(WasmRuntimeType.WASI, singleTest(child), "test",
|
||||
configuration, outputPath);
|
||||
TestRun run = prepareRun(configuration, child, compileResult, notifier, RunKind.WASI, onSuccess);
|
||||
TestRun run = prepareRun(configuration, child, compileResult, notifier, RunKind.WASI);
|
||||
if (run != null) {
|
||||
runs.add(run);
|
||||
|
||||
|
@ -644,11 +612,8 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
} catch (Throwable e) {
|
||||
notifier.fireTestFailure(new Failure(describeChild(child), e));
|
||||
notifier.fireTestFinished(describeChild(child));
|
||||
latch.countDown();
|
||||
return;
|
||||
}
|
||||
|
||||
onSuccess.accept(true);
|
||||
}
|
||||
|
||||
static String[] getExpectedExceptions(MethodReader method) {
|
||||
|
@ -974,38 +939,22 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}
|
||||
|
||||
private TestRun prepareRun(TeaVMTestConfiguration<?> configuration, Method child, CompileResult result,
|
||||
RunNotifier notifier, RunKind kind, Consumer<Boolean> onComplete) {
|
||||
RunNotifier notifier, RunKind kind) {
|
||||
Description description = describeChild(child);
|
||||
|
||||
if (!result.success) {
|
||||
notifier.fireTestFailure(createFailure(description, result));
|
||||
notifier.fireTestFinished(description);
|
||||
latch.countDown();
|
||||
return null;
|
||||
}
|
||||
|
||||
return createTestRun(configuration, result.file, child, kind, null, notifier, onComplete);
|
||||
return createTestRun(configuration, result.file, child, kind, null);
|
||||
}
|
||||
|
||||
private TestRun createTestRun(TeaVMTestConfiguration<?> configuration, File file, Method child, RunKind kind,
|
||||
String argument, RunNotifier notifier, Consumer<Boolean> onComplete) {
|
||||
Description description = describeChild(child);
|
||||
|
||||
TestRunCallback callback = new TestRunCallback() {
|
||||
@Override
|
||||
public void complete() {
|
||||
onComplete.accept(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Throwable e) {
|
||||
notifier.fireTestFailure(new Failure(description, e));
|
||||
onComplete.accept(false);
|
||||
}
|
||||
};
|
||||
|
||||
return new TestRun(generateName(child.getName(), configuration), file.getParentFile(), child, description,
|
||||
file.getName(), kind, argument, callback);
|
||||
String argument) {
|
||||
return new TestRun(generateName(child.getName(), configuration), file.getParentFile(), child,
|
||||
file.getName(), kind, argument);
|
||||
}
|
||||
|
||||
private String generateName(String baseName, TeaVMTestConfiguration<?> configuration) {
|
||||
|
@ -1024,27 +973,15 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
return new Failure(description, throwable);
|
||||
}
|
||||
|
||||
private void submitRun(TestRun run) {
|
||||
synchronized (TeaVMTestRunner.class) {
|
||||
private boolean submitRun(TestRun run) throws IOException {
|
||||
runsInCurrentClass.add(run);
|
||||
RunnerKindInfo info = runners.get(run.getKind());
|
||||
|
||||
if (info.strategy == null) {
|
||||
run.getCallback().complete();
|
||||
return;
|
||||
var strategy = runners.get(run.getKind());
|
||||
if (strategy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.runner == null) {
|
||||
info.runner = new TestRunner(info.strategy);
|
||||
try {
|
||||
info.runner.setNumThreads(Integer.parseInt(System.getProperty(THREAD_COUNT, "1")));
|
||||
} catch (NumberFormatException e) {
|
||||
info.runner.setNumThreads(1);
|
||||
}
|
||||
info.runner.init();
|
||||
}
|
||||
info.runner.run(run);
|
||||
}
|
||||
strategy.runTest(run);
|
||||
return true;
|
||||
}
|
||||
|
||||
private File getOutputPath(Method method) {
|
||||
|
@ -1422,9 +1359,8 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
return sb.append(s.substring(i)).toString();
|
||||
}
|
||||
|
||||
private ClassHolderSource getClassSource(ClassLoader classLoader) {
|
||||
return classSources.computeIfAbsent(classLoader, cl -> new PreOptimizingClassHolderSource(
|
||||
new ClasspathClassHolderSource(classLoader, referenceCache)));
|
||||
private static ClassHolderSource getClassSource(ClassLoader classLoader) {
|
||||
return new PreOptimizingClassHolderSource(new ClasspathClassHolderSource(classLoader, referenceCache));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,7 +30,7 @@ final class TestNativeEntryPoint {
|
|||
} catch (Throwable e) {
|
||||
PrintStream out = new PrintStream(StderrOutputStream.INSTANCE);
|
||||
e.printStackTrace(out);
|
||||
out.println("FAILURE");
|
||||
new PrintStream(StdoutOutputStream.INSTANCE).println("FAILURE");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,28 +17,23 @@ package org.teavm.junit;
|
|||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import org.junit.runner.Description;
|
||||
|
||||
class TestRun {
|
||||
private String name;
|
||||
private File baseDirectory;
|
||||
private Method method;
|
||||
private Description description;
|
||||
private String fileName;
|
||||
private RunKind kind;
|
||||
private TestRunCallback callback;
|
||||
private String argument;
|
||||
|
||||
TestRun(String name, File baseDirectory, Method method, Description description, String fileName, RunKind kind,
|
||||
String argument, TestRunCallback callback) {
|
||||
TestRun(String name, File baseDirectory, Method method, String fileName, RunKind kind,
|
||||
String argument) {
|
||||
this.name = name;
|
||||
this.baseDirectory = baseDirectory;
|
||||
this.method = method;
|
||||
this.description = description;
|
||||
this.fileName = fileName;
|
||||
this.kind = kind;
|
||||
this.argument = argument;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
@ -53,10 +48,6 @@ class TestRun {
|
|||
return method;
|
||||
}
|
||||
|
||||
public Description getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
@ -68,8 +59,4 @@ class TestRun {
|
|||
public String getArgument() {
|
||||
return argument;
|
||||
}
|
||||
|
||||
public TestRunCallback getCallback() {
|
||||
return callback;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,11 @@ package org.teavm.junit;
|
|||
import java.io.IOException;
|
||||
|
||||
interface TestRunStrategy {
|
||||
void beforeAll();
|
||||
default void beforeAll() {
|
||||
}
|
||||
|
||||
void afterAll();
|
||||
|
||||
void beforeThread();
|
||||
|
||||
void afterThread();
|
||||
default void afterAll() {
|
||||
}
|
||||
|
||||
void runTest(TestRun run) throws IOException;
|
||||
}
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 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 java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
class TestRunner {
|
||||
private int numThreads = 1;
|
||||
private TestRunStrategy strategy;
|
||||
private BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
|
||||
private CountDownLatch latch;
|
||||
private volatile boolean stopped;
|
||||
|
||||
TestRunner(TestRunStrategy strategy) {
|
||||
this.strategy = strategy;
|
||||
}
|
||||
|
||||
public void setNumThreads(int numThreads) {
|
||||
this.numThreads = numThreads;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
latch = new CountDownLatch(numThreads);
|
||||
strategy.beforeAll();
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
strategy.afterAll();
|
||||
}));
|
||||
|
||||
for (int i = 0; i < numThreads; ++i) {
|
||||
Thread thread = new Thread(() -> {
|
||||
strategy.beforeThread();
|
||||
while (!stopped || !taskQueue.isEmpty()) {
|
||||
Runnable task;
|
||||
try {
|
||||
task = taskQueue.poll(100, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
if (task != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
strategy.afterThread();
|
||||
latch.countDown();
|
||||
});
|
||||
thread.setDaemon(true);
|
||||
thread.setName("teavm-test-runner-" + i);
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void addTask(Runnable runnable) {
|
||||
taskQueue.add(runnable);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
stopped = true;
|
||||
taskQueue.add(() -> { });
|
||||
}
|
||||
|
||||
public void waitForCompletion() {
|
||||
while (true) {
|
||||
try {
|
||||
if (latch.await(1000, TimeUnit.MILLISECONDS)) {
|
||||
break;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run(TestRun run) {
|
||||
addTask(() -> runImpl(run));
|
||||
}
|
||||
|
||||
private void runImpl(TestRun run) {
|
||||
try {
|
||||
strategy.runTest(run);
|
||||
} catch (Exception e) {
|
||||
run.getCallback().error(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,22 +30,6 @@ class WasiRunStrategy implements TestRunStrategy {
|
|||
this.runCommand = runCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeAll() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAll() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeThread() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterThread() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runTest(TestRun run) throws IOException {
|
||||
try {
|
||||
|
@ -62,12 +46,11 @@ class WasiRunStrategy implements TestRunStrategy {
|
|||
}
|
||||
if (!stdout.isEmpty() && stdout.get(stdout.size() - 1).equals("SUCCESS")) {
|
||||
writeLines(runtimeOutput);
|
||||
run.getCallback().complete();
|
||||
} else {
|
||||
run.getCallback().error(new RuntimeException("Test failed:\n" + mergeLines(runtimeOutput)));
|
||||
throw new RuntimeException("Test failed:\n" + mergeLines(runtimeOutput));
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
run.getCallback().complete();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
var $rt_decodeStack;
|
||||
|
||||
function runMain(argument, stackDecoder, callback) {
|
||||
$rt_decodeStack = stackDecoder;
|
||||
main(argument !== null ? [argument] : [], function(result) {
|
||||
var message = {};
|
||||
if (result instanceof Error) {
|
||||
makeErrorMessage(message, result);
|
||||
} else {
|
||||
message.status = "ok";
|
||||
}
|
||||
callback.complete(message);
|
||||
});
|
||||
|
||||
function makeErrorMessage(message, e) {
|
||||
message.status = "exception";
|
||||
var je = main.javaException(e);
|
||||
if (je) {
|
||||
message.className = je.constructor.name;
|
||||
message.message = je.getMessage();
|
||||
} else {
|
||||
message.className = Object.getPrototypeOf(e).name;
|
||||
message.message = e.message;
|
||||
}
|
||||
message.exception = e;
|
||||
message.stack = e.stack;
|
||||
}
|
||||
}
|
|
@ -91,6 +91,7 @@ function launchTest(argument, callback) {
|
|||
function launchWasmTest(path, argument, callback) {
|
||||
let output = [];
|
||||
let outputBuffer = "";
|
||||
let outputBufferStderr = "";
|
||||
|
||||
function putwchar(charCode) {
|
||||
if (charCode === 10) {
|
||||
|
@ -106,6 +107,7 @@ function launchWasmTest(path, argument, callback) {
|
|||
break;
|
||||
default:
|
||||
output.push(outputBuffer);
|
||||
log.push({ message: outputBuffer, type: "stdout" });
|
||||
outputBuffer = "";
|
||||
}
|
||||
} else {
|
||||
|
@ -113,8 +115,37 @@ function launchWasmTest(path, argument, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
function putwchars(controller, buffer, count) {
|
||||
let memory = new Int8Array(instance.exports.memory.buffer);
|
||||
for (let i = 0; i < count; ++i) {
|
||||
// TODO: support UTF-8
|
||||
putwchar(memory[buffer++]);
|
||||
}
|
||||
}
|
||||
|
||||
function putwcharStderr(charCode) {
|
||||
if (charCode === 10) {
|
||||
log.push({ message: outputBufferStderr, type: "stderr" });
|
||||
outputBufferStderr = "";
|
||||
} else {
|
||||
outputBufferStderr += String.fromCharCode(charCode);
|
||||
}
|
||||
}
|
||||
|
||||
function putwcharsStderr(controller, buffer, count) {
|
||||
let memory = new Int8Array(instance.exports.memory.buffer);
|
||||
for (let i = 0; i < count; ++i) {
|
||||
// TODO: support UTF-8
|
||||
putwcharStderr(memory[buffer++]);
|
||||
}
|
||||
}
|
||||
|
||||
let instance = null;
|
||||
|
||||
TeaVM.wasm.load(path, {
|
||||
installImports: function(o) {
|
||||
o.teavm.putwcharsOut = (chars, count) => putwchars(instance, chars, count);
|
||||
o.teavm.putwcharsErr = (chars, count) => putwcharsStderr(instance, chars, count);
|
||||
o.teavm.putwchar = putwchar;
|
||||
},
|
||||
errorCallback: function(err) {
|
||||
|
@ -124,12 +155,9 @@ function launchWasmTest(path, argument, callback) {
|
|||
}));
|
||||
}
|
||||
}).then(teavm => {
|
||||
teavm.main(argument ? [argument] : []);
|
||||
})
|
||||
.then(() => {
|
||||
callback(wrapResponse({ status: "OK" }));
|
||||
})
|
||||
.catch(err => {
|
||||
instance = teavm.instance;
|
||||
return teavm.main(argument ? [argument] : []);
|
||||
}).catch(err => {
|
||||
callback(wrapResponse({
|
||||
status: "failed",
|
||||
errorMessage: err.message + '\n' + err.stack
|
||||
|
|
Loading…
Reference in New Issue
Block a user