mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -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="MAIN_CLASS_NAME" value="" />
|
||||||
<option name="METHOD_NAME" value="" />
|
<option name="METHOD_NAME" value="" />
|
||||||
<option name="TEST_OBJECT" value="package" />
|
<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="PARAMETERS" value="" />
|
||||||
<option name="WORKING_DIRECTORY" value="file://$MODULE_DIR$" />
|
<option name="WORKING_DIRECTORY" value="file://$MODULE_DIR$" />
|
||||||
<option name="ENV_VARIABLES" />
|
<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.DateTimeZoneProvider;
|
||||||
import org.teavm.classlib.impl.tz.FixedDateTimeZone;
|
import org.teavm.classlib.impl.tz.FixedDateTimeZone;
|
||||||
import org.teavm.classlib.impl.unicode.CLDRHelper;
|
import org.teavm.classlib.impl.unicode.CLDRHelper;
|
||||||
|
import org.teavm.classlib.java.lang.TThreadInterruptHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code TimeZone} represents a time zone offset, taking into account
|
* {@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() {
|
public static TTimeZone getDefault() {
|
||||||
if (defaultTz == null) {
|
if (defaultTz == null) {
|
||||||
defaultTz = new TIANATimeZone(DateTimeZoneProvider.detectTimezone());
|
//defaultTz = new TIANATimeZone(DateTimeZoneProvider.detectTimezone());
|
||||||
|
defaultTz = TTimeZone.getTimeZone("UTC");
|
||||||
}
|
}
|
||||||
return (TTimeZone) defaultTz.clone();
|
return (TTimeZone) defaultTz.clone();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.java.util;
|
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 {
|
public interface TestService {
|
||||||
void foo();
|
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-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-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: 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: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: 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: 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.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: 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: 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: 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: 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.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: 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: 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.websocket:websocket-client:9.2.13.v20150730" 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-util:9.2.13.v20150730" 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:jetty-io:9.2.13.v20150730" 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-common:9.2.13.v20150730" 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-api:9.2.13.v20150730" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</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>
|
<dependency>
|
||||||
<groupId>net.sourceforge.htmlunit</groupId>
|
<groupId>net.sourceforge.htmlunit</groupId>
|
||||||
<artifactId>htmlunit</artifactId>
|
<artifactId>htmlunit</artifactId>
|
||||||
<version>2.18</version>
|
<version>2.19</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.junit;
|
package org.teavm.junit;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
final class ExceptionHelper {
|
final class ExceptionHelper {
|
||||||
private ExceptionHelper() {
|
private ExceptionHelper() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,33 +29,56 @@ import net.sourceforge.htmlunit.corejs.javascript.Function;
|
||||||
import net.sourceforge.htmlunit.corejs.javascript.NativeJavaObject;
|
import net.sourceforge.htmlunit.corejs.javascript.NativeJavaObject;
|
||||||
import org.apache.commons.io.IOUtils;
|
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
|
@Override
|
||||||
public void beforeThread() {
|
public void beforeThread() {
|
||||||
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterThread() {
|
public void afterThread() {
|
||||||
|
cleanUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String runTest(TestRun run) throws IOException {
|
public String runTest(TestRun run) throws IOException {
|
||||||
try (WebClient webClient = new WebClient(BrowserVersion.CHROME)) {
|
if (++runs == 50) {
|
||||||
HtmlPage page = webClient.getPage("about:blank");
|
runs = 0;
|
||||||
page.executeJavaScript(readFile(new File(run.getBaseDirectory(), "runtime.js")));
|
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();
|
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();
|
.getJavaScriptResult();
|
||||||
Object[] args = new Object[] { new NativeJavaObject(function, asyncResult, AsyncResult.class) };
|
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")));
|
private void cleanUp() {
|
||||||
page.cleanUp();
|
page.get().cleanUp();
|
||||||
for (WebWindow window : webClient.getWebWindows()) {
|
for (WebWindow window : webClient.get().getWebWindows()) {
|
||||||
window.getJobManager().removeAllJobs();
|
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.DesiredCapabilities;
|
||||||
import org.openqa.selenium.remote.RemoteWebDriver;
|
import org.openqa.selenium.remote.RemoteWebDriver;
|
||||||
|
|
||||||
public class SeleniumRunStrategy implements TestRunStrategy {
|
class SeleniumRunStrategy implements TestRunStrategy {
|
||||||
private URL url;
|
private URL url;
|
||||||
private ThreadLocal<WebDriver> webDriver = new ThreadLocal<>();
|
private ThreadLocal<WebDriver> webDriver = new ThreadLocal<>();
|
||||||
private ThreadLocal<Integer> commandsSent = new ThreadLocal<>();
|
private ThreadLocal<Integer> commandsSent = new ThreadLocal<>();
|
||||||
|
private int rebootRate = Integer.getInteger("teavm.junit.js.selenium.rebootAfter", 1000);
|
||||||
|
|
||||||
public SeleniumRunStrategy(URL url) {
|
public SeleniumRunStrategy(URL url) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
|
@ -54,7 +55,7 @@ public class SeleniumRunStrategy implements TestRunStrategy {
|
||||||
@Override
|
@Override
|
||||||
public String runTest(TestRun run) throws IOException {
|
public String runTest(TestRun run) throws IOException {
|
||||||
commandsSent.set(commandsSent.get() + 1);
|
commandsSent.set(commandsSent.get() + 1);
|
||||||
if (commandsSent.get().equals(20)) {
|
if (commandsSent.get().equals(100)) {
|
||||||
commandsSent.set(0);
|
commandsSent.set(0);
|
||||||
webDriver.get().close();
|
webDriver.get().close();
|
||||||
webDriver.get().quit();
|
webDriver.get().quit();
|
||||||
|
|
|
@ -66,6 +66,7 @@ import org.teavm.vm.TeaVMBuilder;
|
||||||
public class TeaVMTestRunner extends Runner {
|
public class TeaVMTestRunner extends Runner {
|
||||||
private static final String PATH_PARAM = "teavm.junit.target";
|
private static final String PATH_PARAM = "teavm.junit.target";
|
||||||
private static final String RUNNER = "teavm.junit.js.runner";
|
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 String SELENIUM_URL = "teavm.junit.js.selenium.url";
|
||||||
private static final int stopTimeout = 15000;
|
private static final int stopTimeout = 15000;
|
||||||
private Class<?> testClass;
|
private Class<?> testClass;
|
||||||
|
@ -83,6 +84,16 @@ public class TeaVMTestRunner extends Runner {
|
||||||
private static volatile ScheduledFuture<?> cleanupFuture;
|
private static volatile ScheduledFuture<?> cleanupFuture;
|
||||||
private CountDownLatch latch;
|
private CountDownLatch latch;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
|
synchronized (TeaVMTestRunner.class) {
|
||||||
|
cleanupFuture = null;
|
||||||
|
runner.stop();
|
||||||
|
runner.waitForCompletion();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
public TeaVMTestRunner(Class<?> testClass) throws InitializationError {
|
public TeaVMTestRunner(Class<?> testClass) throws InitializationError {
|
||||||
this.testClass = testClass;
|
this.testClass = testClass;
|
||||||
classLoader = TeaVMTestRunner.class.getClassLoader();
|
classLoader = TeaVMTestRunner.class.getClassLoader();
|
||||||
|
@ -167,14 +178,27 @@ public class TeaVMTestRunner extends Runner {
|
||||||
boolean run = false;
|
boolean run = false;
|
||||||
boolean success = true;
|
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)
|
if (!child.isAnnotationPresent(SkipJVM.class)
|
||||||
&& !child.getDeclaringClass().isAnnotationPresent(SkipJVM.class)) {
|
&& !child.getDeclaringClass().isAnnotationPresent(SkipJVM.class)) {
|
||||||
run = true;
|
run = true;
|
||||||
success = runInJvm(child, notifier);
|
success = runInJvm(child, notifier, expectedExceptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success && outputDir != null) {
|
if (success && outputDir != null) {
|
||||||
runInTeaVM(child, notifier);
|
runInTeaVM(child, notifier, expectedExceptions);
|
||||||
} else {
|
} else {
|
||||||
if (!run) {
|
if (!run) {
|
||||||
notifier.fireTestIgnored(describeChild(child));
|
notifier.fireTestIgnored(describeChild(child));
|
||||||
|
@ -184,18 +208,7 @@ public class TeaVMTestRunner extends Runner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean runInJvm(Method child, RunNotifier notifier) {
|
private boolean runInJvm(Method child, RunNotifier notifier, Set<Class<?>> expectedExceptions) {
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Object instance;
|
Object instance;
|
||||||
try {
|
try {
|
||||||
instance = testClass.newInstance();
|
instance = testClass.newInstance();
|
||||||
|
@ -233,22 +246,29 @@ public class TeaVMTestRunner extends Runner {
|
||||||
return true;
|
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;
|
CompileResult compileResult;
|
||||||
try {
|
try {
|
||||||
compileResult = compileTest(child);
|
compileResult = compileTest(child);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
notifier.fireTestFailure(new Failure(describeChild(child), e));
|
notifier.fireTestFailure(new Failure(description, e));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!compileResult.success) {
|
if (!compileResult.success) {
|
||||||
notifier.fireTestFailure(new Failure(describeChild(child),
|
notifier.fireTestFailure(new Failure(description,
|
||||||
new AssertionError(compileResult.errorMessage)));
|
new AssertionError(compileResult.errorMessage)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Description description = describeChild(child);
|
if (runStrategy == null) {
|
||||||
|
notifier.fireTestFinished(description);
|
||||||
|
latch.countDown();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
TestRunCallback callback = new TestRunCallback() {
|
TestRunCallback callback = new TestRunCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void complete() {
|
public void complete() {
|
||||||
|
@ -264,7 +284,7 @@ public class TeaVMTestRunner extends Runner {
|
||||||
|
|
||||||
TestRun run = new TestRun(compileResult.file.getParentFile(), child,
|
TestRun run = new TestRun(compileResult.file.getParentFile(), child,
|
||||||
new MethodReference(testClass.getName(), getDescriptor(child)),
|
new MethodReference(testClass.getName(), getDescriptor(child)),
|
||||||
description, callback);
|
description, callback, expectedExceptions);
|
||||||
submitRun(run);
|
submitRun(run);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -277,6 +297,11 @@ public class TeaVMTestRunner extends Runner {
|
||||||
|
|
||||||
if (runner == null) {
|
if (runner == null) {
|
||||||
runner = new TestRunner(runStrategy);
|
runner = new TestRunner(runStrategy);
|
||||||
|
try {
|
||||||
|
runner.setNumThreads(Integer.parseInt(System.getProperty(THREAD_COUNT, "1")));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
runner.setNumThreads(1);
|
||||||
|
}
|
||||||
runner.init();
|
runner.init();
|
||||||
}
|
}
|
||||||
runner.run(run);
|
runner.run(run);
|
||||||
|
|
|
@ -17,23 +17,28 @@ package org.teavm.junit;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
import org.junit.runner.Description;
|
import org.junit.runner.Description;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
public class TestRun {
|
class TestRun {
|
||||||
private File baseDirectory;
|
private File baseDirectory;
|
||||||
private Method method;
|
private Method method;
|
||||||
private MethodReference reference;
|
private MethodReference reference;
|
||||||
private Description description;
|
private Description description;
|
||||||
private TestRunCallback callback;
|
private TestRunCallback callback;
|
||||||
|
private Set<Class<?>> expectedExceptions;
|
||||||
|
|
||||||
public TestRun(File baseDirectory, Method method, MethodReference reference, Description description,
|
TestRun(File baseDirectory, Method method, MethodReference reference, Description description,
|
||||||
TestRunCallback callback) {
|
TestRunCallback callback, Set<Class<?>> expectedExceptions) {
|
||||||
this.baseDirectory = baseDirectory;
|
this.baseDirectory = baseDirectory;
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.reference = reference;
|
this.reference = reference;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
this.expectedExceptions = Collections.unmodifiableSet(new HashSet<>(expectedExceptions));
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getBaseDirectory() {
|
public File getBaseDirectory() {
|
||||||
|
@ -55,4 +60,8 @@ public class TestRun {
|
||||||
public TestRunCallback getCallback() {
|
public TestRunCallback getCallback() {
|
||||||
return callback;
|
return callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Class<?>> getExpectedExceptions() {
|
||||||
|
return expectedExceptions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.junit;
|
package org.teavm.junit;
|
||||||
|
|
||||||
public interface TestRunCallback {
|
interface TestRunCallback {
|
||||||
void complete();
|
void complete();
|
||||||
|
|
||||||
void error(Throwable e);
|
void error(Throwable e);
|
||||||
|
|
|
@ -17,7 +17,7 @@ package org.teavm.junit;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public interface TestRunStrategy {
|
interface TestRunStrategy {
|
||||||
void beforeThread();
|
void beforeThread();
|
||||||
|
|
||||||
void afterThread();
|
void afterThread();
|
||||||
|
|
|
@ -22,18 +22,15 @@ import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.TimeUnit;
|
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 int numThreads = 1;
|
||||||
private TestRunStrategy strategy;
|
private TestRunStrategy strategy;
|
||||||
private BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
|
private BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
|
||||||
private CountDownLatch latch;
|
private CountDownLatch latch;
|
||||||
private volatile boolean stopped;
|
private volatile boolean stopped;
|
||||||
|
|
||||||
public TestRunner(TestRunStrategy strategy) {
|
TestRunner(TestRunStrategy strategy) {
|
||||||
this.strategy = strategy;
|
this.strategy = strategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +70,19 @@ public class TestRunner {
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
stopped = true;
|
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) {
|
public void run(TestRun run) {
|
||||||
|
@ -81,7 +90,6 @@ public class TestRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runImpl(TestRun run) {
|
private void runImpl(TestRun run) {
|
||||||
MethodReference ref = run.getReference();
|
|
||||||
try {
|
try {
|
||||||
String result = strategy.runTest(run);
|
String result = strategy.runTest(run);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
|
@ -93,17 +101,38 @@ public class TestRunner {
|
||||||
String status = resultObject.get("status").asText();
|
String status = resultObject.get("status").asText();
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case "ok":
|
case "ok":
|
||||||
|
if (!run.getExpectedExceptions().isEmpty()) {
|
||||||
|
run.getCallback().error(new AssertionError("Expected exception was not thrown"));
|
||||||
|
} else {
|
||||||
run.getCallback().complete();
|
run.getCallback().complete();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "exception": {
|
case "exception": {
|
||||||
String stack = resultObject.get("stack").asText();
|
String stack = resultObject.get("stack").asText();
|
||||||
String exception = resultObject.get("exception").asText();
|
String exception = resultObject.has("exception") ? resultObject.get("exception").asText() : null;
|
||||||
run.getCallback().error(new AssertionError(exception + "\n" + exception));
|
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();
|
run.getCallback().complete();
|
||||||
break;
|
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().error(e);
|
||||||
run.getCallback().complete();
|
run.getCallback().complete();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
function main(callback) {
|
function main(callback) {
|
||||||
var JUnitClient = {};
|
|
||||||
JUnitClient.run = function() {
|
|
||||||
$rt_startThread(function () {
|
$rt_startThread(function () {
|
||||||
var thread = $rt_nativeThread();
|
var thread = $rt_nativeThread();
|
||||||
var instance;
|
var instance;
|
||||||
|
@ -10,13 +8,14 @@ function main(callback) {
|
||||||
ptr = thread.pop();
|
ptr = thread.pop();
|
||||||
instance = thread.pop();
|
instance = thread.pop();
|
||||||
}
|
}
|
||||||
loop: while (true) { switch (ptr) {
|
loop: while (true) {
|
||||||
|
switch (ptr) {
|
||||||
case 0:
|
case 0:
|
||||||
try {
|
try {
|
||||||
runTest();
|
runTest();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
message = {};
|
message = {};
|
||||||
JUnitClient.makeErrorMessage(message, e);
|
makeErrorMessage(message, e);
|
||||||
break loop;
|
break loop;
|
||||||
}
|
}
|
||||||
if (thread.isSuspending()) {
|
if (thread.isSuspending()) {
|
||||||
|
@ -27,12 +26,12 @@ function main(callback) {
|
||||||
message = {};
|
message = {};
|
||||||
message.status = "ok";
|
message.status = "ok";
|
||||||
break loop;
|
break loop;
|
||||||
}}
|
}
|
||||||
|
}
|
||||||
callback.complete(JSON.stringify(message));
|
callback.complete(JSON.stringify(message));
|
||||||
})
|
});
|
||||||
};
|
|
||||||
|
|
||||||
JUnitClient.makeErrorMessage = function(message, e) {
|
function makeErrorMessage(message, e) {
|
||||||
message.status = "exception";
|
message.status = "exception";
|
||||||
var stack = e.stack;
|
var stack = e.stack;
|
||||||
if (e.$javaException && e.$javaException.constructor.$meta) {
|
if (e.$javaException && e.$javaException.constructor.$meta) {
|
||||||
|
@ -42,7 +41,5 @@ function main(callback) {
|
||||||
message.stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
|
message.stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
|
||||||
}
|
}
|
||||||
message.stack += "\n" + stack;
|
message.stack += "\n" + stack;
|
||||||
};
|
}
|
||||||
|
|
||||||
window.JUnitClient = JUnitClient;
|
|
||||||
}
|
}
|
|
@ -29,7 +29,7 @@ $rt_startThread(function() {
|
||||||
runTest();
|
runTest();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
message = {};
|
message = {};
|
||||||
JUnitClient.makeErrorMessage(message, e);
|
makeErrorMessage(message, e);
|
||||||
break loop;
|
break loop;
|
||||||
}
|
}
|
||||||
if (thread.isSuspending()) {
|
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-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-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: 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:xalan:2.7.2" level="project" />
|
||||||
<orderEntry type="library" name="Maven: xalan:serializer: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: 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.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: 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: 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: 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: 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.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: 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-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: 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.websocket:websocket-client:9.2.13.v20150730" 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-util:9.2.13.v20150730" 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:jetty-io:9.2.13.v20150730" 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-common:9.2.13.v20150730" 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-api:9.2.13.v20150730" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
Loading…
Reference in New Issue
Block a user