Deep refactoring of tooling libraries

This commit is contained in:
Alexey Andreev 2015-10-09 17:56:38 +03:00
parent 90fec4e219
commit 5522f55c68
66 changed files with 744 additions and 633 deletions

View File

@ -74,12 +74,11 @@
<execution>
<id>generate-javascript-tests</id>
<goals>
<goal>build-test-javascript</goal>
<goal>testCompile</goal>
</goals>
<phase>process-test-classes</phase>
<configuration>
<minifying>false</minifying>
<outputDir>${project.build.directory}/javascript-test</outputDir>
<targetDirectory>${project.build.directory}/javascript-test</targetDirectory>
<debugInformationGenerated>true</debugInformationGenerated>
<sourceMapsGenerated>true</sourceMapsGenerated>
</configuration>
@ -87,13 +86,12 @@
<execution>
<id>generate-javascript-tck</id>
<goals>
<goal>build-test-javascript</goal>
<goal>testCompile</goal>
</goals>
<phase>process-test-classes</phase>
<configuration>
<minifying>false</minifying>
<scanDependencies>true</scanDependencies>
<outputDir>${project.build.directory}/javascript-tck</outputDir>
<targetDirectory>${project.build.directory}/javascript-tck</targetDirectory>
<adapterClass>org.teavm.html4j.testing.KOTestAdapter</adapterClass>
<transformers>
<param>org.teavm.javascript.NullPointerExceptionTransformer</param>

View File

@ -21,6 +21,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xs
<groupId>org.teavm</groupId>
<artifactId>teavm</artifactId>
<version>0.4.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<artifactId>teavm-jso-apis</artifactId>

View File

@ -21,6 +21,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xs
<groupId>org.teavm</groupId>
<artifactId>teavm</artifactId>
<version>0.4.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<artifactId>teavm-jso</artifactId>

View File

@ -21,6 +21,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xs
<groupId>org.teavm</groupId>
<artifactId>teavm</artifactId>
<version>0.4.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<artifactId>teavm-jso-impl</artifactId>

12
pom.xml
View File

