mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Improving JUnit test runner
This commit is contained in:
parent
c808f41a8f
commit
5576275998
|
@ -13,7 +13,7 @@
|
|||
<option name="MAIN_CLASS_NAME" value="" />
|
||||
<option name="METHOD_NAME" value="" />
|
||||
<option name="TEST_OBJECT" value="package" />
|
||||
<option name="VM_PARAMETERS" value="-ea -Dteavm.junit.target=target/js-tests" />
|
||||
<option name="VM_PARAMETERS" value="-ea -Dteavm.junit.target=target/js-tests -Dteavm.junit.js.runner=htmlunit -Dteavm.junit.js.threads=2" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$MODULE_DIR$" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.teavm.classlib.impl.tz.DateTimeZone;
|
|||
import org.teavm.classlib.impl.tz.DateTimeZoneProvider;
|
||||
import org.teavm.classlib.impl.tz.FixedDateTimeZone;
|
||||
import org.teavm.classlib.impl.unicode.CLDRHelper;
|
||||
import org.teavm.classlib.java.lang.TThreadInterruptHandler;
|
||||
|
||||
/**
|
||||
* {@code TimeZone} represents a time zone offset, taking into account
|
||||
|
@ -152,7 +153,8 @@ public abstract class TTimeZone implements Serializable, Cloneable {
|
|||
*/
|
||||
public static TTimeZone getDefault() {
|
||||
if (defaultTz == null) {
|
||||
defaultTz = new TIANATimeZone(DateTimeZoneProvider.detectTimezone());
|
||||
//defaultTz = new TIANATimeZone(DateTimeZoneProvider.detectTimezone());
|
||||
defaultTz = TTimeZone.getTimeZone("UTC");
|
||||
}
|
||||
return (TTimeZone) defaultTz.clone();
|
||||
}
|
||||
|
|
|
@ -15,14 +15,6 @@
|
|||
*/
|
||||
package org.teavm.classlib.java.util;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.teavm.junit.TeaVMTestRunner;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
@RunWith(TeaVMTestRunner.class)
|
||||
public interface TestService {
|
||||
void foo();
|
||||
}
|
||||
|
|
|
@ -52,24 +52,24 @@
|
|||
<orderEntry type="library" scope="TEST" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.6.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.6.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: com.fasterxml.jackson.core:jackson-core:2.6.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.sourceforge.htmlunit:htmlunit:2.18" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.sourceforge.htmlunit:htmlunit:2.19" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: xalan:xalan:2.7.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: xalan:serializer:2.7.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: commons-collections:commons-collections:3.2.1" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.apache.commons:commons-lang3:3.4" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.apache.httpcomponents:httpmime:4.5" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.apache.httpcomponents:httpmime:4.5.1" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: commons-codec:commons-codec:1.10" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.sourceforge.htmlunit:htmlunit-core-js:2.17" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: xerces:xercesImpl:2.11.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: xml-apis:xml-apis:1.4.01" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.sourceforge.nekohtml:nekohtml:1.9.22" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.sourceforge.cssparser:cssparser:0.9.16" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.sourceforge.cssparser:cssparser:0.9.18" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.w3c.css:sac:1.3" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: commons-logging:commons-logging:1.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.2.12.v20150709" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty:jetty-util:9.2.12.v20150709" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty:jetty-io:9.2.12.v20150709" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.2.12.v20150709" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.2.12.v20150709" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.2.13.v20150730" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty:jetty-util:9.2.13.v20150730" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty:jetty-io:9.2.13.v20150730" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.2.13.v20150730" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.2.13.v20150730" level="project" />
|
||||
</component>
|
||||
</module>
|
|
@ -1,215 +0,0 @@
|
|||
/*
|
||||
* Copyright 2014 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.cli;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.OptionBuilder;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.cli.PosixParser;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.testing.TestAdapter;
|
||||
import org.teavm.tooling.TeaVMToolException;
|
||||
import org.teavm.tooling.testing.TeaVMTestTool;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public final class TeaVMTestRunner {
|
||||
private TeaVMTestRunner() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("static-access")
|
||||
public static void main(String[] args) {
|
||||
Options options = new Options();
|
||||
options.addOption(OptionBuilder
|
||||
.withArgName("directory")
|
||||
.hasArg()
|
||||
.withDescription("a directory where to put generated files (current directory by default)")
|
||||
.withLongOpt("targetdir")
|
||||
.create('d'));
|
||||
options.addOption(OptionBuilder
|
||||
.withDescription("causes TeaVM to generate minimized JavaScript file")
|
||||
.withLongOpt("minify")
|
||||
.create("m"));
|
||||
options.addOption(OptionBuilder
|
||||
.withArgName("number")
|
||||
.hasArg()
|
||||
.withDescription("how many threads should TeaVM run")
|
||||
.withLongOpt("threads")
|
||||
.create("t"));
|
||||
options.addOption(OptionBuilder
|
||||
.withArgName("class name")
|
||||
.hasArg()
|
||||
.withDescription("qualified class name of test adapter")
|
||||
.withLongOpt("adapter")
|
||||
.create("a"));
|
||||
options.addOption(OptionBuilder
|
||||
.hasArg()
|
||||
.hasOptionalArgs()
|
||||
.withArgName("class name")
|
||||
.withDescription("qualified class names of transformers")
|
||||
.withLongOpt("transformers")
|
||||
.create("T"));
|
||||
options.addOption(OptionBuilder
|
||||
.withDescription("Incremental build")
|
||||
.withLongOpt("incremental")
|
||||
.create('i'));
|
||||
|
||||
if (args.length == 0) {
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
CommandLineParser parser = new PosixParser();
|
||||
CommandLine commandLine;
|
||||
try {
|
||||
commandLine = parser.parse(options, args);
|
||||
} catch (ParseException e) {
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
|
||||
TeaVMTestTool tool = new TeaVMTestTool();
|
||||
tool.setTargetDirectory(new File(commandLine.getOptionValue("d", ".")));
|
||||
tool.setMinifying(commandLine.hasOption("m"));
|
||||
try {
|
||||
tool.setNumThreads(Integer.parseInt(commandLine.getOptionValue("t", "1")));
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Invalid number specified for -t option");
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
if (commandLine.hasOption("a")) {
|
||||
tool.setAdapter(instantiateAdapter(commandLine.getOptionValue("a")));
|
||||
}
|
||||
if (commandLine.hasOption("T")) {
|
||||
for (String transformerType : commandLine.getOptionValues("T")) {
|
||||
tool.getTransformers().add(instantiateTransformer(transformerType));
|
||||
}
|
||||
}
|
||||
if (commandLine.hasOption('i')) {
|
||||
tool.setIncremental(true);
|
||||
}
|
||||
|
||||
args = commandLine.getArgs();
|
||||
if (args.length == 0) {
|
||||
System.err.println("You did not specify any test classes");
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
tool.getTestClasses().addAll(Arrays.asList(args));
|
||||
|
||||
tool.setLog(new ConsoleTeaVMToolLog());
|
||||
tool.getProperties().putAll(System.getProperties());
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
tool.generate();
|
||||
} catch (TeaVMToolException e) {
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(-2);
|
||||
}
|
||||
System.out.println("Operation took " + (System.currentTimeMillis() - start) + " milliseconds");
|
||||
}
|
||||
|
||||
private static TestAdapter instantiateAdapter(String adapterName) {
|
||||
Class<?> adapterClass;
|
||||
try {
|
||||
adapterClass = Class.forName(adapterName, true, TeaVMTestRunner.class.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.err.println("Adapter not found: " + adapterName);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
if (!TestAdapter.class.isAssignableFrom(adapterClass)) {
|
||||
System.err.println("Adapter class does not implement TestAdapter: " + adapterName);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
Constructor<?> cons;
|
||||
try {
|
||||
cons = adapterClass.getConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
System.err.println("Adapter class does not contain no-arg constructor: " + adapterName);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return (TestAdapter) cons.newInstance();
|
||||
} catch (IllegalAccessException | InstantiationException e) {
|
||||
System.err.println("Error instantiating adapter: " + adapterName);
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
} catch (InvocationTargetException e) {
|
||||
System.err.println("Error instantiating adapter: " + adapterName);
|
||||
e.getTargetException().printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static ClassHolderTransformer instantiateTransformer(String transformerName) {
|
||||
Class<?> adapterClass;
|
||||
try {
|
||||
adapterClass = Class.forName(transformerName, true, TeaVMTestRunner.class.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.err.println("Transformer not found: " + transformerName);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
if (!ClassHolderTransformer.class.isAssignableFrom(adapterClass)) {
|
||||
System.err.println("Transformer class does not implement ClassHolderTransformer: " + transformerName);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
Constructor<?> cons;
|
||||
try {
|
||||
cons = adapterClass.getConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
System.err.println("Transformer class does not contain no-arg constructor: " + transformerName);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return (ClassHolderTransformer) cons.newInstance();
|
||||
} catch (IllegalAccessException | InstantiationException e) {
|
||||
System.err.println("Error instantiating transformer: " + transformerName);
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
} catch (InvocationTargetException e) {
|
||||
System.err.println("Error instantiating transformer: " + transformerName);
|
||||
e.getTargetException().printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void printUsage(Options options) {
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp("java " + TeaVMTestRunner.class.getName() + " [OPTIONS] test_name {test_name}", options);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
|
@ -53,7 +53,7 @@
|
|||
<dependency>
|
||||
<groupId>net.sourceforge.htmlunit</groupId>
|
||||
<artifactId>htmlunit</artifactId>
|
||||
<version>2.18</version>
|
||||
<version>2.19</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -15,10 +15,6 @@
|
|||
*/
|
||||
package org.teavm.junit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
final class ExceptionHelper {
|
||||
private ExceptionHelper() {
|
||||
}
|
||||
|
|
|
@ -29,33 +29,56 @@ import net.sourceforge.htmlunit.corejs.javascript.Function;
|
|||
import net.sourceforge.htmlunit.corejs.javascript.NativeJavaObject;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
public class HtmlUnitRunStrategy implements TestRunStrategy {
|
||||
class HtmlUnitRunStrategy implements TestRunStrategy {
|
||||
private ThreadLocal<WebClient> webClient = new ThreadLocal<>();
|
||||
private ThreadLocal<HtmlPage> page = new ThreadLocal<>();
|
||||
private int runs;
|
||||
|
||||
@Override
|
||||
public void beforeThread() {
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterThread() {
|
||||
cleanUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String runTest(TestRun run) throws IOException {
|
||||
try (WebClient webClient = new WebClient(BrowserVersion.CHROME)) {
|
||||
HtmlPage page = webClient.getPage("about:blank");
|
||||
page.executeJavaScript(readFile(new File(run.getBaseDirectory(), "runtime.js")));
|
||||
if (++runs == 50) {
|
||||
runs = 0;
|
||||
cleanUp();
|
||||
init();
|
||||
}
|
||||
|
||||
page.get().executeJavaScript(readFile(new File(run.getBaseDirectory(), "runtime.js")));
|
||||
page.get().executeJavaScript(readFile(new File(run.getBaseDirectory(), "test.js")));
|
||||
|
||||
AsyncResult asyncResult = new AsyncResult();
|
||||
Function function = (Function) page.executeJavaScript(readResource("teavm-htmlunit-adapter.js"))
|
||||
Function function = (Function) page.get().executeJavaScript(readResource("teavm-htmlunit-adapter.js"))
|
||||
.getJavaScriptResult();
|
||||
Object[] args = new Object[] { new NativeJavaObject(function, asyncResult, AsyncResult.class) };
|
||||
page.executeJavaScriptFunctionIfPossible(function, function, args, page);
|
||||
page.get().executeJavaScriptFunctionIfPossible(function, function, args, page.get());
|
||||
return (String) asyncResult.getResult();
|
||||
}
|
||||
|
||||
page.executeJavaScript(readFile(new File(run.getBaseDirectory(), "test.js")));
|
||||
page.cleanUp();
|
||||
for (WebWindow window : webClient.getWebWindows()) {
|
||||
private void cleanUp() {
|
||||
page.get().cleanUp();
|
||||
for (WebWindow window : webClient.get().getWebWindows()) {
|
||||
window.getJobManager().removeAllJobs();
|
||||
}
|
||||
return (String) asyncResult.getResult();
|
||||
page.remove();
|
||||
webClient.get().close();
|
||||
webClient.remove();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
webClient.set(new WebClient(BrowserVersion.CHROME));
|
||||
try {
|
||||
page.set(webClient.get().getPage("about:blank"));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,10 +28,11 @@ import org.openqa.selenium.WebDriver;
|
|||
import org.openqa.selenium.remote.DesiredCapabilities;
|
||||
import org.openqa.selenium.remote.RemoteWebDriver;
|
||||
|
||||
public class SeleniumRunStrategy implements TestRunStrategy {
|
||||
class SeleniumRunStrategy implements TestRunStrategy {
|
||||
private URL url;
|
||||
private ThreadLocal<WebDriver> webDriver = new ThreadLocal<>();
|
||||
private ThreadLocal<Integer> commandsSent = new ThreadLocal<>();
|
||||
private int rebootRate = Integer.getInteger("teavm.junit.js.selenium.rebootAfter", 1000);
|
||||
|
||||
public SeleniumRunStrategy(URL url) {
|
||||
this.url = url;
|
||||
|
@ -54,7 +55,7 @@ public class SeleniumRunStrategy implements TestRunStrategy {
|
|||
@Override
|
||||
public String runTest(TestRun run) throws IOException {
|
||||
commandsSent.set(commandsSent.get() + 1);
|
||||
if (commandsSent.get().equals(20)) {
|
||||
if (commandsSent.get().equals(100)) {
|
||||
commandsSent.set(0);
|
||||
webDriver.get().close();
|
||||
webDriver.get().quit();
|
||||
|
|
|
@ -66,6 +66,7 @@ import org.teavm.vm.TeaVMBuilder;
|
|||
public class TeaVMTestRunner extends Runner {
|
||||
private static final String PATH_PARAM = "teavm.junit.target";
|
||||
private static final String 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 int stopTimeout = 15000;
|
||||
private Class<?> testClass;
|
||||
|
@ -83,6 +84,16 @@ public class TeaVMTestRunner extends Runner {
|
|||
private static volatile ScheduledFuture<?> cleanupFuture;
|
||||
private CountDownLatch latch;
|
||||
|
||||
static {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
synchronized (TeaVMTestRunner.class) {
|
||||
cleanupFuture = null;
|
||||
runner.stop();
|
||||
runner.waitForCompletion();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public TeaVMTestRunner(Class<?> testClass) throws InitializationError {
|
||||
this.testClass = testClass;
|
||||
classLoader = TeaVMTestRunner.class.getClassLoader();
|
||||
|
@ -167,14 +178,27 @@ public class TeaVMTestRunner extends Runner {
|
|||
boolean run = false;
|
||||
boolean success = true;
|
||||
|
||||
MethodHolder methodHolder = classHolder.getMethod(getDescriptor(child));
|
||||
Set<Class<?>> expectedExceptions = new HashSet<>();
|
||||
for (String exceptionName : testAdapter.getExpectedExceptions(methodHolder)) {
|
||||
try {
|
||||
expectedExceptions.add(Class.forName(exceptionName, false, classLoader));
|
||||
} catch (ClassNotFoundException e) {
|
||||
notifier.fireTestFailure(new Failure(describeChild(child), e));
|
||||
notifier.fireTestFinished(describeChild(child));
|
||||
latch.countDown();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!child.isAnnotationPresent(SkipJVM.class)
|
||||
&& !child.getDeclaringClass().isAnnotationPresent(SkipJVM.class)) {
|
||||
run = true;
|
||||
success = runInJvm(child, notifier);
|
||||
success = runInJvm(child, notifier, expectedExceptions);
|
||||
}
|
||||
|
||||
if (success && outputDir != null) {
|
||||
runInTeaVM(child, notifier);
|
||||
runInTeaVM(child, notifier, expectedExceptions);
|
||||
} else {
|
||||
if (!run) {
|
||||
notifier.fireTestIgnored(describeChild(child));
|
||||
|
@ -184,18 +208,7 @@ public class TeaVMTestRunner extends Runner {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean runInJvm(Method child, RunNotifier notifier) {
|
||||
MethodHolder methodHolder = classHolder.getMethod(getDescriptor(child));
|
||||
Set<Class<?>> expectedExceptions = new HashSet<>();
|
||||
for (String exceptionName : testAdapter.getExpectedExceptions(methodHolder)) {
|
||||
try {
|
||||
expectedExceptions.add(Class.forName(exceptionName, false, classLoader));
|
||||
} catch (ClassNotFoundException e) {
|
||||
notifier.fireTestFailure(new Failure(describeChild(child), e));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean runInJvm(Method child, RunNotifier notifier, Set<Class<?>> expectedExceptions) {
|
||||
Object instance;
|
||||
try {
|
||||
instance = testClass.newInstance();
|
||||
|
@ -233,22 +246,29 @@ public class TeaVMTestRunner extends Runner {
|
|||
return true;
|
||||
}
|
||||
|
||||
private boolean runInTeaVM(Method child, RunNotifier notifier) {
|
||||
private boolean runInTeaVM(Method child, RunNotifier notifier, Set<Class<?>> expectedExceptions) {
|
||||
Description description = describeChild(child);
|
||||
|
||||
CompileResult compileResult;
|
||||
try {
|
||||
compileResult = compileTest(child);
|
||||
} catch (IOException e) {
|
||||
notifier.fireTestFailure(new Failure(describeChild(child), e));
|
||||
notifier.fireTestFailure(new Failure(description, e));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!compileResult.success) {
|
||||
notifier.fireTestFailure(new Failure(describeChild(child),
|
||||
notifier.fireTestFailure(new Failure(description,
|
||||
new AssertionError(compileResult.errorMessage)));
|
||||
return false;
|
||||
}
|
||||
|
||||
Description description = describeChild(child);
|
||||
if (runStrategy == null) {
|
||||
notifier.fireTestFinished(description);
|
||||
latch.countDown();
|
||||
return true;
|
||||
}
|
||||
|
||||
TestRunCallback callback = new TestRunCallback() {
|
||||
@Override
|
||||
public void complete() {
|
||||
|
@ -264,7 +284,7 @@ public class TeaVMTestRunner extends Runner {
|
|||
|
||||
TestRun run = new TestRun(compileResult.file.getParentFile(), child,
|
||||
new MethodReference(testClass.getName(), getDescriptor(child)),
|
||||
description, callback);
|
||||
description, callback, expectedExceptions);
|
||||
submitRun(run);
|
||||
return true;
|
||||
}
|
||||
|
@ -277,6 +297,11 @@ public class TeaVMTestRunner extends Runner {
|
|||
|
||||
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);
|
||||
|
|
|
@ -17,23 +17,28 @@ package org.teavm.junit;
|
|||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.junit.runner.Description;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class TestRun {
|
||||
class TestRun {
|
||||
private File baseDirectory;
|
||||
private Method method;
|
||||
private MethodReference reference;
|
||||
private Description description;
|
||||
private TestRunCallback callback;
|
||||
private Set<Class<?>> expectedExceptions;
|
||||
|
||||
public TestRun(File baseDirectory, Method method, MethodReference reference, Description description,
|
||||
TestRunCallback callback) {
|
||||
TestRun(File baseDirectory, Method method, MethodReference reference, Description description,
|
||||
TestRunCallback callback, Set<Class<?>> expectedExceptions) {
|
||||
this.baseDirectory = baseDirectory;
|
||||
this.method = method;
|
||||
this.reference = reference;
|
||||
this.description = description;
|
||||
this.callback = callback;
|
||||
this.expectedExceptions = Collections.unmodifiableSet(new HashSet<>(expectedExceptions));
|
||||
}
|
||||
|
||||
public File getBaseDirectory() {
|
||||
|
@ -55,4 +60,8 @@ public class TestRun {
|
|||
public TestRunCallback getCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
public Set<Class<?>> getExpectedExceptions() {
|
||||
return expectedExceptions;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package org.teavm.junit;
|
||||
|
||||
public interface TestRunCallback {
|
||||
interface TestRunCallback {
|
||||
void complete();
|
||||
|
||||
void error(Throwable e);
|
||||
|
|
|
@ -17,7 +17,7 @@ package org.teavm.junit;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface TestRunStrategy {
|
||||
interface TestRunStrategy {
|
||||
void beforeThread();
|
||||
|
||||
void afterThread();
|
||||
|
|
|
@ -22,18 +22,15 @@ import java.util.concurrent.BlockingQueue;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.runner.notification.Failure;
|
||||
import org.junit.runner.notification.RunNotifier;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class TestRunner {
|
||||
class TestRunner {
|
||||
private int numThreads = 1;
|
||||
private TestRunStrategy strategy;
|
||||
private BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
|
||||
private CountDownLatch latch;
|
||||
private volatile boolean stopped;
|
||||
|
||||
public TestRunner(TestRunStrategy strategy) {
|
||||
TestRunner(TestRunStrategy strategy) {
|
||||
this.strategy = strategy;
|
||||
}
|
||||
|
||||
|
@ -73,7 +70,19 @@ public class TestRunner {
|
|||
|
||||
public void stop() {
|
||||
stopped = true;
|
||||
taskQueue.add(null);
|
||||
taskQueue.add(() -> { });
|
||||
}
|
||||
|
||||
public void waitForCompletion() {
|
||||
while (true) {
|
||||
try {
|
||||
if (latch.await(1000, TimeUnit.MILLISECONDS)) {
|
||||
break;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run(TestRun run) {
|
||||
|
@ -81,7 +90,6 @@ public class TestRunner {
|
|||
}
|
||||
|
||||
private void runImpl(TestRun run) {
|
||||
MethodReference ref = run.getReference();
|
||||
try {
|
||||
String result = strategy.runTest(run);
|
||||
if (result == null) {
|
||||
|
@ -93,17 +101,38 @@ public class TestRunner {
|
|||
String status = resultObject.get("status").asText();
|
||||
switch (status) {
|
||||
case "ok":
|
||||
if (!run.getExpectedExceptions().isEmpty()) {
|
||||
run.getCallback().error(new AssertionError("Expected exception was not thrown"));
|
||||
} else {
|
||||
run.getCallback().complete();
|
||||
}
|
||||
break;
|
||||
case "exception": {
|
||||
String stack = resultObject.get("stack").asText();
|
||||
String exception = resultObject.get("exception").asText();
|
||||
run.getCallback().error(new AssertionError(exception + "\n" + exception));
|
||||
String exception = resultObject.has("exception") ? resultObject.get("exception").asText() : null;
|
||||
Class<?> exceptionClass;
|
||||
if (exception != null) {
|
||||
try {
|
||||
exceptionClass = Class.forName(exception, false, TestRunner.class.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
exceptionClass = null;
|
||||
}
|
||||
} else {
|
||||
exceptionClass = null;
|
||||
}
|
||||
if (exceptionClass != null) {
|
||||
Class<?> caught = exceptionClass;
|
||||
if (run.getExpectedExceptions().stream().anyMatch(e -> e.isAssignableFrom(caught))) {
|
||||
run.getCallback().complete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
run.getCallback().error(new AssertionError(exception + "\n" + stack));
|
||||
run.getCallback().complete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
run.getCallback().error(e);
|
||||
run.getCallback().complete();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
function main(callback) {
|
||||
var JUnitClient = {};
|
||||
JUnitClient.run = function() {
|
||||
$rt_startThread(function () {
|
||||
var thread = $rt_nativeThread();
|
||||
var instance;
|
||||
|
@ -10,13 +8,14 @@ function main(callback) {
|
|||
ptr = thread.pop();
|
||||
instance = thread.pop();
|
||||
}
|
||||
loop: while (true) { switch (ptr) {
|
||||
loop: while (true) {
|
||||
switch (ptr) {
|
||||
case 0:
|
||||
try {
|
||||
runTest();
|
||||
} catch (e) {
|
||||
message = {};
|
||||
JUnitClient.makeErrorMessage(message, e);
|
||||
makeErrorMessage(message, e);
|
||||
break loop;
|
||||
}
|
||||
if (thread.isSuspending()) {
|
||||
|
@ -27,12 +26,12 @@ function main(callback) {
|
|||
message = {};
|
||||
message.status = "ok";
|
||||
break loop;
|
||||
}}
|
||||
}
|
||||
}
|
||||
callback.complete(JSON.stringify(message));
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
JUnitClient.makeErrorMessage = function(message, e) {
|
||||
function makeErrorMessage(message, e) {
|
||||
message.status = "exception";
|
||||
var stack = e.stack;
|
||||
if (e.$javaException && e.$javaException.constructor.$meta) {
|
||||
|
@ -42,7 +41,5 @@ function main(callback) {
|
|||
message.stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
|
||||
}
|
||||
message.stack += "\n" + stack;
|
||||
};
|
||||
|
||||
window.JUnitClient = JUnitClient;
|
||||
}
|
||||
}
|
|
@ -29,7 +29,7 @@ $rt_startThread(function() {
|
|||
runTest();
|
||||
} catch (e) {
|
||||
message = {};
|
||||
JUnitClient.makeErrorMessage(message, e);
|
||||
makeErrorMessage(message, e);
|
||||
break loop;
|
||||
}
|
||||
if (thread.isSuspending()) {
|
||||
|
|
|
@ -41,25 +41,25 @@
|
|||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.6.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.6.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.6.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.sourceforge.htmlunit:htmlunit:2.18" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.sourceforge.htmlunit:htmlunit:2.19" level="project" />
|
||||
<orderEntry type="library" name="Maven: xalan:xalan:2.7.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: xalan:serializer:2.7.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpmime:4.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpmime:4.5.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.10" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.sourceforge.htmlunit:htmlunit-core-js:2.17" level="project" />
|
||||
<orderEntry type="library" name="Maven: xerces:xercesImpl:2.11.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: xml-apis:xml-apis:1.4.01" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.sourceforge.nekohtml:nekohtml:1.9.22" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.sourceforge.cssparser:cssparser:0.9.16" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.sourceforge.cssparser:cssparser:0.9.18" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.w3c.css:sac:1.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.2.12.v20150709" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-util:9.2.12.v20150709" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-io:9.2.12.v20150709" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.2.12.v20150709" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.2.12.v20150709" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.2.13.v20150730" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-util:9.2.13.v20150730" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-io:9.2.13.v20150730" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.2.13.v20150730" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.2.13.v20150730" level="project" />
|
||||
</component>
|
||||
</module>
|
Loading…
Reference in New Issue
Block a user