diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TThrowable.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TThrowable.java index d8e2debf3..b1d80f812 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TThrowable.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TThrowable.java @@ -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); } } diff --git a/core/src/main/java/org/teavm/backend/c/CTarget.java b/core/src/main/java/org/teavm/backend/c/CTarget.java index fce405d98..12a2b7f4a 100644 --- a/core/src/main/java/org/teavm/backend/c/CTarget.java +++ b/core/src/main/java/org/teavm/backend/c/CTarget.java @@ -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); diff --git a/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java b/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java index f34397491..bd4fff17d 100644 --- a/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java +++ b/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java @@ -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); diff --git a/tools/junit/src/main/java/org/teavm/junit/CRunner.java b/tools/junit/src/main/java/org/teavm/junit/CRunner.java new file mode 100644 index 000000000..3893c80b9 --- /dev/null +++ b/tools/junit/src/main/java/org/teavm/junit/CRunner.java @@ -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 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 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 lines) { + StringBuilder sb = new StringBuilder(); + for (String line : lines) { + sb.append(line).append('\n'); + } + return sb.toString(); + } + + private void writeLines(List lines) { + for (String line : lines) { + System.out.println(line); + } + } + + private boolean runCompiler(File inputFile, File outputFile, List 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 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; + } +} diff --git a/tools/junit/src/main/java/org/teavm/junit/HtmlUnitRunStrategy.java b/tools/junit/src/main/java/org/teavm/junit/HtmlUnitRunStrategy.java index 293edca05..d734fa213 100644 --- a/tools/junit/src/main/java/org/teavm/junit/HtmlUnitRunStrategy.java +++ b/tools/junit/src/main/java/org/teavm/junit/HtmlUnitRunStrategy.java @@ -54,7 +54,7 @@ class HtmlUnitRunStrategy implements TestRunStrategy { } try { - page.set(webClient.get().getPage("about:blank")); + page.set(webClient.get().getPage("about:blank")); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/tools/junit/src/main/java/org/teavm/junit/RunKind.java b/tools/junit/src/main/java/org/teavm/junit/RunKind.java new file mode 100644 index 000000000..ea7ebd316 --- /dev/null +++ b/tools/junit/src/main/java/org/teavm/junit/RunKind.java @@ -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 +} diff --git a/tools/junit/src/main/java/org/teavm/junit/TeaVMTestConfiguration.java b/tools/junit/src/main/java/org/teavm/junit/TeaVMTestConfiguration.java index 98c0731ee..14527d005 100644 --- a/tools/junit/src/main/java/org/teavm/junit/TeaVMTestConfiguration.java +++ b/tools/junit/src/main/java/org/teavm/junit/TeaVMTestConfiguration.java @@ -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 { String getSuffix(); void apply(TeaVM vm); - void apply(JavaScriptTarget target); + void apply(T target); - TeaVMTestConfiguration DEFAULT = new TeaVMTestConfiguration() { + TeaVMTestConfiguration JS_DEFAULT = new TeaVMTestConfiguration() { @Override public String getSuffix() { return ""; @@ -43,7 +45,7 @@ interface TeaVMTestConfiguration { } }; - TeaVMTestConfiguration OPTIMIZED = new TeaVMTestConfiguration() { + TeaVMTestConfiguration JS_OPTIMIZED = new TeaVMTestConfiguration() { @Override public String getSuffix() { return "optimized"; @@ -60,7 +62,7 @@ interface TeaVMTestConfiguration { } }; - TeaVMTestConfiguration MINIFIED = new TeaVMTestConfiguration() { + TeaVMTestConfiguration JS_MINIFIED = new TeaVMTestConfiguration() { @Override public String getSuffix() { return "min"; @@ -76,4 +78,37 @@ interface TeaVMTestConfiguration { target.setMinifying(true); } }; + + TeaVMTestConfiguration C_DEFAULT = new TeaVMTestConfiguration() { + @Override + public String getSuffix() { + return ""; + } + + @Override + public void apply(TeaVM vm) { + vm.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE); + } + + @Override + public void apply(CTarget target) { + } + }; + + + TeaVMTestConfiguration C_OPTIMIZED = new TeaVMTestConfiguration() { + @Override + public String getSuffix() { + return ""; + } + + @Override + public void apply(TeaVM vm) { + vm.setOptimizationLevel(TeaVMOptimizationLevel.FULL); + } + + @Override + public void apply(CTarget target) { + } + }; } diff --git a/tools/junit/src/main/java/org/teavm/junit/TeaVMTestRunner.java b/tools/junit/src/main/java/org/teavm/junit/TeaVMTestRunner.java index 5f6e80442..3134d5922 100644 --- a/tools/junit/src/main/java/org/teavm/junit/TeaVMTestRunner.java +++ b/tools/junit/src/main/java/org/teavm/junit/TeaVMTestRunner.java @@ -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 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 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 configurations = getConfigurations(); int[] configurationIndex = new int[] { 0 }; List> 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 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 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 onComplete) { + private TestRun compile(Method child, RunNotifier notifier, RunKind kind, + CompileFunction compiler, Consumer 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 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 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 CompileResult compileTest(Method method, TeaVMTestConfiguration configuration, + Supplier targetSupplier, Consumer 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 getConfigurations() { - List configurations = new ArrayList<>(); - configurations.add(TeaVMTestConfiguration.DEFAULT); - if (Boolean.parseBoolean(System.getProperty("teavm.junit.minified", "false"))) { - configurations.add(TeaVMTestConfiguration.MINIFIED); + private List> getJavaScriptConfigurations() { + List> 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> getCConfigurations() { + List> 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); + } } diff --git a/tools/junit/src/main/java/org/teavm/junit/TestEntryPoint.java b/tools/junit/src/main/java/org/teavm/junit/TestEntryPoint.java index 1f5fd4a44..7eec252bc 100644 --- a/tools/junit/src/main/java/org/teavm/junit/TestEntryPoint.java +++ b/tools/junit/src/main/java/org/teavm/junit/TestEntryPoint.java @@ -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); + } + } } diff --git a/tools/junit/src/main/java/org/teavm/junit/TestRun.java b/tools/junit/src/main/java/org/teavm/junit/TestRun.java index 0e6526a00..88f8b9feb 100644 --- a/tools/junit/src/main/java/org/teavm/junit/TestRun.java +++ b/tools/junit/src/main/java/org/teavm/junit/TestRun.java @@ -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; + } }