@ -70,6 +70,7 @@
<jetty.version>9.2.1.v20140609</jetty.version>
<slf4j.version>1.7.7</slf4j.version>
<selenium.version>2.47.2</selenium.version>
<jackson.version>2.6.2</jackson.version>
</properties>
<modules>
@ -81,6 +82,7 @@
<module>html4j</module>
<module>samples</module>
<module>platform</module>
<module>tools/core</module>
<module>tools/cli</module>
<module>tools/maven</module>
<module>tools/chrome-rdp</module>
@ -176,6 +178,16 @@
<artifactId>selenium-remote-driver</artifactId>
<version>${selenium.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@ -57,9 +57,8 @@
<executions>
<execution>
<id>web-client</id>
<phase>prepare-package</phase>
<goals>
<goal>build-javascript</goal>
<goal>compile</goal>
</goals>
<configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>

View File

@ -111,9 +111,8 @@
<executions>
<execution>
<id>web-client</id>
<phase>prepare-package</phase>
<goals>
<goal>build-javascript</goal>
<goal>compile</goal>
</goals>
<configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>

View File

@ -76,9 +76,8 @@
<executions>
<execution>
<id>web-client</id>
<phase>prepare-package</phase>
<goals>
<goal>build-javascript</goal>
<goal>compile</goal>
</goals>
<configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>

View File

@ -92,9 +92,8 @@
<executions>
<execution>
<id>web-client</id>
<phase>prepare-package</phase>
<goals>
<goal>build-javascript</goal>
<goal>compile</goal>
</goals>
<configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>

View File

@ -36,6 +36,8 @@
<module>video</module>
<module>async</module>
<module>kotlin</module>
<!--
<module>scala</module>
-->
</modules>
</project>

View File

@ -67,9 +67,8 @@
<executions>
<execution>
<id>web-client</id>
<phase>prepare-package</phase>
<goals>
<goal>build-javascript</goal>
<goal>compile</goal>
</goals>
<configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>

View File

@ -78,12 +78,11 @@
<id>web-client</id>
<phase>prepare-package</phase>
<goals>
<goal>build-javascript</goal>
<goal>compile</goal>
</goals>
<configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>
<mainClass>org.teavm.samples.storage.Application</mainClass>
<runtime>SEPARATE</runtime>
<minifying>false</minifying>
<debugInformationGenerated>true</debugInformationGenerated>
<sourceMapsGenerated>true</sourceMapsGenerated>

View File

@ -76,9 +76,8 @@
<executions>
<execution>
<id>web-client</id>
<phase>prepare-package</phase>
<goals>
<goal>build-javascript</goal>
<goal>compile</goal>
</goals>
<configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>

View File

@ -72,9 +72,8 @@
<execution>
<id>generate-javascript-tests</id>
<goals>
<goal>build-test-javascript</goal>
<goal>testCompile</goal>
</goals>
<phase>process-test-classes</phase>
<configuration>
<minifying>false</minifying>
<scanDependencies>true</scanDependencies>

View File

@ -21,6 +21,7 @@
<groupId>org.teavm</groupId>
<artifactId>teavm</artifactId>
<version>0.4.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<artifactId>teavm-cli</artifactId>
@ -30,7 +31,7 @@
<dependencies>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-core</artifactId>
<artifactId>teavm-tooling</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>

View File

@ -19,11 +19,17 @@ import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import org.apache.commons.cli.*;
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.TeaVMTestTool;
import org.teavm.tooling.TeaVMToolException;
import org.teavm.tooling.testing.TeaVMTestTool;
/**
*
@ -84,7 +90,7 @@ public final class TeaVMTestRunner {
}
TeaVMTestTool tool = new TeaVMTestTool();
tool.setOutputDir(new File(commandLine.getOptionValue("d", ".")));
tool.setTargetDirectory(new File(commandLine.getOptionValue("d", ".")));
tool.setMinifying(commandLine.hasOption("m"));
try {
tool.setNumThreads(Integer.parseInt(commandLine.getOptionValue("t", "1")));

64
tools/core/pom.xml Normal file
View File

@ -0,0 +1,64 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.teavm</groupId>
<artifactId>teavm</artifactId>
<version>0.4.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<artifactId>teavm-tooling</artifactId>
<name>TeaVM tooling core</name>
<description>TeaVM API that helps to create tooling</description>
<dependencies>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<configuration>
<configLocation>../../checkstyle.xml</configLocation>
<propertyExpansion>config_loc=${basedir}/../..</propertyExpansion>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,50 @@
/*
* Copyright 2015 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.tooling;
import java.io.File;
import java.util.List;
import java.util.Properties;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.tooling.sources.SourceFileProvider;
/**
*
* @author Alexey Andreev
*/
public interface BaseTeaVMTool {
void setTargetDirectory(File targetDirectory);
void setMinifying(boolean minifying);
void setIncremental(boolean incremental);
void setDebugInformationGenerated(boolean debugInformationGenerated);
void setSourceMapsFileGenerated(boolean sourceMapsFileGenerated);
void setSourceFilesCopied(boolean sourceFilesCopied);
Properties getProperties();
List<ClassHolderTransformer> getTransformers();
void setLog(TeaVMToolLog log);
void setClassLoader(ClassLoader classLoader);
void addSourceFileProvider(SourceFileProvider sourceFileProvider);
}

View File

@ -29,6 +29,8 @@ import org.teavm.diagnostics.ProblemProvider;
import org.teavm.javascript.RenderingContext;
import org.teavm.model.*;
import org.teavm.parsing.ClasspathClassHolderSource;
import org.teavm.tooling.sources.SourceFileProvider;
import org.teavm.tooling.sources.SourceFilesCopier;
import org.teavm.vm.*;
import org.teavm.vm.spi.AbstractRendererListener;
@ -36,7 +38,7 @@ import org.teavm.vm.spi.AbstractRendererListener;
*
* @author Alexey Andreev
*/
public class TeaVMTool {
public class TeaVMTool implements BaseTeaVMTool {
private File targetDirectory = new File(".");
private String targetFileName = "classes.js";
private boolean minifying = true;
@ -69,6 +71,7 @@ public class TeaVMTool {
return targetDirectory;
}
@Override
public void setTargetDirectory(File targetDirectory) {
this.targetDirectory = targetDirectory;
}
@ -85,6 +88,7 @@ public class TeaVMTool {
return minifying;
}
@Override
public void setMinifying(boolean minifying) {
this.minifying = minifying;
}
@ -93,6 +97,7 @@ public class TeaVMTool {
return incremental;
}
@Override
public void setIncremental(boolean incremental) {
this.incremental = incremental;
}
@ -133,6 +138,7 @@ public class TeaVMTool {
return debugInformationGenerated;
}
@Override
public void setDebugInformationGenerated(boolean debugInformationGenerated) {
this.debugInformationGenerated = debugInformationGenerated;
}
@ -149,6 +155,7 @@ public class TeaVMTool {
return sourceMapsFileGenerated;
}
@Override
public void setSourceMapsFileGenerated(boolean sourceMapsFileGenerated) {
this.sourceMapsFileGenerated = sourceMapsFileGenerated;
}
@ -157,14 +164,17 @@ public class TeaVMTool {
return sourceFilesCopied;
}
@Override
public void setSourceFilesCopied(boolean sourceFilesCopied) {
this.sourceFilesCopied = sourceFilesCopied;
}
@Override
public Properties getProperties() {
return properties;
}
@Override
public List<ClassHolderTransformer> getTransformers() {
return transformers;
}
@ -181,6 +191,7 @@ public class TeaVMTool {
return log;
}
@Override
public void setLog(TeaVMToolLog log) {
this.log = log;
}
@ -189,6 +200,7 @@ public class TeaVMTool {
return classLoader;
}
@Override
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@ -245,6 +257,7 @@ public class TeaVMTool {
return resources;
}
@Override
public void addSourceFileProvider(SourceFileProvider sourceFileProvider) {
sourceFileProviders.add(sourceFileProvider);
}

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.tooling;
package org.teavm.tooling.sources;
import java.io.File;
import java.io.FileInputStream;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.tooling;
package org.teavm.tooling.sources;
import java.io.File;
import java.io.IOException;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.tooling;
package org.teavm.tooling.sources;
import java.util.List;
import java.util.Set;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.tooling;
package org.teavm.tooling.sources;
import java.io.IOException;
import java.io.InputStream;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.tooling;
package org.teavm.tooling.sources;
import java.io.*;
import java.util.HashSet;
@ -23,6 +23,8 @@ import org.apache.commons.io.IOUtils;
import org.teavm.model.ClassReader;
import org.teavm.model.ListableClassReaderSource;
import org.teavm.model.MethodReader;
import org.teavm.tooling.EmptyTeaVMToolLog;
import org.teavm.tooling.TeaVMToolLog;
/**
*

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.tooling;
package org.teavm.tooling.testing;
/**
*

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.tooling;
package org.teavm.tooling.testing;
import java.io.File;
import java.io.FileOutputStream;
@ -25,6 +25,7 @@ import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.io.IOUtils;
import org.teavm.common.FiniteExecutor;
import org.teavm.common.SimpleFiniteExecutor;
@ -47,6 +48,13 @@ import org.teavm.model.ValueType;
import org.teavm.parsing.ClasspathClassHolderSource;
import org.teavm.testing.JUnitTestAdapter;
import org.teavm.testing.TestAdapter;
import org.teavm.tooling.BaseTeaVMTool;
import org.teavm.tooling.EmptyTeaVMToolLog;
import org.teavm.tooling.TeaVMProblemRenderer;
import org.teavm.tooling.TeaVMToolException;
import org.teavm.tooling.TeaVMToolLog;
import org.teavm.tooling.sources.SourceFileProvider;
import org.teavm.tooling.sources.SourceFilesCopier;
import org.teavm.vm.DirectoryBuildTarget;
import org.teavm.vm.TeaVM;
import org.teavm.vm.TeaVMBuilder;
@ -55,7 +63,7 @@ import org.teavm.vm.TeaVMBuilder;
*
* @author Alexey Andreev
*/
public class TeaVMTestTool {
public class TeaVMTestTool implements BaseTeaVMTool {
private File outputDir = new File(".");
private boolean minifying = true;
private int numThreads = 1;
@ -68,22 +76,25 @@ public class TeaVMTestTool {
private ClassLoader classLoader = TeaVMTestTool.class.getClassLoader();
private TeaVMToolLog log = new EmptyTeaVMToolLog();
private boolean debugInformationGenerated;
private boolean sourceMapsGenerated;
private boolean sourceMapsFileGenerated;
private boolean sourceFilesCopied;
private boolean incremental;
private List<SourceFileProvider> sourceFileProviders = new ArrayList<>();
private MethodNodeCache astCache;
private ProgramCache programCache;
private SourceFilesCopier sourceFilesCopier;
private List<TeaVMTestToolListener> listeners = new ArrayList<>();
private List<TeaVMTestClass> testPlan = new ArrayList<>();
private List<TestClassBuilder> testPlan = new ArrayList<>();
private int fileIndexGenerator;
private long startTime;
private int testCount;
private AtomicInteger testsBuilt = new AtomicInteger();
public File getOutputDir() {
return outputDir;
}
public void setOutputDir(File outputDir) {
@Override
public void setTargetDirectory(File outputDir) {
this.outputDir = outputDir;
}
@ -91,6 +102,7 @@ public class TeaVMTestTool {
return minifying;
}
@Override
public void setMinifying(boolean minifying) {
this.minifying = minifying;
}
@ -111,6 +123,7 @@ public class TeaVMTestTool {
this.adapter = adapter;
}
@Override
public List<ClassHolderTransformer> getTransformers() {
return transformers;
}
@ -119,6 +132,7 @@ public class TeaVMTestTool {
return additionalScripts;
}
@Override
public Properties getProperties() {
return properties;
}
@ -131,6 +145,7 @@ public class TeaVMTestTool {
return classLoader;
}
@Override
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@ -139,6 +154,7 @@ public class TeaVMTestTool {
return log;
}
@Override
public void setLog(TeaVMToolLog log) {
this.log = log;
}
@ -147,6 +163,7 @@ public class TeaVMTestTool {
return incremental;
}
@Override
public void setIncremental(boolean incremental) {
this.incremental = incremental;
}
@ -155,31 +172,36 @@ public class TeaVMTestTool {
return debugInformationGenerated;
}
@Override
public void setDebugInformationGenerated(boolean debugInformationGenerated) {
this.debugInformationGenerated = debugInformationGenerated;
}
public boolean isSourceMapsGenerated() {
return sourceMapsGenerated;
public boolean isSourceMapsFileGenerated() {
return sourceMapsFileGenerated;
}
public void setSourceMapsGenerated(boolean sourceMapsGenerated) {
this.sourceMapsGenerated = sourceMapsGenerated;
@Override
public void setSourceMapsFileGenerated(boolean sourceMapsFileGenerated) {
this.sourceMapsFileGenerated = sourceMapsFileGenerated;
}
public boolean isSourceFilesCopied() {
return sourceFilesCopied;
}
@Override
public void setSourceFilesCopied(boolean sourceFilesCopied) {
this.sourceFilesCopied = sourceFilesCopied;
}
@Override
public void addSourceFileProvider(SourceFileProvider sourceFileProvider) {
sourceFileProviders.add(sourceFileProvider);
}
public void generate() throws TeaVMToolException {
public TestPlan generate() throws TeaVMToolException {
testsBuilt.set(0);
Runnable finalizer = null;
try {
new File(outputDir, "tests").mkdirs();
@ -201,12 +223,17 @@ public class TeaVMTestTool {
if (incremental) {
classSource = new PreOptimizingClassHolderSource(classSource);
}
List<TestGroup> groups = new ArrayList<>();
for (String testClass : testClasses) {
ClassHolder classHolder = classSource.get(testClass);
if (classHolder == null) {
throw new TeaVMToolException("Could not find class " + testClass);
}
findTests(classHolder);
TestGroup group = findTests(classHolder);
if (group != null) {
groups.add(group);
}
}
includeAdditionalScripts(classLoader);
@ -220,16 +247,21 @@ public class TeaVMTestTool {
FiniteExecutor executor = new SimpleFiniteExecutor();
if (numThreads != 1) {
int threads = numThreads != 0 ? numThreads : Runtime.getRuntime().availableProcessors();
final ThreadPoolFiniteExecutor threadedExecutor = new ThreadPoolFiniteExecutor(threads);
ThreadPoolFiniteExecutor threadedExecutor = new ThreadPoolFiniteExecutor(threads);
finalizer = () -> threadedExecutor.stop();
executor = threadedExecutor;
}
startTime = System.currentTimeMillis();
int methodsGenerated = writeMethods(executor, classSource);
if (sourceFilesCopied) {
sourceFilesCopier.copy(new File(new File(outputDir, "tests"), "src"));
}
log.info("Test files successfully generated for " + methodsGenerated + " method(s).");
long timeSpent = System.currentTimeMillis() - startTime;
log.info("Test files successfully generated for " + methodsGenerated + " method(s) in "
+ (timeSpent / 1000.0) + " seconds.");
return new TestPlan("res/runtime.js", groups);
} catch (IOException e) {
throw new TeaVMToolException("IO error occured generating JavaScript files", e);
} finally {
@ -245,7 +277,7 @@ public class TeaVMTestTool {
allTestsWriter.write("prepare = function() {\n");
allTestsWriter.write(" return new JUnitServer(document.body).readTests([");
boolean first = true;
for (TeaVMTestClass testClass : testPlan) {
for (TestClassBuilder testClass : testPlan) {
if (!first) {
allTestsWriter.append(",");
}
@ -253,7 +285,7 @@ public class TeaVMTestTool {
allTestsWriter.append("\n { name : \"").append(testClass.getClassName())
.append("\", methods : [");
boolean firstMethod = true;
for (TeaVMTestMethod testMethod : testClass.getMethods()) {
for (TestMethodBuilder testMethod : testClass.getMethods()) {
String scriptName = testMethod.getFileName();
if (!firstMethod) {
allTestsWriter.append(",");
@ -289,13 +321,12 @@ public class TeaVMTestTool {
log.info("Generating test files");
sourceFilesCopier = new SourceFilesCopier(sourceFileProviders);
sourceFilesCopier.setLog(log);
for (TeaVMTestClass testClass : testPlan) {
for (TeaVMTestMethod testMethod : testClass.getMethods()) {
final ClassHolderSource builderClassSource = classSource;
for (TestClassBuilder testClass : testPlan) {
for (TestMethodBuilder testMethod : testClass.getMethods()) {
executor.execute(() -> {
log.debug("Building test for " + testMethod.getMethod());
try {
decompileClassesForTest(classLoader, new CopyClassHolderSource(builderClassSource),
decompileClassesForTest(classLoader, new CopyClassHolderSource(classSource),
testMethod);
} catch (IOException e) {
log.error("Error generating JavaScript", e);
@ -316,8 +347,9 @@ public class TeaVMTestTool {
}
}
private void findTests(ClassHolder cls) {
TeaVMTestClass testClass = new TeaVMTestClass(cls.getName());
private TestGroup findTests(ClassHolder cls) {
List<TestCase> cases = new ArrayList<>();
TestClassBuilder testClass = new TestClassBuilder(cls.getName());
for (MethodHolder method : cls.getMethods()) {
if (adapter.acceptMethod(method)) {
MethodReference ref = new MethodReference(cls.getName(), method.getDescriptor());
@ -328,12 +360,19 @@ public class TeaVMTestTool {
exceptions.add(exception);
}
TeaVMTestMethod testMethod = new TeaVMTestMethod(ref, fileName, exceptions);
TestMethodBuilder testMethod = new TestMethodBuilder(ref, fileName, exceptions);
testClass.getMethods().add(testMethod);
String debugTable = debugInformationGenerated ? testMethod.getFileName() + ".teavmdbg" : null;
cases.add(new TestCase(ref, testMethod.getFileName(), debugTable, testMethod.getExpectedExceptions()));
++testCount;
}
}
if (!testClass.getMethods().isEmpty()) {
testPlan.add(testClass);
return new TestGroup(cls.getName(), cases);
} else {
return null;
}
}
@ -362,7 +401,7 @@ public class TeaVMTestTool {
}
private void decompileClassesForTest(ClassLoader classLoader, ClassHolderSource classSource,
TeaVMTestMethod testMethod) throws IOException {
TestMethodBuilder testMethod) throws IOException {
String targetName = testMethod.getFileName();
TeaVM vm = new TeaVMBuilder()
.setClassLoader(classLoader)
@ -380,7 +419,7 @@ public class TeaVMTestTool {
}
File file = new File(outputDir, testMethod.getFileName());
DebugInformationBuilder debugInfoBuilder = sourceMapsGenerated || debugInformationGenerated
DebugInformationBuilder debugInfoBuilder = sourceMapsFileGenerated || debugInformationGenerated
? new DebugInformationBuilder() : null;
MethodReference methodRef = testMethod.getMethod();
try (Writer innerWriter = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) {
@ -395,7 +434,7 @@ public class TeaVMTestTool {
vm.build(innerWriter, new DirectoryBuildTarget(outputDir));
innerWriter.append("\n");
innerWriter.append("\nJUnitClient.run();");
if (sourceMapsGenerated) {
if (sourceMapsFileGenerated) {
String sourceMapsFileName = targetName.substring(targetName.lastIndexOf('/') + 1) + ".map";
innerWriter.append("\n//# sourceMappingURL=").append(sourceMapsFileName);
}
@ -410,16 +449,15 @@ public class TeaVMTestTool {
}
}
File debugTableFile = null;
if (debugInformationGenerated) {
DebugInformation debugInfo = debugInfoBuilder.getDebugInformation();
debugTableFile = new File(outputDir, targetName + ".teavmdbg");
File debugTableFile = new File(outputDir, targetName + ".teavmdbg");
try (OutputStream debugInfoOut = new FileOutputStream(debugTableFile)) {
debugInfo.write(debugInfoOut);
}
}
if (sourceMapsGenerated) {
if (sourceMapsFileGenerated) {
DebugInformation debugInfo = debugInfoBuilder.getDebugInformation();
String sourceMapsFileName = targetName + ".map";
try (Writer sourceMapsOut = new OutputStreamWriter(new FileOutputStream(
@ -431,11 +469,19 @@ public class TeaVMTestTool {
sourceFilesCopier.addClasses(vm.getWrittenClasses());
}
TeaVMTestCase testCase = new TeaVMTestCase(methodRef, new File(outputDir, "res/runtime.js"),
file, debugTableFile, testMethod.getExpectedExceptions());
for (TeaVMTestToolListener listener : listeners) {
listener.testGenerated(testCase);
incrementCounter();
}
private void incrementCounter() {
int count = testsBuilt.incrementAndGet();
if (count % 10 != 0) {
return;
}
long timeSpent = System.currentTimeMillis() - startTime;
getLog().info(count + " of " + testCount + " tests built in " + (timeSpent / 1000.0) + " seconds ("
+ String.format("%.2f", (double) count / timeSpent * 1000.0) + " tests per second avg.)");
}
private void escapeString(String string, Writer writer) throws IOException {
@ -465,12 +511,4 @@ public class TeaVMTestTool {
}
writer.append('\"');
}
public void addListener(TeaVMTestToolListener listener) {
listeners.add(listener);
}
public void removeListener(TeaVMTestToolListener listener) {
listeners.remove(listener);
}
}

View File

@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.tooling;
package org.teavm.tooling.testing;
/**
*
* @author Alexey Andreev
*/
public interface TeaVMTestToolListener {
void testGenerated(TeaVMTestCase testCase);
void testGenerated(TestCase testCase);
}

View File

@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.tooling;
package org.teavm.tooling.testing;
import java.io.File;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -25,38 +27,40 @@ import org.teavm.model.MethodReference;
*
* @author Alexey Andreev
*/
public class TeaVMTestCase {
public class TestCase {
private MethodReference testMethod;
private File runtimeScript;
private File testScript;
private File debugTable;
private String testScript;
private String debugTable;
private List<String> expectedExceptions = new ArrayList<>();
public TeaVMTestCase(MethodReference testMethod, File runtimeScript, File testScript, File debugTable,
List<String> expectedExceptions) {
@JsonCreator
public TestCase(
@JsonProperty("testMethod") MethodReference testMethod,
@JsonProperty("script") String testScript,
@JsonProperty("debugTable") String debugTable,
@JsonProperty("expectedExceptions") List<String> expectedExceptions) {
this.testMethod = testMethod;
this.runtimeScript = runtimeScript;
this.testScript = testScript;
this.debugTable = debugTable;
this.expectedExceptions = Collections.unmodifiableList(new ArrayList<>(expectedExceptions));
}
@JsonGetter
public MethodReference getTestMethod() {
return testMethod;
}
public File getRuntimeScript() {
return runtimeScript;
}
public File getTestScript() {
@JsonGetter("script")
public String getTestScript() {
return testScript;
}
public File getDebugTable() {
@JsonGetter
public String getDebugTable() {
return debugTable;
}
@JsonGetter
public List<String> getExpectedExceptions() {
return expectedExceptions;
}

View File

@ -13,19 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.tooling;
package org.teavm.tooling.testing;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Alexey Andreev
*/
class TeaVMTestClass {
class TestClassBuilder {
private String className;
private List<TeaVMTestMethod> methods;
private List<TestMethodBuilder> methods = new ArrayList<>();
public TeaVMTestClass(String className) {
public TestClassBuilder(String className) {
this.className = className;
}
@ -33,7 +34,7 @@ class TeaVMTestClass {
return className;
}
public List<TeaVMTestMethod> getMethods() {
public List<TestMethodBuilder> getMethods() {
return methods;
}
}

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.tooling;
package org.teavm.tooling.testing;
import org.teavm.dependency.AbstractDependencyListener;
import org.teavm.dependency.DependencyAgent;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.tooling;
package org.teavm.tooling.testing;
import org.teavm.vm.spi.TeaVMHost;
import org.teavm.vm.spi.TeaVMPlugin;

View File

@ -0,0 +1,49 @@
/*
* Copyright 2015 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.tooling.testing;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
*
* @author Alexey Andreev
*/
public class TestGroup {
private String className;
private List<TestCase> testCases;
@JsonCreator
public TestGroup(@JsonProperty("className") String className,
@JsonProperty("testCases") List<TestCase> testCases) {
this.className = className;
this.testCases = Collections.unmodifiableList(new ArrayList<>(testCases));
}
@JsonGetter("className")
public String getClassName() {
return className;
}
@JsonGetter("testCases")
public List<TestCase> getTestCases() {
return testCases;
}
}

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.tooling;
package org.teavm.tooling.testing;
import java.util.ArrayList;
import java.util.Collections;
@ -24,12 +24,12 @@ import org.teavm.model.MethodReference;
*
* @author Alexey Andreev
*/
class TeaVMTestMethod {
class TestMethodBuilder {
private MethodReference method;
private String fileName;
private List<String> expectedExceptions = new ArrayList<>();
public TeaVMTestMethod(MethodReference method, String fileName, List<String> expectedExceptions) {
public TestMethodBuilder(MethodReference method, String fileName, List<String> expectedExceptions) {
this.method = method;
this.fileName = fileName;
this.expectedExceptions = Collections.unmodifiableList(new ArrayList<>(expectedExceptions));

View File

@ -0,0 +1,47 @@
/*
* Copyright 2015 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.tooling.testing;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
*
* @author Alexey Andreev
*/
public class TestPlan {
private String runtimeScript;
private List<TestGroup> groups = new ArrayList<>();
@JsonCreator
public TestPlan(
@JsonProperty("runtimeScript") String runtimeScript,
@JsonProperty("groupList") List<TestGroup> groups) {
this.runtimeScript = runtimeScript;
this.groups = Collections.unmodifiableList(new ArrayList<>(groups));
}
public String getRuntimeScript() {
return runtimeScript;
}
public List<TestGroup> getGroups() {
return groups;
}
}

View File

Before

Width:  |  Height:  |  Size: 774 B

After

Width:  |  Height:  |  Size: 774 B

View File

@ -39,6 +39,7 @@ Bundle-ClassPath: .,
lib/slf4j-api-1.7.7.jar,
lib/teavm-chrome-rdp-0.4.0-SNAPSHOT.jar,
lib/teavm-core-0.4.0-SNAPSHOT.jar,
lib/teavm-tooling-0.4.0-SNAPSHOT.jar,
lib/websocket-api-9.2.1.v20140609.jar,
lib/websocket-client-9.2.1.v20140609.jar,
lib/websocket-common-9.2.1.v20140609.jar,

View File

@ -36,6 +36,7 @@ bin.includes = META-INF/,\
lib/slf4j-api-1.7.7.jar,\
lib/teavm-chrome-rdp-0.4.0-SNAPSHOT.jar,\
lib/teavm-core-0.4.0-SNAPSHOT.jar,\
lib/teavm-tooling-0.4.0-SNAPSHOT.jar,\
lib/websocket-api-9.2.1.v20140609.jar,\
lib/websocket-client-9.2.1.v20140609.jar,\
lib/websocket-common-9.2.1.v20140609.jar,\

View File

@ -79,6 +79,11 @@
<artifactId>teavm-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-tooling</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-chrome-rdp</artifactId>

View File

@ -21,6 +21,7 @@
<groupId>org.teavm</groupId>
<artifactId>teavm</artifactId>
<version>0.4.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<artifactId>teavm-eclipse</artifactId>
<packaging>pom</packaging>

View File

@ -50,7 +50,7 @@
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-core</artifactId>
<artifactId>teavm-tooling</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
@ -68,7 +68,6 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>

View File

@ -0,0 +1,219 @@
/*
* Copyright 2015 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.maven;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.MavenArtifactRepository;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.tooling.BaseTeaVMTool;
import org.teavm.tooling.sources.SourceFileProvider;
/**
*
* @author Alexey Andreev
*/
public abstract class AbstractJavascriptMojo extends AbstractMojo {
@Component
protected MavenProject project;
@Component
protected RepositorySystem repositorySystem;
@Parameter(required = true, readonly = true, defaultValue = "${localRepository}")
protected MavenArtifactRepository localRepository;
@Parameter(required = true, readonly = true, defaultValue = "${project.remoteArtifactRepositories}")
protected List<MavenArtifactRepository> remoteRepositories;
@Parameter(readonly = true, defaultValue = "${plugin.artifacts}")
protected List<Artifact> pluginArtifacts;
@Parameter(defaultValue = "${project.build.outputDirectory}")
protected File classFiles;
@Parameter
protected List<String> compileScopes;
@Parameter
protected boolean minifying = true;
@Parameter
protected String mainClass;
@Parameter
protected Properties properties;
@Parameter
protected boolean debugInformationGenerated;
@Parameter
protected boolean sourceMapsGenerated;
@Parameter
protected boolean sourceFilesCopied;
@Parameter
protected boolean incremental;
@Parameter
protected String[] transformers;
protected ClassLoader classLoader;
protected abstract File getTargetDirectory();
protected final List<ClassHolderTransformer> instantiateTransformers(ClassLoader classLoader)
throws MojoExecutionException {
List<ClassHolderTransformer> transformerInstances = new ArrayList<>();
if (transformers == null) {
return transformerInstances;
}
for (String transformerName : transformers) {
Class<?> transformerRawType;
try {
transformerRawType = Class.forName(transformerName, true, classLoader);
} catch (ClassNotFoundException e) {
throw new MojoExecutionException("Transformer not found: " + transformerName, e);
}
if (!ClassHolderTransformer.class.isAssignableFrom(transformerRawType)) {
throw new MojoExecutionException("Transformer " + transformerName + " is not subtype of " +
ClassHolderTransformer.class.getName());
}
Class<? extends ClassHolderTransformer> transformerType = transformerRawType.asSubclass(
ClassHolderTransformer.class);
Constructor<? extends ClassHolderTransformer> ctor;
try {
ctor = transformerType.getConstructor();
} catch (NoSuchMethodException e) {
throw new MojoExecutionException("Transformer " + transformerName + " has no default constructor");
}
try {
ClassHolderTransformer transformer = ctor.newInstance();
transformerInstances.add(transformer);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new MojoExecutionException("Error instantiating transformer " + transformerName, e);
}
}
return transformerInstances;
}
protected void setupTool(BaseTeaVMTool tool) throws MojoExecutionException {
tool.setLog(new MavenTeaVMToolLog(getLog()));
try {
ClassLoader classLoader = prepareClassLoader();
tool.setClassLoader(classLoader);
tool.setMinifying(minifying);
tool.setTargetDirectory(getTargetDirectory());
tool.getTransformers().addAll(instantiateTransformers(classLoader));
if (sourceFilesCopied) {
for (SourceFileProvider provider : getSourceFileProviders()) {
tool.addSourceFileProvider(provider);
}
}
if (properties != null) {
tool.getProperties().putAll(properties);
}
tool.setIncremental(incremental);
tool.setDebugInformationGenerated(debugInformationGenerated);
tool.setSourceMapsFileGenerated(sourceMapsGenerated);
tool.setSourceFilesCopied(sourceFilesCopied);
} catch (RuntimeException e) {
throw new MojoExecutionException("Unexpected error occured", e);
}
}
protected final ClassLoader prepareClassLoader() throws MojoExecutionException {
try {
Log log = getLog();
log.info("Preparing classpath for JavaScript generation");
List<URL> urls = new ArrayList<>();
StringBuilder classpath = new StringBuilder();
for (Artifact artifact : project.getArtifacts()) {
if (!filterByScope(artifact)) {
continue;
}
File file = artifact.getFile();
if (classpath.length() > 0) {
classpath.append(':');
}
classpath.append(file.getPath());
urls.add(file.toURI().toURL());
}
if (classpath.length() > 0) {
classpath.append(':');
}
classpath.append(classFiles.getPath());
urls.add(classFiles.toURI().toURL());
for (File additionalEntry : getAdditionalClassPath()) {
classpath.append(':').append(additionalEntry.getPath());
urls.add(additionalEntry.toURI().toURL());
}
log.info("Using the following classpath for JavaScript generation: " + classpath);
classLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]),
AbstractJavascriptMojo.class.getClassLoader());
return classLoader;
} catch (MalformedURLException e) {
throw new MojoExecutionException("Error gathering classpath information", e);
}
}
protected List<File> getAdditionalClassPath() {
return Collections.emptyList();
}
protected boolean filterByScope(Artifact artifact) {
return compileScopes == null ? isSupportedScope(artifact.getScope())
: compileScopes.contains(artifact.getScope());
}
protected boolean isSupportedScope(String scope) {
switch (scope) {
case Artifact.SCOPE_COMPILE:
case Artifact.SCOPE_PROVIDED:
case Artifact.SCOPE_SYSTEM:
return true;
default:
return false;
}
}
protected final List<SourceFileProvider> getSourceFileProviders() {
MavenSourceFileProviderLookup lookup = new MavenSourceFileProviderLookup();
lookup.setMavenProject(project);
lookup.setRepositorySystem(repositorySystem);
lookup.setLocalRepository(localRepository);
lookup.setRemoteRepositories(remoteRepositories);
lookup.setPluginDependencies(pluginArtifacts);
return lookup.resolve();
}
}

View File

@ -16,33 +16,16 @@
package org.teavm.maven;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.MavenArtifactRepository;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.tooling.ClassAlias;
import org.teavm.tooling.MethodAlias;
import org.teavm.tooling.RuntimeCopyOperation;
import org.teavm.tooling.SourceFileProvider;
import org.teavm.tooling.TeaVMTool;
import org.teavm.tooling.TeaVMToolException;
@ -50,72 +33,25 @@ import org.teavm.tooling.TeaVMToolException;
*
* @author Alexey Andreev
*/
@Mojo(name = "build-javascript", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)
public class BuildJavascriptMojo extends AbstractMojo {
@Component
private MavenProject project;
@Component
private RepositorySystem repositorySystem;
@Parameter(required = true, readonly = true, defaultValue = "${localRepository}")
private MavenArtifactRepository localRepository;
@Parameter(required = true, readonly = true, defaultValue = "${project.remoteArtifactRepositories}")
private List<MavenArtifactRepository> remoteRepositories;
@Parameter(readonly = true, defaultValue = "${plugin.artifacts}")
private List<Artifact> pluginArtifacts;
@Mojo(name = "compile", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME,
defaultPhase = LifecyclePhase.PROCESS_CLASSES)
public class BuildJavascriptMojo extends AbstractJavascriptMojo {
@Parameter(defaultValue = "${project.build.directory}/javascript")
private File targetDirectory;
@Parameter(defaultValue = "${project.build.outputDirectory}")
private File classFiles;
@Parameter
private List<String> compileScopes;
@Parameter
private String targetFileName = "classes.js";
@Parameter
private boolean minifying = true;
@Parameter
private String mainClass;
@Parameter
private RuntimeCopyOperation runtime = RuntimeCopyOperation.SEPARATE;
@Parameter
private Properties properties;
@Parameter
private boolean mainPageIncluded;
@Parameter
private boolean bytecodeLogging;
@Parameter
private boolean debugInformationGenerated;
@Parameter
private boolean sourceMapsGenerated;
@Parameter
private boolean sourceFilesCopied;
@Parameter
private boolean incremental;
@Parameter(defaultValue = "${project.build.directory}/teavm-cache")
private File cacheDirectory;
@Parameter
private String[] transformers;
@Parameter
private ClassAlias[] classAliases;
@ -125,152 +61,37 @@ public class BuildJavascriptMojo extends AbstractMojo {
@Parameter
private boolean stopOnErrors = true;
@Parameter
protected RuntimeCopyOperation runtime = RuntimeCopyOperation.SEPARATE;
@Parameter(defaultValue = "${project.build.directory}/teavm-cache")
protected File cacheDirectory;
private TeaVMTool tool = new TeaVMTool();
public void setProject(MavenProject project) {
this.project = project;
}
public void setTargetDirectory(File targetDirectory) {
this.targetDirectory = targetDirectory;
}
public void setTargetFileName(String targetFileName) {
this.targetFileName = targetFileName;
}
public void setClassFiles(File classFiles) {
this.classFiles = classFiles;
}
public void setMinifying(boolean minifying) {
this.minifying = minifying;
}
public void setBytecodeLogging(boolean bytecodeLogging) {
this.bytecodeLogging = bytecodeLogging;
}
public void setRuntimeCopy(RuntimeCopyOperation runtimeCopy) {
this.runtime = runtimeCopy;
}
public void setMainPageIncluded(boolean mainPageIncluded) {
this.mainPageIncluded = mainPageIncluded;
}
public void setCompileScopes(List<String> compileScopes) {
this.compileScopes = compileScopes;
}
public void setMainClass(String mainClass) {
this.mainClass = mainClass;
}
public String[] getTransformers() {
return transformers;
}
public void setTransformers(String[] transformers) {
this.transformers = transformers;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public void setClassAliases(ClassAlias[] classAliases) {
this.classAliases = classAliases;
}
public void setMethodAliases(MethodAlias[] methodAliases) {
this.methodAliases = methodAliases;
}
public boolean isDebugInformationGenerated() {
return debugInformationGenerated;
}
public void setDebugInformationGenerated(boolean debugInformationGenerated) {
this.debugInformationGenerated = debugInformationGenerated;
}
public boolean isSourceMapsGenerated() {
return sourceMapsGenerated;
}
public void setSourceMapsGenerated(boolean sourceMapsGenerated) {
this.sourceMapsGenerated = sourceMapsGenerated;
}
public boolean isSourceFilesCopied() {
return sourceFilesCopied;
}
public void setSourceFilesCopied(boolean sourceFilesCopied) {
this.sourceFilesCopied = sourceFilesCopied;
}
public boolean isIncremental() {
return incremental;
}
public void setIncremental(boolean incremental) {
this.incremental = incremental;
}
public void setStopOnErrors(boolean stopOnErrors) {
this.stopOnErrors = stopOnErrors;
}
public File getCacheDirectory() {
return cacheDirectory;
}
public void setCacheDirectory(File cacheDirectory) {
this.cacheDirectory = cacheDirectory;
@Override
protected File getTargetDirectory() {
return targetDirectory;
}
@Override
public void execute() throws MojoExecutionException {
Log log = getLog();
setupTool(tool);
tool.setLog(new MavenTeaVMToolLog(log));
try {
ClassLoader classLoader = prepareClassLoader();
tool.setClassLoader(classLoader);
tool.setBytecodeLogging(bytecodeLogging);
tool.setMainClass(mainClass);
tool.setMainPageIncluded(mainPageIncluded);
tool.setMinifying(minifying);
tool.setRuntime(runtime);
tool.setTargetDirectory(targetDirectory);
tool.setTargetFileName(targetFileName);
tool.getTransformers().addAll(instantiateTransformers(classLoader));
if (sourceFilesCopied) {
MavenSourceFileProviderLookup lookup = new MavenSourceFileProviderLookup();
lookup.setMavenProject(project);
lookup.setRepositorySystem(repositorySystem);
lookup.setLocalRepository(localRepository);
lookup.setRemoteRepositories(remoteRepositories);
lookup.setPluginDependencies(pluginArtifacts);
for (SourceFileProvider provider : lookup.resolve()) {
tool.addSourceFileProvider(provider);
}
}
if (classAliases != null) {
tool.getClassAliases().addAll(Arrays.asList(classAliases));
}
if (methodAliases != null) {
tool.getMethodAliases().addAll(Arrays.asList(methodAliases));
}
if (properties != null) {
tool.getProperties().putAll(properties);
}
tool.setCacheDirectory(cacheDirectory);
tool.setIncremental(incremental);
tool.setDebugInformationGenerated(debugInformationGenerated);
tool.setSourceMapsFileGenerated(sourceMapsGenerated);
tool.setSourceFilesCopied(sourceFilesCopied);
tool.generate();
if (stopOnErrors && !tool.getProblemProvider().getSevereProblems().isEmpty()) {
throw new MojoExecutionException("Build error");
@ -281,75 +102,4 @@ public class BuildJavascriptMojo extends AbstractMojo {
throw new MojoExecutionException("IO error occured", e);
}
}
private List<ClassHolderTransformer> instantiateTransformers(ClassLoader classLoader)
throws MojoExecutionException {
List<ClassHolderTransformer> transformerInstances = new ArrayList<>();
if (transformers == null) {
return transformerInstances;
}
for (String transformerName : transformers) {
Class<?> transformerRawType;
try {
transformerRawType = Class.forName(transformerName, true, classLoader);
} catch (ClassNotFoundException e) {
throw new MojoExecutionException("Transformer not found: " + transformerName, e);
}
if (!ClassHolderTransformer.class.isAssignableFrom(transformerRawType)) {
throw new MojoExecutionException("Transformer " + transformerName + " is not subtype of " +
ClassHolderTransformer.class.getName());
}
Class<? extends ClassHolderTransformer> transformerType = transformerRawType.asSubclass(
ClassHolderTransformer.class);
Constructor<? extends ClassHolderTransformer> ctor;
try {
ctor = transformerType.getConstructor();
} catch (NoSuchMethodException e) {
throw new MojoExecutionException("Transformer " + transformerName + " has no default constructor");
}
try {
ClassHolderTransformer transformer = ctor.newInstance();
transformerInstances.add(transformer);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new MojoExecutionException("Error instantiating transformer " + transformerName, e);
}
}
return transformerInstances;
}
private ClassLoader prepareClassLoader() throws MojoExecutionException {
try {
Log log = getLog();
log.info("Preparing classpath for JavaScript generation");
List<URL> urls = new ArrayList<>();
StringBuilder classpath = new StringBuilder();
Set<String> scopes;
if (compileScopes == null) {
scopes = new HashSet<>(Arrays.asList(
Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_SYSTEM));
} else {
scopes = new HashSet<>(compileScopes);
}
for (Artifact artifact : project.getArtifacts()) {
if (!scopes.contains(artifact.getScope())) {
continue;
}
File file = artifact.getFile();
if (classpath.length() > 0) {
classpath.append(':');
}
classpath.append(file.getPath());
urls.add(file.toURI().toURL());
}
if (classpath.length() > 0) {
classpath.append(':');
}
classpath.append(classFiles.getPath());
urls.add(classFiles.toURI().toURL());
log.info("Using the following classpath for JavaScript generation: " + classpath);
return new URLClassLoader(urls.toArray(new URL[urls.size()]), BuildJavascriptMojo.class.getClassLoader());
} catch (MalformedURLException e) {
throw new MojoExecutionException("Error gathering classpath information", e);
}
}
}

View File

@ -21,8 +21,6 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
@ -33,55 +31,31 @@ import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.apache.commons.io.FilenameUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.MavenArtifactRepository;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.testing.JUnitTestAdapter;
import org.teavm.testing.TestAdapter;
import org.teavm.tooling.SourceFileProvider;
import org.teavm.tooling.TeaVMTestTool;
import org.teavm.tooling.TeaVMToolException;
import org.teavm.tooling.testing.TeaVMTestTool;
/**
*
* @author Alexey Andreev
*/
@Mojo(name = "build-test-javascript", requiresDependencyResolution = ResolutionScope.TEST,
requiresDependencyCollection = ResolutionScope.TEST)
public class BuildJavascriptTestMojo extends AbstractMojo {
@Mojo(name = "testCompile", requiresDependencyResolution = ResolutionScope.TEST,
requiresDependencyCollection = ResolutionScope.TEST,
defaultPhase = LifecyclePhase.PROCESS_TEST_CLASSES)
public class BuildJavascriptTestMojo extends AbstractJavascriptMojo {
private static Set<String> testScopes = new HashSet<>(Arrays.asList(
Artifact.SCOPE_COMPILE, Artifact.SCOPE_TEST, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME,
Artifact.SCOPE_PROVIDED));
@Component
private MavenProject project;
@Component
private RepositorySystem repositorySystem;
@Parameter(required = true, readonly = true, defaultValue = "${localRepository}")
private MavenArtifactRepository localRepository;
@Parameter(required = true, readonly = true, defaultValue = "${project.remoteArtifactRepositories}")
private List<MavenArtifactRepository> remoteRepositories;
@Parameter(readonly = true, defaultValue = "${plugin.artifacts}")
private List<Artifact> pluginArtifacts;
@Parameter(defaultValue = "${project.build.directory}/javascript-test")
private File outputDir;
@Parameter(defaultValue = "${project.build.outputDirectory}")
private File classFiles;
private File targetDirectory;
@Parameter(defaultValue = "${project.build.testOutputDirectory}")
private File testFiles;
@ -92,9 +66,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
@Parameter
private String[] excludeWildcards = new String[0];
@Parameter
private boolean minifying = true;
@Parameter
private boolean scanDependencies;
@ -104,9 +75,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
@Parameter
private String adapterClass = JUnitTestAdapter.class.getName();
@Parameter
private String[] transformers;
@Parameter
private String[] additionalScripts;
@ -116,15 +84,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
@Parameter
private boolean incremental;
@Parameter
private boolean debugInformationGenerated;
@Parameter
private boolean sourceMapsGenerated;
@Parameter
private boolean sourceFilesCopied;
@Parameter
private URL seleniumURL;
@ -132,86 +91,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
private TeaVMTestTool tool = new TeaVMTestTool();
public void setProject(MavenProject project) {
this.project = project;
}
public void setOutputDir(File outputDir) {
this.outputDir = outputDir;
}
public void setClassFiles(File classFiles) {
this.classFiles = classFiles;
}
public void setTestFiles(File testFiles) {
this.testFiles = testFiles;
}
public void setMinifying(boolean minifying) {
this.minifying = minifying;
}
public void setNumThreads(int numThreads) {
this.numThreads = numThreads;
}
public void setAdapterClass(String adapterClass) {
this.adapterClass = adapterClass;
}
public void setWildcards(String[] wildcards) {
this.wildcards = wildcards;
}
public void setExcludeWildcards(String[] excludeWildcards) {
this.excludeWildcards = excludeWildcards;
}
public String[] getTransformers() {
return transformers;
}
public void setTransformers(String[] transformers) {
this.transformers = transformers;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public void setIncremental(boolean incremental) {
this.incremental = incremental;
}
public boolean isDebugInformationGenerated() {
return debugInformationGenerated;
}
public void setDebugInformationGenerated(boolean debugInformationGenerated) {
this.debugInformationGenerated = debugInformationGenerated;
}
public boolean isSourceMapsGenerated() {
return sourceMapsGenerated;
}
public void setSourceMapsGenerated(boolean sourceMapsGenerated) {
this.sourceMapsGenerated = sourceMapsGenerated;
}
public boolean isSourceFilesCopied() {
return sourceFilesCopied;
}
public void setSourceFilesCopied(boolean sourceFilesCopied) {
this.sourceFilesCopied = sourceFilesCopied;
}
public void setSeleniumURL(URL seleniumURL) {
this.seleniumURL = seleniumURL;
}
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
if (System.getProperty("maven.test.skip", "false").equals("true") ||
@ -220,54 +99,21 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
return;
}
seleniumRunner = new SeleniumTestRunner();
seleniumRunner.setUrl(seleniumURL);
seleniumRunner.setLog(getLog());
seleniumRunner.detectSelenium();
setupTool(tool);
try {
final ClassLoader classLoader = prepareClassLoader();
getLog().info("Searching for tests in the directory `" + testFiles.getAbsolutePath() + "'");
tool.setClassLoader(classLoader);
tool.setAdapter(createAdapter(classLoader));
findTestClasses(classLoader, testFiles, "");
if (scanDependencies) {
findTestsInDependencies(classLoader);
}
tool.getTransformers().addAll(instantiateTransformers(classLoader));
tool.setLog(new MavenTeaVMToolLog(getLog()));
tool.setOutputDir(outputDir);
tool.setNumThreads(numThreads);
tool.setMinifying(minifying);
tool.setIncremental(incremental);
tool.setDebugInformationGenerated(debugInformationGenerated);
tool.setSourceMapsGenerated(sourceMapsGenerated);
tool.setSourceFilesCopied(sourceFilesCopied);
if (sourceFilesCopied) {
MavenSourceFileProviderLookup lookup = new MavenSourceFileProviderLookup();
lookup.setMavenProject(project);
lookup.setRepositorySystem(repositorySystem);
lookup.setLocalRepository(localRepository);
lookup.setRemoteRepositories(remoteRepositories);
lookup.setPluginDependencies(pluginArtifacts);
for (SourceFileProvider provider : lookup.resolve()) {
tool.addSourceFileProvider(provider);
}
}
if (properties != null) {
tool.getProperties().putAll(properties);
}
if (additionalScripts != null) {
tool.getAdditionalScripts().addAll(Arrays.asList(additionalScripts));
}
tool.addListener(testCase -> seleniumRunner.run(testCase));
tool.generate();
seleniumRunner.stopSelenium();
seleniumRunner.waitForSelenium();
processReport(seleniumRunner.getReport());
} catch (TeaVMToolException e) {
throw new MojoFailureException("Error occured generating JavaScript files", e);
} finally {
seleniumRunner.stopSelenium();
}
}
@ -318,38 +164,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
}
}
private ClassLoader prepareClassLoader() throws MojoExecutionException {
try {
Log log = getLog();
log.info("Preparing classpath for JavaScript test generation");
List<URL> urls = new ArrayList<>();
StringBuilder classpath = new StringBuilder();
for (Artifact artifact : project.getArtifacts()) {
if (!testScopes.contains(artifact.getScope())) {
continue;
}
File file = artifact.getFile();
if (classpath.length() > 0) {
classpath.append(':');
}
classpath.append(file.getPath());
urls.add(file.toURI().toURL());
}
if (classpath.length() > 0) {
classpath.append(':');
}
classpath.append(testFiles.getPath());
urls.add(testFiles.toURI().toURL());
classpath.append(':').append(classFiles.getPath());
urls.add(classFiles.toURI().toURL());
log.info("Using the following classpath for JavaScript test generation: " + classpath);
return new URLClassLoader(urls.toArray(new URL[urls.size()]),
BuildJavascriptTestMojo.class.getClassLoader());
} catch (MalformedURLException e) {
throw new MojoExecutionException("Error gathering classpath information", e);
}
}
private void findTestsInDependencies(ClassLoader classLoader) throws MojoExecutionException {
try {
Log log = getLog();
@ -430,40 +244,18 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
}
}
private List<ClassHolderTransformer> instantiateTransformers(ClassLoader classLoader)
throws MojoExecutionException {
List<ClassHolderTransformer> transformerInstances = new ArrayList<>();
if (transformers == null) {
return transformerInstances;
}
for (String transformerName : transformers) {
Class<?> transformerRawType;
try {
transformerRawType = Class.forName(transformerName, true, classLoader);
} catch (ClassNotFoundException e) {
throw new MojoExecutionException("Transformer not found: " + transformerName, e);
}
if (!ClassHolderTransformer.class.isAssignableFrom(transformerRawType)) {
throw new MojoExecutionException("Transformer " + transformerName + " is not subtype of " +
ClassHolderTransformer.class.getName());
}
Class<? extends ClassHolderTransformer> transformerType = transformerRawType.asSubclass(
ClassHolderTransformer.class);
Constructor<? extends ClassHolderTransformer> ctor;
try {
ctor = transformerType.getConstructor();
} catch (NoSuchMethodException e) {
throw new MojoExecutionException("Transformer " + transformerName + " has no default constructor");
}
try {
ClassHolderTransformer transformer = ctor.newInstance();
transformerInstances.add(transformer);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new MojoExecutionException("Error instantiating transformer " + transformerName, e);
}
}
return transformerInstances;
@Override
protected File getTargetDirectory() {
return targetDirectory;
}
@Override
protected List<File> getAdditionalClassPath() {
return Arrays.asList(testFiles);
}
@Override
protected boolean isSupportedScope(String scope) {
return testScopes.contains(scope);
}
}

View File

@ -26,9 +26,9 @@ import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;
import org.teavm.tooling.DirectorySourceFileProvider;
import org.teavm.tooling.JarSourceFileProvider;
import org.teavm.tooling.SourceFileProvider;
import org.teavm.tooling.sources.DirectorySourceFileProvider;
import org.teavm.tooling.sources.JarSourceFileProvider;
import org.teavm.tooling.sources.SourceFileProvider;
/**
*

View File

@ -0,0 +1,31 @@
/*
* Copyright 2015 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.maven;
import java.io.File;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
/**
*
* @author Alexey Andreev
*/
@Mojo(name = "run-tests", defaultPhase = LifecyclePhase.TEST)
public class RunTestsMojo {
@Parameter(defaultValue = "${project.build.directory}/javascript-tests")
private File targetDirectory;
}

View File

@ -35,7 +35,9 @@ import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.chrome.ChromeDriver;
import org.teavm.tooling.TeaVMTestCase;
import org.teavm.tooling.testing.TestCase;
import org.teavm.tooling.testing.TestGroup;
import org.teavm.tooling.testing.TestPlan;
/**
*
@ -43,13 +45,15 @@ import org.teavm.tooling.TeaVMTestCase;
*/
public class SeleniumTestRunner {
private URL url;
private WebDriver webDriver;
private int numThreads = 1;
private ThreadLocal<WebDriver> webDriver = new ThreadLocal<>();
private BlockingQueue<Runnable> seleniumTaskQueue = new LinkedBlockingQueue<>();
private CountDownLatch latch = new CountDownLatch(1);
private volatile boolean seleniumStopped = false;
private Log log;
private List<TestResult> report = new CopyOnWriteArrayList<>();
private ThreadLocal<List<TestResult>> localReport = new ThreadLocal<>();
private File directory = new File(".");
public URL getUrl() {
return url;
@ -63,28 +67,55 @@ public class SeleniumTestRunner {
this.log = log;
}
public void detectSelenium() {
if (url == null) {
return;
}
ChromeDriver driver = new ChromeDriver();
webDriver = driver;
new Thread(() -> {
localReport.set(new ArrayList<>());
while (!seleniumStopped) {
Runnable task;
try {
task = seleniumTaskQueue.poll(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
break;
}
if (task != null) {
task.run();
}
public File getDirectory() {
return directory;
}
public void setDirectory(File directory) {
this.directory = directory;
}
public int getNumThreads() {
return numThreads;
}
public void setNumThreads(int numThreads) {
this.numThreads = numThreads;
}
public void run(TestPlan testPlan) {
initSelenium();
for (TestGroup group : testPlan.getGroups()) {
for (TestCase testCase : group.getTestCases()) {
run(testPlan.getRuntimeScript(), testCase);
}
report.addAll(localReport.get());
localReport.remove();
}).start();
}
stopSelenium();
waitForCompletion();
}
private void initSelenium() {
for (int i = 0; i < numThreads; ++i) {
new Thread(() -> {
ChromeDriver driver = new ChromeDriver();
webDriver.set(driver);
localReport.set(new ArrayList<>());
while (!seleniumStopped) {
Runnable task;
try {
task = seleniumTaskQueue.poll(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
break;
}
if (task != null) {
task.run();
}
}
report.addAll(localReport.get());
localReport.remove();
webDriver.remove();
}).start();
}
}
private void addSeleniumTask(Runnable runnable) {
@ -93,14 +124,14 @@ public class SeleniumTestRunner {
}
}
public void stopSelenium() {
private void stopSelenium() {
addSeleniumTask(() -> {
seleniumStopped = true;
latch.countDown();
});
}
public void waitForSelenium() {
private void waitForCompletion() {
try {
latch.await();
} catch (InterruptedException e) {
@ -108,21 +139,18 @@ public class SeleniumTestRunner {
}
}
public void run(TeaVMTestCase testCase) {
addSeleniumTask(() -> runImpl(testCase));
private void run(String runtimeScript, TestCase testCase) {
addSeleniumTask(() -> runImpl(runtimeScript, testCase));
}
private void runImpl(TeaVMTestCase testCase) {
if (webDriver == null) {
return;
}
webDriver.manage().timeouts().setScriptTimeout(5, TimeUnit.SECONDS);
private void runImpl(String runtimeScript, TestCase testCase) {
webDriver.get().manage().timeouts().setScriptTimeout(2, TimeUnit.SECONDS);
JavascriptExecutor js = (JavascriptExecutor) webDriver;
try {
String result = (String) js.executeAsyncScript(
readResource("teavm-selenium.js"),
readFile(testCase.getRuntimeScript()),
readFile(testCase.getTestScript()),
readFile(new File(directory, runtimeScript)),
readFile(new File(directory, testCase.getTestScript())),
readResource("teavm-selenium-adapter.js"));
ObjectMapper mapper = new ObjectMapper();
ObjectNode resultObject = (ObjectNode) mapper.readTree(result);

View File

@ -21,6 +21,7 @@
<groupId>org.teavm</groupId>
<artifactId>teavm</artifactId>
<version>0.4.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<artifactId>teavm-maven</artifactId>