mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Add support for C backend in TeaVMTestRunner
This commit is contained in:
parent
e77997c93f
commit
4990dbe8e4
|
@ -157,7 +157,7 @@ public class TThrowable extends RuntimeException {
|
|||
stream.println(TString.wrap(getClass().getName() + ": " + getMessage()));
|
||||
if (stackTrace != null) {
|
||||
for (TStackTraceElement element : stackTrace) {
|
||||
stream.print(TString.wrap(" at "));
|
||||
stream.print(TString.wrap(" at "));
|
||||
stream.println(element);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ import org.teavm.model.ClassHolder;
|
|||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.FieldReader;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.ListableClassHolderSource;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
|
@ -170,6 +171,7 @@ public class CTarget implements TeaVMTarget {
|
|||
|
||||
dependencyAnalyzer.linkClass("java.lang.String", null);
|
||||
dependencyAnalyzer.linkClass("java.lang.Class", null);
|
||||
dependencyAnalyzer.linkField(new FieldReference("java.lang.String", "hashCode"), null);
|
||||
|
||||
ClassDependency runtimeClassDep = dependencyAnalyzer.linkClass(RuntimeClass.class.getName(), null);
|
||||
ClassDependency runtimeObjectDep = dependencyAnalyzer.linkClass(RuntimeObject.class.getName(), null);
|
||||
|
|
|
@ -202,6 +202,9 @@ public class ExceptionHandlingShadowStackContributor {
|
|||
|
||||
String fileName = insn.getLocation() != null ? insn.getLocation().getFileName() : null;
|
||||
int lineNumber = insn.getLocation() != null ? insn.getLocation().getLine() : -1;
|
||||
if (fileName != null) {
|
||||
fileName = fileName.substring(fileName.lastIndexOf('/') + 1);
|
||||
}
|
||||
CallSiteLocation location = new CallSiteLocation(fileName, method.getClassName(), method.getName(),
|
||||
lineNumber);
|
||||
CallSiteDescriptor callSite = new CallSiteDescriptor(callSites.size(), location);
|
||||
|
|
118
tools/junit/src/main/java/org/teavm/junit/CRunner.java
Normal file
118
tools/junit/src/main/java/org/teavm/junit/CRunner.java
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* 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 java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CRunner {
|
||||
private String compilerCommand;
|
||||
|
||||
public CRunner(String compilerCommand) {
|
||||
this.compilerCommand = compilerCommand;
|
||||
}
|
||||
|
||||
public void run(TestRun run) {
|
||||
try {
|
||||
File inputFile = new File(run.getBaseDirectory(), run.getFileName());
|
||||
String exeName = run.getFileName();
|
||||
if (exeName.endsWith(".c")) {
|
||||
exeName = exeName.substring(0, exeName.length() - 2);
|
||||
}
|
||||
if (System.getProperty("os.name").toLowerCase().contains("win")) {
|
||||
exeName += ".exe";
|
||||
} else {
|
||||
exeName += ".out";
|
||||
}
|
||||
|
||||
File outputFile = new File(run.getBaseDirectory(), exeName);
|
||||
List<String> compilerOutput = new ArrayList<>();
|
||||
boolean compilerSuccess = runCompiler(inputFile, outputFile, compilerOutput);
|
||||
if (!compilerSuccess) {
|
||||
run.getCallback().error(new RuntimeException("C compiler error:\n" + mergeLines(compilerOutput)));
|
||||
return;
|
||||
}
|
||||
writeLines(compilerOutput);
|
||||
|
||||
List<String> runtimeOutput = new ArrayList<>();
|
||||
outputFile.setExecutable(true);
|
||||
runProcess(new ProcessBuilder(outputFile.getPath()).start(), runtimeOutput);
|
||||
if (!runtimeOutput.isEmpty() && runtimeOutput.get(runtimeOutput.size() - 1).equals("SUCCESS")) {
|
||||
writeLines(runtimeOutput.subList(0, runtimeOutput.size() - 1));
|
||||
run.getCallback().complete();
|
||||
} else {
|
||||
run.getCallback().error(new RuntimeException("Test failed:\n" + mergeLines(runtimeOutput)));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
run.getCallback().error(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private String mergeLines(List<String> lines) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
sb.append(line).append('\n');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void writeLines(List<String> lines) {
|
||||
for (String line : lines) {
|
||||
System.out.println(line);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean runCompiler(File inputFile, File outputFile, List<String> output) throws Exception {
|
||||
String[] parts = compilerCommand.split(" +");
|
||||
for (int i = 0; i < parts.length; ++i) {
|
||||
switch (parts[i]) {
|
||||
case "@IN":
|
||||
parts[i] = inputFile.getPath();
|
||||
break;
|
||||
case "@OUT":
|
||||
parts[i] = outputFile.getPath();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return runProcess(new ProcessBuilder(parts).start(), output);
|
||||
}
|
||||
|
||||
private boolean runProcess(Process process, List<String> output) throws Exception {
|
||||
BufferedReader stdin = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
BufferedReader stderr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
||||
|
||||
while (process.isAlive()) {
|
||||
String line = stderr.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
output.add(line);
|
||||
}
|
||||
while (process.isAlive()) {
|
||||
String line = stdin.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
output.add(line);
|
||||
}
|
||||
|
||||
return process.waitFor() == 0;
|
||||
}
|
||||
}
|
|
@ -54,7 +54,7 @@ class HtmlUnitRunStrategy implements TestRunStrategy {
|
|||
}
|
||||
|
||||
try {
|
||||
page.set(webClient.get().<HtmlPage>getPage("about:blank"));
|
||||
page.set(webClient.get().getPage("about:blank"));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
21
tools/junit/src/main/java/org/teavm/junit/RunKind.java
Normal file
21
tools/junit/src/main/java/org/teavm/junit/RunKind.java
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
enum RunKind {
|
||||
JAVASCRIPT,
|
||||
C
|
||||
}
|
|
@ -15,18 +15,20 @@
|
|||
*/
|
||||
package org.teavm.junit;
|
||||
|
||||
import org.teavm.backend.c.CTarget;
|
||||
import org.teavm.backend.javascript.JavaScriptTarget;
|
||||
import org.teavm.vm.TeaVM;
|
||||
import org.teavm.vm.TeaVMOptimizationLevel;
|
||||
import org.teavm.vm.TeaVMTarget;
|
||||
|
||||
interface TeaVMTestConfiguration {
|
||||
interface TeaVMTestConfiguration<T extends TeaVMTarget> {
|
||||
String getSuffix();
|
||||
|
||||
void apply(TeaVM vm);
|
||||
|
||||
void apply(JavaScriptTarget target);
|
||||
void apply(T target);
|
||||
|
||||
TeaVMTestConfiguration DEFAULT = new TeaVMTestConfiguration() {
|
||||
TeaVMTestConfiguration<JavaScriptTarget> JS_DEFAULT = new TeaVMTestConfiguration<JavaScriptTarget>() {
|
||||
@Override
|
||||
public String getSuffix() {
|
||||
return "";
|
||||
|
@ -43,7 +45,7 @@ interface TeaVMTestConfiguration {
|
|||
}
|
||||
};
|
||||
|
||||
TeaVMTestConfiguration OPTIMIZED = new TeaVMTestConfiguration() {
|
||||
TeaVMTestConfiguration<JavaScriptTarget> JS_OPTIMIZED = new TeaVMTestConfiguration<JavaScriptTarget>() {
|
||||
@Override
|
||||
public String getSuffix() {
|
||||
return "optimized";
|
||||
|
@ -60,7 +62,7 @@ interface TeaVMTestConfiguration {
|
|||
}
|
||||
};
|
||||
|
||||
TeaVMTestConfiguration MINIFIED = new TeaVMTestConfiguration() {
|
||||
TeaVMTestConfiguration<JavaScriptTarget> JS_MINIFIED = new TeaVMTestConfiguration<JavaScriptTarget>() {
|
||||
@Override
|
||||
public String getSuffix() {
|
||||
return "min";
|
||||
|
@ -76,4 +78,37 @@ interface TeaVMTestConfiguration {
|
|||
target.setMinifying(true);
|
||||
}
|
||||
};
|
||||
|
||||
TeaVMTestConfiguration<CTarget> C_DEFAULT = new TeaVMTestConfiguration<CTarget>() {
|
||||
@Override
|
||||
public String getSuffix() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(TeaVM vm) {
|
||||
vm.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(CTarget target) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TeaVMTestConfiguration<CTarget> C_OPTIMIZED = new TeaVMTestConfiguration<CTarget>() {
|
||||
@Override
|
||||
public String getSuffix() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(TeaVM vm) {
|
||||
vm.setOptimizationLevel(TeaVMOptimizationLevel.FULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(CTarget target) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ import java.util.concurrent.ScheduledFuture;
|
|||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.runner.Description;
|
||||
|
@ -49,6 +50,7 @@ import org.junit.runner.manipulation.NoTestsRemainException;
|
|||
import org.junit.runner.notification.Failure;
|
||||
import org.junit.runner.notification.RunNotifier;
|
||||
import org.junit.runners.model.InitializationError;
|
||||
import org.teavm.backend.c.CTarget;
|
||||
import org.teavm.backend.javascript.JavaScriptTarget;
|
||||
import org.teavm.callgraph.CallGraph;
|
||||
import org.teavm.diagnostics.DefaultProblemTextConsumer;
|
||||
|
@ -67,12 +69,18 @@ import org.teavm.tooling.TeaVMProblemRenderer;
|
|||
import org.teavm.vm.DirectoryBuildTarget;
|
||||
import org.teavm.vm.TeaVM;
|
||||
import org.teavm.vm.TeaVMBuilder;
|
||||
import org.teavm.vm.TeaVMTarget;
|
||||
|
||||
public class TeaVMTestRunner extends Runner implements Filterable {
|
||||
private static final String PATH_PARAM = "teavm.junit.target";
|
||||
private static final String RUNNER = "teavm.junit.js.runner";
|
||||
private static final String JS_RUNNER = "teavm.junit.js.runner";
|
||||
private static final String THREAD_COUNT = "teavm.junit.js.threads";
|
||||
private static final String SELENIUM_URL = "teavm.junit.js.selenium.url";
|
||||
private static final String C_ENABLED = "teavm.junit.c";
|
||||
private static final String C_COMPILER = "teavm.junit.c-compiler";
|
||||
private static final String MINIFIED = "teavm.junit.minified";
|
||||
private static final String OPTIMIZED = "teavm.junit.optimized";
|
||||
|
||||
private static final int stopTimeout = 15000;
|
||||
private Class<?> testClass;
|
||||
private ClassHolder classHolder;
|
||||
|
@ -82,12 +90,13 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
private File outputDir;
|
||||
private TestAdapter testAdapter = new JUnitTestAdapter();
|
||||
private Map<Method, Description> descriptions = new HashMap<>();
|
||||
private TestRunStrategy runStrategy;
|
||||
private TestRunStrategy jsRunStrategy;
|
||||
private static volatile TestRunner runner;
|
||||
private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
|
||||
private static volatile ScheduledFuture<?> cleanupFuture;
|
||||
private CountDownLatch latch;
|
||||
private List<Method> filteredChildren;
|
||||
private CRunner cRunner;
|
||||
|
||||
static {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
|
@ -111,27 +120,32 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
outputDir = new File(outputPath);
|
||||
}
|
||||
|
||||
String runStrategyName = System.getProperty(RUNNER);
|
||||
String runStrategyName = System.getProperty(JS_RUNNER);
|
||||
if (runStrategyName != null) {
|
||||
switch (runStrategyName) {
|
||||
case "selenium":
|
||||
try {
|
||||
runStrategy = new SeleniumRunStrategy(new URL(System.getProperty(SELENIUM_URL)));
|
||||
jsRunStrategy = new SeleniumRunStrategy(new URL(System.getProperty(SELENIUM_URL)));
|
||||
} catch (MalformedURLException e) {
|
||||
throw new InitializationError(e);
|
||||
}
|
||||
break;
|
||||
case "htmlunit":
|
||||
runStrategy = new HtmlUnitRunStrategy();
|
||||
jsRunStrategy = new HtmlUnitRunStrategy();
|
||||
break;
|
||||
case "":
|
||||
case "none":
|
||||
runStrategy = null;
|
||||
jsRunStrategy = null;
|
||||
break;
|
||||
default:
|
||||
throw new InitializationError("Unknown run strategy: " + runStrategyName);
|
||||
}
|
||||
}
|
||||
|
||||
String cCommand = System.getProperty(C_COMPILER);
|
||||
if (cCommand != null) {
|
||||
cRunner = new CRunner(cCommand);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -217,7 +231,6 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
|
||||
Description description = describeChild(child);
|
||||
if (success && outputDir != null) {
|
||||
List<TeaVMTestConfiguration> configurations = getConfigurations();
|
||||
int[] configurationIndex = new int[] { 0 };
|
||||
List<Consumer<Boolean>> onSuccess = new ArrayList<>();
|
||||
|
||||
|
@ -231,18 +244,30 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}
|
||||
});
|
||||
|
||||
for (TeaVMTestConfiguration configuration : configurations) {
|
||||
try {
|
||||
TestRun run = compileByTeaVM(child, notifier, configuration, onSuccess.get(0));
|
||||
try {
|
||||
File outputPath = getOutputPath(child);
|
||||
copyJsFilesTo(outputPath);
|
||||
|
||||
for (TeaVMTestConfiguration<JavaScriptTarget> configuration : getJavaScriptConfigurations()) {
|
||||
TestRun run = compile(child, notifier, RunKind.JAVASCRIPT,
|
||||
m -> compileToJs(m, configuration, outputPath), onSuccess.get(0));
|
||||
if (run != null) {
|
||||
runs.add(run);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
notifier.fireTestFailure(new Failure(description, e));
|
||||
notifier.fireTestFinished(description);
|
||||
latch.countDown();
|
||||
return;
|
||||
}
|
||||
|
||||
for (TeaVMTestConfiguration<CTarget> configuration : getCConfigurations()) {
|
||||
TestRun run = compile(child, notifier, RunKind.C,
|
||||
m -> compileToC(m, configuration, outputPath), onSuccess.get(0));
|
||||
if (run != null) {
|
||||
runs.add(run);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
notifier.fireTestFailure(new Failure(description, e));
|
||||
notifier.fireTestFinished(description);
|
||||
latch.countDown();
|
||||
return;
|
||||
}
|
||||
|
||||
onSuccess.get(0).accept(true);
|
||||
|
@ -293,13 +318,13 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
return true;
|
||||
}
|
||||
|
||||
private TestRun compileByTeaVM(Method child, RunNotifier notifier,
|
||||
TeaVMTestConfiguration configuration, Consumer<Boolean> onComplete) {
|
||||
private TestRun compile(Method child, RunNotifier notifier, RunKind kind,
|
||||
CompileFunction compiler, Consumer<Boolean> onComplete) {
|
||||
Description description = describeChild(child);
|
||||
|
||||
CompileResult compileResult;
|
||||
try {
|
||||
compileResult = compileTest(child, configuration);
|
||||
compileResult = compiler.compile(child);
|
||||
} catch (Exception e) {
|
||||
notifier.fireTestFailure(new Failure(description, e));
|
||||
notifier.fireTestFinished(description);
|
||||
|
@ -308,12 +333,11 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}
|
||||
|
||||
if (!compileResult.success) {
|
||||
notifier.fireTestFailure(new Failure(description,
|
||||
new AssertionError(compileResult.errorMessage)));
|
||||
notifier.fireTestFailure(new Failure(description, new AssertionError(compileResult.errorMessage)));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (runStrategy == null) {
|
||||
if (jsRunStrategy == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -330,36 +354,59 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}
|
||||
};
|
||||
|
||||
return new TestRun(compileResult.file.getParentFile(), child,
|
||||
new MethodReference(testClass.getName(), getDescriptor(child)),
|
||||
description, compileResult.file.getName(), callback);
|
||||
return new TestRun(compileResult.file.getParentFile(), child, description, compileResult.file.getName(),
|
||||
kind, callback);
|
||||
}
|
||||
|
||||
private void submitRun(TestRun run) {
|
||||
synchronized (TeaVMTestRunner.class) {
|
||||
if (runStrategy == null) {
|
||||
return;
|
||||
switch (run.getKind()) {
|
||||
case JAVASCRIPT:
|
||||
submitJavaScriptRun(run);
|
||||
break;
|
||||
case C:
|
||||
submitCRun(run);
|
||||
break;
|
||||
default:
|
||||
run.getCallback().complete();
|
||||
break;
|
||||
}
|
||||
|
||||
if (runner == null) {
|
||||
runner = new TestRunner(runStrategy);
|
||||
try {
|
||||
runner.setNumThreads(Integer.parseInt(System.getProperty(THREAD_COUNT, "1")));
|
||||
} catch (NumberFormatException e) {
|
||||
runner.setNumThreads(1);
|
||||
}
|
||||
runner.init();
|
||||
}
|
||||
runner.run(run);
|
||||
|
||||
if (cleanupFuture != null) {
|
||||
cleanupFuture.cancel(false);
|
||||
cleanupFuture = null;
|
||||
}
|
||||
cleanupFuture = executor.schedule(TeaVMTestRunner::cleanupRunner, stopTimeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void submitJavaScriptRun(TestRun run) {
|
||||
if (jsRunStrategy == null) {
|
||||
run.getCallback().complete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (runner == null) {
|
||||
runner = new TestRunner(jsRunStrategy);
|
||||
try {
|
||||
runner.setNumThreads(Integer.parseInt(System.getProperty(THREAD_COUNT, "1")));
|
||||
} catch (NumberFormatException e) {
|
||||
runner.setNumThreads(1);
|
||||
}
|
||||
runner.init();
|
||||
}
|
||||
runner.run(run);
|
||||
|
||||
if (cleanupFuture != null) {
|
||||
cleanupFuture.cancel(false);
|
||||
cleanupFuture = null;
|
||||
}
|
||||
cleanupFuture = executor.schedule(TeaVMTestRunner::cleanupRunner, stopTimeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void submitCRun(TestRun run) {
|
||||
if (cRunner == null) {
|
||||
run.getCallback().complete();
|
||||
return;
|
||||
}
|
||||
|
||||
cRunner.run(run);
|
||||
}
|
||||
|
||||
private static void cleanupRunner() {
|
||||
synchronized (TeaVMTestRunner.class) {
|
||||
cleanupFuture = null;
|
||||
|
@ -368,13 +415,39 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}
|
||||
}
|
||||
|
||||
private CompileResult compileTest(Method method, TeaVMTestConfiguration configuration) throws IOException {
|
||||
CompileResult result = new CompileResult();
|
||||
|
||||
private File getOutputPath(Method method) {
|
||||
File path = outputDir;
|
||||
path = new File(path, method.getDeclaringClass().getName().replace('.', '/'));
|
||||
path = new File(path, method.getName());
|
||||
path.mkdirs();
|
||||
return path;
|
||||
}
|
||||
|
||||
private void copyJsFilesTo(File path) throws IOException {
|
||||
resourceToFile("org/teavm/backend/javascript/runtime.js", new File(path, "runtime.js"));
|
||||
resourceToFile("teavm-run-test.html", new File(path, "run-test.html"));
|
||||
}
|
||||
|
||||
private CompileResult compileToJs(Method method, TeaVMTestConfiguration<JavaScriptTarget> configuration,
|
||||
File path) {
|
||||
return compileTest(method, configuration, JavaScriptTarget::new, vm -> {
|
||||
MethodReference exceptionMsg = new MethodReference(ExceptionHelper.class, "showException",
|
||||
Throwable.class, String.class);
|
||||
vm.entryPoint("runTest", new MethodReference(TestEntryPoint.class, "run", void.class)).async();
|
||||
vm.entryPoint("extractException", exceptionMsg);
|
||||
}, path, ".js");
|
||||
}
|
||||
|
||||
private CompileResult compileToC(Method method, TeaVMTestConfiguration<CTarget> configuration,
|
||||
File path) {
|
||||
return compileTest(method, configuration, CTarget::new, vm -> {
|
||||
vm.entryPoint("main", new MethodReference(TestEntryPoint.class, "main", String[].class, void.class));
|
||||
}, path, ".c");
|
||||
}
|
||||
|
||||
private <T extends TeaVMTarget> CompileResult compileTest(Method method, TeaVMTestConfiguration<T> configuration,
|
||||
Supplier<T> targetSupplier, Consumer<TeaVM> preBuild, File path, String extension) {
|
||||
CompileResult result = new CompileResult();
|
||||
|
||||
StringBuilder simpleName = new StringBuilder();
|
||||
simpleName.append("test");
|
||||
|
@ -382,23 +455,20 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
if (!suffix.isEmpty()) {
|
||||
simpleName.append('-').append(suffix);
|
||||
}
|
||||
simpleName.append(".js");
|
||||
simpleName.append(extension);
|
||||
File outputFile = new File(path, simpleName.toString());
|
||||
result.file = outputFile;
|
||||
|
||||
resourceToFile("org/teavm/backend/javascript/runtime.js", new File(path, "runtime.js"));
|
||||
resourceToFile("teavm-run-test.html", new File(path, "run-test.html"));
|
||||
|
||||
ClassLoader classLoader = TeaVMTestRunner.class.getClassLoader();
|
||||
ClassHolderSource classSource = getClassSource(classLoader);
|
||||
|
||||
MethodHolder methodHolder = classHolder.getMethod(getDescriptor(method));
|
||||
Class<?> runnerType = testAdapter.getRunner(methodHolder);
|
||||
|
||||
JavaScriptTarget jsTarget = new JavaScriptTarget();
|
||||
configuration.apply(jsTarget);
|
||||
T target = targetSupplier.get();
|
||||
configuration.apply(target);
|
||||
|
||||
TeaVM vm = new TeaVMBuilder(jsTarget)
|
||||
TeaVM vm = new TeaVMBuilder(target)
|
||||
.setClassLoader(classLoader)
|
||||
.setClassSource(classSource)
|
||||
.build();
|
||||
|
@ -414,10 +484,7 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
new TestExceptionPlugin().install(vm);
|
||||
new TestEntryPointTransformer(runnerType.getName(), methodHolder.getReference()).install(vm);
|
||||
|
||||
MethodReference exceptionMsg = new MethodReference(ExceptionHelper.class, "showException",
|
||||
Throwable.class, String.class);
|
||||
vm.entryPoint("runTest", new MethodReference(TestEntryPoint.class, "run", void.class)).async();
|
||||
vm.entryPoint("extractException", exceptionMsg);
|
||||
preBuild.accept(vm);
|
||||
vm.build(new DirectoryBuildTarget(outputFile.getParentFile()), outputFile.getName());
|
||||
if (!vm.getProblemProvider().getProblems().isEmpty()) {
|
||||
result.success = false;
|
||||
|
@ -427,14 +494,25 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
return result;
|
||||
}
|
||||
|
||||
private List<TeaVMTestConfiguration> getConfigurations() {
|
||||
List<TeaVMTestConfiguration> configurations = new ArrayList<>();
|
||||
configurations.add(TeaVMTestConfiguration.DEFAULT);
|
||||
if (Boolean.parseBoolean(System.getProperty("teavm.junit.minified", "false"))) {
|
||||
configurations.add(TeaVMTestConfiguration.MINIFIED);
|
||||
private List<TeaVMTestConfiguration<JavaScriptTarget>> getJavaScriptConfigurations() {
|
||||
List<TeaVMTestConfiguration<JavaScriptTarget>> configurations = new ArrayList<>();
|
||||
configurations.add(TeaVMTestConfiguration.JS_DEFAULT);
|
||||
if (Boolean.getBoolean(MINIFIED)) {
|
||||
configurations.add(TeaVMTestConfiguration.JS_MINIFIED);
|
||||
}
|
||||
if (Boolean.parseBoolean(System.getProperty("teavm.junit.optimized", "false"))) {
|
||||
configurations.add(TeaVMTestConfiguration.OPTIMIZED);
|
||||
if (Boolean.getBoolean(OPTIMIZED)) {
|
||||
configurations.add(TeaVMTestConfiguration.JS_OPTIMIZED);
|
||||
}
|
||||
return configurations;
|
||||
}
|
||||
|
||||
private List<TeaVMTestConfiguration<CTarget>> getCConfigurations() {
|
||||
List<TeaVMTestConfiguration<CTarget>> configurations = new ArrayList<>();
|
||||
if (Boolean.getBoolean(C_ENABLED)) {
|
||||
configurations.add(TeaVMTestConfiguration.C_DEFAULT);
|
||||
if (Boolean.getBoolean(OPTIMIZED)) {
|
||||
configurations.add(TeaVMTestConfiguration.C_OPTIMIZED);
|
||||
}
|
||||
}
|
||||
return configurations;
|
||||
}
|
||||
|
@ -501,4 +579,8 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
String errorMessage;
|
||||
File file;
|
||||
}
|
||||
|
||||
interface CompileFunction {
|
||||
CompileResult compile(Method method);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,4 +32,13 @@ final class TestEntryPoint {
|
|||
private static native void launchTest();
|
||||
|
||||
private static native boolean isExpectedException(Class<?> cls);
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
run();
|
||||
System.out.println("SUCCESS");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,24 +18,23 @@ package org.teavm.junit;
|
|||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import org.junit.runner.Description;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
class TestRun {
|
||||
private File baseDirectory;
|
||||
private Method method;
|
||||
private MethodReference reference;
|
||||
private Description description;
|
||||
private TestRunCallback callback;
|
||||
private String fileName;
|
||||
private RunKind kind;
|
||||
private TestRunCallback callback;
|
||||
|
||||
TestRun(File baseDirectory, Method method, MethodReference reference, Description description, String fileName,
|
||||
TestRun(File baseDirectory, Method method, Description description, String fileName, RunKind kind,
|
||||
TestRunCallback callback) {
|
||||
this.baseDirectory = baseDirectory;
|
||||
this.method = method;
|
||||
this.reference = reference;
|
||||
this.description = description;
|
||||
this.callback = callback;
|
||||
this.fileName = fileName;
|
||||
this.kind = kind;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public File getBaseDirectory() {
|
||||
|
@ -46,19 +45,19 @@ class TestRun {
|
|||
return method;
|
||||
}
|
||||
|
||||
public MethodReference getReference() {
|
||||
return reference;
|
||||
}
|
||||
|
||||
public Description getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public TestRunCallback getCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public RunKind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
public TestRunCallback getCallback() {
|
||||
return callback;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user