Merge branch 'selenium'

This commit is contained in:
Alexey Andreev 2015-10-10 12:45:05 +03:00
commit 02d853adf7
87 changed files with 1941 additions and 680 deletions

13
.travis.yml Normal file
View File

@ -0,0 +1,13 @@
language: java
jdk:
- oraclejdk8
cache:
directories:
- $HOME/.m2
script: >
mvn test \
-Dteavm.test.skip=false \
-Dteavm.test.selenium="http://$SAUCE_USER_NAME:$SAUCE_ACCESS_KEY@ondemand.saucelabs.com:80/wd/hub" \
-Dteavm.test.threads=2
after_script:
- rm -rf $HOME/.m2/repository/org/teavm

View File

@ -1,6 +1,8 @@
TeaVM TeaVM
===== =====
[![Build Status](https://travis-ci.org/konsoletyper/teavm.svg?branch=selenium)](https://travis-ci.org/konsoletyper/teavm)
What is TeaVM? What is TeaVM?
-------------- --------------

View File

@ -45,6 +45,11 @@
<artifactId>hppc</artifactId> <artifactId>hppc</artifactId>
<version>0.6.1</version> <version>0.6.1</version>
</dependency> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<optional>true</optional>
</dependency>
</dependencies> </dependencies>
<name>TeaVM core</name> <name>TeaVM core</name>

View File

@ -15,6 +15,8 @@
*/ */
package org.teavm.model; package org.teavm.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import java.util.Arrays; import java.util.Arrays;
/** /**
@ -132,6 +134,7 @@ public class MethodReference {
} }
@Override @Override
@JsonValue
public String toString() { public String toString() {
if (reprCache == null) { if (reprCache == null) {
reprCache = className + "." + name + signatureToString(); reprCache = className + "." + name + signatureToString();
@ -139,6 +142,7 @@ public class MethodReference {
return reprCache; return reprCache;
} }
@JsonCreator
public static MethodReference parse(String string) { public static MethodReference parse(String string) {
MethodReference reference = parseIfPossible(string); MethodReference reference = parseIfPossible(string);
if (reference == null) { if (reference == null) {

View File

@ -74,12 +74,11 @@
<execution> <execution>
<id>generate-javascript-tests</id> <id>generate-javascript-tests</id>
<goals> <goals>
<goal>build-test-javascript</goal> <goal>testCompile</goal>
</goals> </goals>
<phase>process-test-classes</phase>
<configuration> <configuration>
<minifying>false</minifying> <minifying>false</minifying>
<outputDir>${project.build.directory}/javascript-test</outputDir> <targetDirectory>${project.build.directory}/javascript-test</targetDirectory>
<debugInformationGenerated>true</debugInformationGenerated> <debugInformationGenerated>true</debugInformationGenerated>
<sourceMapsGenerated>true</sourceMapsGenerated> <sourceMapsGenerated>true</sourceMapsGenerated>
</configuration> </configuration>
@ -87,13 +86,12 @@
<execution> <execution>
<id>generate-javascript-tck</id> <id>generate-javascript-tck</id>
<goals> <goals>
<goal>build-test-javascript</goal> <goal>testCompile</goal>
</goals> </goals>
<phase>process-test-classes</phase>
<configuration> <configuration>
<minifying>false</minifying> <minifying>false</minifying>
<scanDependencies>true</scanDependencies> <scanDependencies>true</scanDependencies>
<outputDir>${project.build.directory}/javascript-tck</outputDir> <targetDirectory>${project.build.directory}/javascript-tck</targetDirectory>
<adapterClass>org.teavm.html4j.testing.KOTestAdapter</adapterClass> <adapterClass>org.teavm.html4j.testing.KOTestAdapter</adapterClass>
<transformers> <transformers>
<param>org.teavm.javascript.NullPointerExceptionTransformer</param> <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> <groupId>org.teavm</groupId>
<artifactId>teavm</artifactId> <artifactId>teavm</artifactId>
<version>0.4.0-SNAPSHOT</version> <version>0.4.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent> </parent>
<artifactId>teavm-jso-apis</artifactId> <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> <groupId>org.teavm</groupId>
<artifactId>teavm</artifactId> <artifactId>teavm</artifactId>
<version>0.4.0-SNAPSHOT</version> <version>0.4.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent> </parent>
<artifactId>teavm-jso</artifactId> <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> <groupId>org.teavm</groupId>
<artifactId>teavm</artifactId> <artifactId>teavm</artifactId>
<version>0.4.0-SNAPSHOT</version> <version>0.4.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent> </parent>
<artifactId>teavm-jso-impl</artifactId> <artifactId>teavm-jso-impl</artifactId>

View File

@ -40,11 +40,6 @@
<artifactId>teavm-jso-apis</artifactId> <artifactId>teavm-jso-apis</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-dom</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>

27
pom.xml
View File

@ -69,7 +69,8 @@
<html4j.version>1.2</html4j.version> <html4j.version>1.2</html4j.version>
<jetty.version>9.2.1.v20140609</jetty.version> <jetty.version>9.2.1.v20140609</jetty.version>
<slf4j.version>1.7.7</slf4j.version> <slf4j.version>1.7.7</slf4j.version>
<checker.version>1.9.3</checker.version> <selenium.version>2.47.2</selenium.version>
<jackson.version>2.6.2</jackson.version>
</properties> </properties>
<modules> <modules>
@ -81,6 +82,7 @@
<module>html4j</module> <module>html4j</module>
<module>samples</module> <module>samples</module>
<module>platform</module> <module>platform</module>
<module>tools/core</module>
<module>tools/cli</module> <module>tools/cli</module>
<module>tools/maven</module> <module>tools/maven</module>
<module>tools/chrome-rdp</module> <module>tools/chrome-rdp</module>
@ -166,13 +168,26 @@
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version> <version>${slf4j.version}</version>
</dependency> </dependency>
<!--
<dependency> <dependency>
<groupId>org.checkerframework</groupId> <groupId>org.seleniumhq.selenium</groupId>
<artifactId>checker</artifactId> <artifactId>selenium-java</artifactId>
<version>${checker.version}</version> <version>${selenium.version}</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<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> </dependency>
-->
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>

View File

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

View File

@ -27,13 +27,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.teavm</groupId> <groupId>org.teavm</groupId>
<artifactId>teavm-jso</artifactId> <artifactId>teavm-jso-apis</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-dom</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@ -111,9 +105,8 @@
<executions> <executions>
<execution> <execution>
<id>web-client</id> <id>web-client</id>
<phase>prepare-package</phase>
<goals> <goals>
<goal>build-javascript</goal> <goal>compile</goal>
</goals> </goals>
<configuration> <configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory> <targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>

View File

@ -42,12 +42,6 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-dom</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId> <artifactId>javax.servlet-api</artifactId>
@ -76,9 +70,8 @@
<executions> <executions>
<execution> <execution>
<id>web-client</id> <id>web-client</id>
<phase>prepare-package</phase>
<goals> <goals>
<goal>build-javascript</goal> <goal>compile</goal>
</goals> </goals>
<configuration> <configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory> <targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>

View File

@ -53,7 +53,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.teavm</groupId> <groupId>org.teavm</groupId>
<artifactId>teavm-dom</artifactId> <artifactId>teavm-jso-apis</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@ -92,9 +92,8 @@
<executions> <executions>
<execution> <execution>
<id>web-client</id> <id>web-client</id>
<phase>prepare-package</phase>
<goals> <goals>
<goal>build-javascript</goal> <goal>compile</goal>
</goals> </goals>
<configuration> <configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory> <targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>

View File

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

View File

@ -38,13 +38,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.teavm</groupId> <groupId>org.teavm</groupId>
<artifactId>teavm-jso</artifactId> <artifactId>teavm-jso-apis</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-dom</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@ -78,12 +72,11 @@
<id>web-client</id> <id>web-client</id>
<phase>prepare-package</phase> <phase>prepare-package</phase>
<goals> <goals>
<goal>build-javascript</goal> <goal>compile</goal>
</goals> </goals>
<configuration> <configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory> <targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>
<mainClass>org.teavm.samples.storage.Application</mainClass> <mainClass>org.teavm.samples.storage.Application</mainClass>
<runtime>SEPARATE</runtime>
<minifying>false</minifying> <minifying>false</minifying>
<debugInformationGenerated>true</debugInformationGenerated> <debugInformationGenerated>true</debugInformationGenerated>
<sourceMapsGenerated>true</sourceMapsGenerated> <sourceMapsGenerated>true</sourceMapsGenerated>

View File

@ -38,13 +38,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.teavm</groupId> <groupId>org.teavm</groupId>
<artifactId>teavm-jso</artifactId> <artifactId>teavm-jso-apis</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-dom</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@ -76,9 +70,8 @@
<executions> <executions>
<execution> <execution>
<id>web-client</id> <id>web-client</id>
<phase>prepare-package</phase>
<goals> <goals>
<goal>build-javascript</goal> <goal>compile</goal>
</goals> </goals>
<configuration> <configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory> <targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>

View File

@ -27,6 +27,13 @@
<name>TeaVM tests</name> <name>TeaVM tests</name>
<description>Project containing TeaVM tests, as it is impossible to test each module separately</description> <description>Project containing TeaVM tests, as it is impossible to test each module separately</description>
<properties>
<teavm.test.incremental>false</teavm.test.incremental>
<teavm.test.threads>1</teavm.test.threads>
<teavm.test.selenium></teavm.test.selenium>
<teavm.test.skip>true</teavm.test.skip>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.teavm</groupId> <groupId>org.teavm</groupId>
@ -72,9 +79,8 @@
<execution> <execution>
<id>generate-javascript-tests</id> <id>generate-javascript-tests</id>
<goals> <goals>
<goal>build-test-javascript</goal> <goal>testCompile</goal>
</goals> </goals>
<phase>process-test-classes</phase>
<configuration> <configuration>
<minifying>false</minifying> <minifying>false</minifying>
<scanDependencies>true</scanDependencies> <scanDependencies>true</scanDependencies>
@ -89,6 +95,17 @@
<incremental>${teavm.test.incremental}</incremental> <incremental>${teavm.test.incremental}</incremental>
</configuration> </configuration>
</execution> </execution>
<execution>
<id>run-javascript-tests</id>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skip>${teavm.test.skip}</skip>
<numThreads>${teavm.test.threads}</numThreads>
<seleniumURL>${teavm.test.selenium}</seleniumURL>
</configuration>
</execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>

View File

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

View File

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

View File

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

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

@ -0,0 +1,76 @@
<!--
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>
<packaging>bundle</packaging>
<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>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>org.teavm.*</Export-Package>
<Bundle-SymbolicName>teavm-tooling</Bundle-SymbolicName>
</instructions>
</configuration>
</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.javascript.RenderingContext;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.parsing.ClasspathClassHolderSource; 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.*;
import org.teavm.vm.spi.AbstractRendererListener; import org.teavm.vm.spi.AbstractRendererListener;
@ -36,7 +38,7 @@ import org.teavm.vm.spi.AbstractRendererListener;
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public class TeaVMTool { public class TeaVMTool implements BaseTeaVMTool {
private File targetDirectory = new File("."); private File targetDirectory = new File(".");
private String targetFileName = "classes.js"; private String targetFileName = "classes.js";
private boolean minifying = true; private boolean minifying = true;
@ -69,6 +71,7 @@ public class TeaVMTool {
return targetDirectory; return targetDirectory;
} }
@Override
public void setTargetDirectory(File targetDirectory) { public void setTargetDirectory(File targetDirectory) {
this.targetDirectory = targetDirectory; this.targetDirectory = targetDirectory;
} }
@ -85,6 +88,7 @@ public class TeaVMTool {
return minifying; return minifying;
} }
@Override
public void setMinifying(boolean minifying) { public void setMinifying(boolean minifying) {
this.minifying = minifying; this.minifying = minifying;
} }
@ -93,6 +97,7 @@ public class TeaVMTool {
return incremental; return incremental;
} }
@Override
public void setIncremental(boolean incremental) { public void setIncremental(boolean incremental) {
this.incremental = incremental; this.incremental = incremental;
} }
@ -133,6 +138,7 @@ public class TeaVMTool {
return debugInformationGenerated; return debugInformationGenerated;
} }
@Override
public void setDebugInformationGenerated(boolean debugInformationGenerated) { public void setDebugInformationGenerated(boolean debugInformationGenerated) {
this.debugInformationGenerated = debugInformationGenerated; this.debugInformationGenerated = debugInformationGenerated;
} }
@ -149,6 +155,7 @@ public class TeaVMTool {
return sourceMapsFileGenerated; return sourceMapsFileGenerated;
} }
@Override
public void setSourceMapsFileGenerated(boolean sourceMapsFileGenerated) { public void setSourceMapsFileGenerated(boolean sourceMapsFileGenerated) {
this.sourceMapsFileGenerated = sourceMapsFileGenerated; this.sourceMapsFileGenerated = sourceMapsFileGenerated;
} }
@ -157,14 +164,17 @@ public class TeaVMTool {
return sourceFilesCopied; return sourceFilesCopied;
} }
@Override
public void setSourceFilesCopied(boolean sourceFilesCopied) { public void setSourceFilesCopied(boolean sourceFilesCopied) {
this.sourceFilesCopied = sourceFilesCopied; this.sourceFilesCopied = sourceFilesCopied;
} }
@Override
public Properties getProperties() { public Properties getProperties() {
return properties; return properties;
} }
@Override
public List<ClassHolderTransformer> getTransformers() { public List<ClassHolderTransformer> getTransformers() {
return transformers; return transformers;
} }
@ -181,6 +191,7 @@ public class TeaVMTool {
return log; return log;
} }
@Override
public void setLog(TeaVMToolLog log) { public void setLog(TeaVMToolLog log) {
this.log = log; this.log = log;
} }
@ -189,6 +200,7 @@ public class TeaVMTool {
return classLoader; return classLoader;
} }
@Override
public void setClassLoader(ClassLoader classLoader) { public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader; this.classLoader = classLoader;
} }
@ -245,6 +257,7 @@ public class TeaVMTool {
return resources; return resources;
} }
@Override
public void addSourceFileProvider(SourceFileProvider sourceFileProvider) { public void addSourceFileProvider(SourceFileProvider sourceFileProvider) {
sourceFileProviders.add(sourceFileProvider); sourceFileProviders.add(sourceFileProvider);
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -13,10 +13,19 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.teavm.tooling; package org.teavm.tooling.testing;
import java.io.*; import java.io.File;
import java.util.*; import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
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.apache.commons.io.IOUtils;
import org.teavm.common.FiniteExecutor; import org.teavm.common.FiniteExecutor;
import org.teavm.common.SimpleFiniteExecutor; import org.teavm.common.SimpleFiniteExecutor;
@ -26,10 +35,26 @@ import org.teavm.debugging.information.DebugInformationBuilder;
import org.teavm.javascript.EmptyRegularMethodNodeCache; import org.teavm.javascript.EmptyRegularMethodNodeCache;
import org.teavm.javascript.InMemoryRegularMethodNodeCache; import org.teavm.javascript.InMemoryRegularMethodNodeCache;
import org.teavm.javascript.MethodNodeCache; import org.teavm.javascript.MethodNodeCache;
import org.teavm.model.*; import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderSource;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.CopyClassHolderSource;
import org.teavm.model.InMemoryProgramCache;
import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReference;
import org.teavm.model.PreOptimizingClassHolderSource;
import org.teavm.model.ProgramCache;
import org.teavm.model.ValueType;
import org.teavm.parsing.ClasspathClassHolderSource; import org.teavm.parsing.ClasspathClassHolderSource;
import org.teavm.testing.JUnitTestAdapter; import org.teavm.testing.JUnitTestAdapter;
import org.teavm.testing.TestAdapter; 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.DirectoryBuildTarget;
import org.teavm.vm.TeaVM; import org.teavm.vm.TeaVM;
import org.teavm.vm.TeaVMBuilder; import org.teavm.vm.TeaVMBuilder;
@ -38,10 +63,7 @@ import org.teavm.vm.TeaVMBuilder;
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public class TeaVMTestTool { public class TeaVMTestTool implements BaseTeaVMTool {
private Map<String, List<MethodReference>> groupedMethods = new HashMap<>();
private Map<MethodReference, String> fileNames = new HashMap<>();
private List<MethodReference> testMethods = new ArrayList<>();
private File outputDir = new File("."); private File outputDir = new File(".");
private boolean minifying = true; private boolean minifying = true;
private int numThreads = 1; private int numThreads = 1;
@ -54,19 +76,25 @@ public class TeaVMTestTool {
private ClassLoader classLoader = TeaVMTestTool.class.getClassLoader(); private ClassLoader classLoader = TeaVMTestTool.class.getClassLoader();
private TeaVMToolLog log = new EmptyTeaVMToolLog(); private TeaVMToolLog log = new EmptyTeaVMToolLog();
private boolean debugInformationGenerated; private boolean debugInformationGenerated;
private boolean sourceMapsGenerated; private boolean sourceMapsFileGenerated;
private boolean sourceFilesCopied; private boolean sourceFilesCopied;
private boolean incremental; private boolean incremental;
private List<SourceFileProvider> sourceFileProviders = new ArrayList<>(); private List<SourceFileProvider> sourceFileProviders = new ArrayList<>();
private MethodNodeCache astCache; private MethodNodeCache astCache;
private ProgramCache programCache; private ProgramCache programCache;
private SourceFilesCopier sourceFilesCopier; private SourceFilesCopier sourceFilesCopier;
private List<TestClassBuilder> testPlan = new ArrayList<>();
private int fileIndexGenerator;
private long startTime;
private int testCount;
private AtomicInteger testsBuilt = new AtomicInteger();
public File getOutputDir() { public File getOutputDir() {
return outputDir; return outputDir;
} }
public void setOutputDir(File outputDir) { @Override
public void setTargetDirectory(File outputDir) {
this.outputDir = outputDir; this.outputDir = outputDir;
} }
@ -74,6 +102,7 @@ public class TeaVMTestTool {
return minifying; return minifying;
} }
@Override
public void setMinifying(boolean minifying) { public void setMinifying(boolean minifying) {
this.minifying = minifying; this.minifying = minifying;
} }
@ -94,6 +123,7 @@ public class TeaVMTestTool {
this.adapter = adapter; this.adapter = adapter;
} }
@Override
public List<ClassHolderTransformer> getTransformers() { public List<ClassHolderTransformer> getTransformers() {
return transformers; return transformers;
} }
@ -102,6 +132,7 @@ public class TeaVMTestTool {
return additionalScripts; return additionalScripts;
} }
@Override
public Properties getProperties() { public Properties getProperties() {
return properties; return properties;
} }
@ -114,6 +145,7 @@ public class TeaVMTestTool {
return classLoader; return classLoader;
} }
@Override
public void setClassLoader(ClassLoader classLoader) { public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader; this.classLoader = classLoader;
} }
@ -122,6 +154,7 @@ public class TeaVMTestTool {
return log; return log;
} }
@Override
public void setLog(TeaVMToolLog log) { public void setLog(TeaVMToolLog log) {
this.log = log; this.log = log;
} }
@ -130,6 +163,7 @@ public class TeaVMTestTool {
return incremental; return incremental;
} }
@Override
public void setIncremental(boolean incremental) { public void setIncremental(boolean incremental) {
this.incremental = incremental; this.incremental = incremental;
} }
@ -138,31 +172,36 @@ public class TeaVMTestTool {
return debugInformationGenerated; return debugInformationGenerated;
} }
@Override
public void setDebugInformationGenerated(boolean debugInformationGenerated) { public void setDebugInformationGenerated(boolean debugInformationGenerated) {
this.debugInformationGenerated = debugInformationGenerated; this.debugInformationGenerated = debugInformationGenerated;
} }
public boolean isSourceMapsGenerated() { public boolean isSourceMapsFileGenerated() {
return sourceMapsGenerated; return sourceMapsFileGenerated;
} }
public void setSourceMapsGenerated(boolean sourceMapsGenerated) { @Override
this.sourceMapsGenerated = sourceMapsGenerated; public void setSourceMapsFileGenerated(boolean sourceMapsFileGenerated) {
this.sourceMapsFileGenerated = sourceMapsFileGenerated;
} }
public boolean isSourceFilesCopied() { public boolean isSourceFilesCopied() {
return sourceFilesCopied; return sourceFilesCopied;
} }
@Override
public void setSourceFilesCopied(boolean sourceFilesCopied) { public void setSourceFilesCopied(boolean sourceFilesCopied) {
this.sourceFilesCopied = sourceFilesCopied; this.sourceFilesCopied = sourceFilesCopied;
} }
@Override
public void addSourceFileProvider(SourceFileProvider sourceFileProvider) { public void addSourceFileProvider(SourceFileProvider sourceFileProvider) {
sourceFileProviders.add(sourceFileProvider); sourceFileProviders.add(sourceFileProvider);
} }
public void generate() throws TeaVMToolException { public TestPlan generate() throws TeaVMToolException {
testsBuilt.set(0);
Runnable finalizer = null; Runnable finalizer = null;
try { try {
new File(outputDir, "tests").mkdirs(); new File(outputDir, "tests").mkdirs();
@ -184,12 +223,17 @@ public class TeaVMTestTool {
if (incremental) { if (incremental) {
classSource = new PreOptimizingClassHolderSource(classSource); classSource = new PreOptimizingClassHolderSource(classSource);
} }
List<TestGroup> groups = new ArrayList<>();
for (String testClass : testClasses) { for (String testClass : testClasses) {
ClassHolder classHolder = classSource.get(testClass); ClassHolder classHolder = classSource.get(testClass);
if (classHolder == null) { if (classHolder == null) {
throw new TeaVMToolException("Could not find class " + testClass); throw new TeaVMToolException("Could not find class " + testClass);
} }
findTests(classHolder); TestGroup group = findTests(classHolder);
if (group != null) {
groups.add(group);
}
} }
includeAdditionalScripts(classLoader); includeAdditionalScripts(classLoader);
@ -198,83 +242,26 @@ public class TeaVMTestTool {
astCache = new InMemoryRegularMethodNodeCache(); astCache = new InMemoryRegularMethodNodeCache();
programCache = new InMemoryProgramCache(); programCache = new InMemoryProgramCache();
} }
File allTestsFile = new File(outputDir, "tests/all.js"); writeMetadata();
try (Writer allTestsWriter = new OutputStreamWriter(new FileOutputStream(allTestsFile), "UTF-8")) {
allTestsWriter.write("prepare = function() {\n");
allTestsWriter.write(" return new JUnitServer(document.body).readTests([");
boolean first = true;
for (String testClass : testClasses) {
Collection<MethodReference> methods = groupedMethods.get(testClass);
if (methods == null) {
continue;
}
if (!first) {
allTestsWriter.append(",");
}
first = false;
allTestsWriter.append("\n { name : \"").append(testClass).append("\", methods : [");
boolean firstMethod = true;
for (MethodReference methodRef : methods) {
String scriptName = "tests/" + fileNames.size() + ".js";
fileNames.put(methodRef, scriptName);
if (!firstMethod) {
allTestsWriter.append(",");
}
firstMethod = false;
allTestsWriter.append("\n { name : \"" + methodRef.getName() + "\", script : \""
+ scriptName + "\", expected : [");
MethodHolder methodHolder = classSource.get(testClass).getMethod(
methodRef.getDescriptor());
boolean firstException = true;
for (String exception : adapter.getExpectedExceptions(methodHolder)) {
if (!firstException) {
allTestsWriter.append(", ");
}
firstException = false;
allTestsWriter.append("\"" + exception + "\"");
}
allTestsWriter.append("], additionalScripts : [");
for (int i = 0; i < additionalScriptLocalPaths.size(); ++i) {
if (i > 0) {
allTestsWriter.append(", ");
}
escapeString(additionalScriptLocalPaths.get(i), allTestsWriter);
}
allTestsWriter.append("] }");
}
allTestsWriter.append("] }");
}
allTestsWriter.write("], function() {}); }");
}
int methodsGenerated = 0;
log.info("Generating test files");
sourceFilesCopier = new SourceFilesCopier(sourceFileProviders);
sourceFilesCopier.setLog(log);
FiniteExecutor executor = new SimpleFiniteExecutor(); FiniteExecutor executor = new SimpleFiniteExecutor();
if (numThreads != 1) { if (numThreads != 1) {
int threads = numThreads != 0 ? numThreads : Runtime.getRuntime().availableProcessors(); int threads = numThreads != 0 ? numThreads : Runtime.getRuntime().availableProcessors();
final ThreadPoolFiniteExecutor threadedExecutor = new ThreadPoolFiniteExecutor(threads); ThreadPoolFiniteExecutor threadedExecutor = new ThreadPoolFiniteExecutor(threads);
finalizer = () -> threadedExecutor.stop(); finalizer = () -> threadedExecutor.stop();
executor = threadedExecutor; executor = threadedExecutor;
} }
for (final MethodReference method : testMethods) { startTime = System.currentTimeMillis();
final ClassHolderSource builderClassSource = classSource; int methodsGenerated = writeMethods(executor, classSource);
executor.execute(() -> {
log.debug("Building test for " + method);
try {
decompileClassesForTest(classLoader, new CopyClassHolderSource(builderClassSource), method,
fileNames.get(method));
} catch (IOException e) {
log.error("Error generating JavaScript", e);
}
});
++methodsGenerated;
}
executor.complete();
if (sourceFilesCopied) { if (sourceFilesCopied) {
sourceFilesCopier.copy(new File(new File(outputDir, "tests"), "src")); 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) { } catch (IOException e) {
throw new TeaVMToolException("IO error occured generating JavaScript files", e); throw new TeaVMToolException("IO error occured generating JavaScript files", e);
} finally { } finally {
@ -284,6 +271,74 @@ public class TeaVMTestTool {
} }
} }
private void writeMetadata() throws IOException {
File allTestsFile = new File(outputDir, "tests/all.js");
try (Writer allTestsWriter = new OutputStreamWriter(new FileOutputStream(allTestsFile), "UTF-8")) {
allTestsWriter.write("prepare = function() {\n");
allTestsWriter.write(" return new JUnitServer(document.body).readTests([");
boolean first = true;
for (TestClassBuilder testClass : testPlan) {
if (!first) {
allTestsWriter.append(",");
}
first = false;
allTestsWriter.append("\n { name : \"").append(testClass.getClassName())
.append("\", methods : [");
boolean firstMethod = true;
for (TestMethodBuilder testMethod : testClass.getMethods()) {
String scriptName = testMethod.getFileName();
if (!firstMethod) {
allTestsWriter.append(",");
}
firstMethod = false;
allTestsWriter.append("\n { name : \"" + testMethod.getMethod().getName()
+ "\", script : \"" + scriptName + "\", expected : [");
boolean firstException = true;
for (String exception : testMethod.getExpectedExceptions()) {
if (!firstException) {
allTestsWriter.append(", ");
}
firstException = false;
allTestsWriter.append("\"" + exception + "\"");
}
allTestsWriter.append("], additionalScripts : [");
for (int i = 0; i < additionalScriptLocalPaths.size(); ++i) {
if (i > 0) {
allTestsWriter.append(", ");
}
escapeString(additionalScriptLocalPaths.get(i), allTestsWriter);
}
allTestsWriter.append("] }");
}
allTestsWriter.append("] }");
}
allTestsWriter.write("], function() {}); }");
}
}
private int writeMethods(FiniteExecutor executor, ClassHolderSource classSource) {
int methodsGenerated = 0;
log.info("Generating test files");
sourceFilesCopier = new SourceFilesCopier(sourceFileProviders);
sourceFilesCopier.setLog(log);
for (TestClassBuilder testClass : testPlan) {
for (TestMethodBuilder testMethod : testClass.getMethods()) {
executor.execute(() -> {
log.debug("Building test for " + testMethod.getMethod());
try {
decompileClassesForTest(classLoader, new CopyClassHolderSource(classSource),
testMethod);
} catch (IOException e) {
log.error("Error generating JavaScript", e);
}
});
++methodsGenerated;
}
}
executor.complete();
return methodsGenerated;
}
private void resourceToFile(String resource, String fileName) throws IOException { private void resourceToFile(String resource, String fileName) throws IOException {
try (InputStream input = TeaVMTestTool.class.getClassLoader().getResourceAsStream(resource)) { try (InputStream input = TeaVMTestTool.class.getClassLoader().getResourceAsStream(resource)) {
try (OutputStream output = new FileOutputStream(new File(outputDir, fileName))) { try (OutputStream output = new FileOutputStream(new File(outputDir, fileName))) {
@ -292,19 +347,34 @@ public class TeaVMTestTool {
} }
} }
private void findTests(ClassHolder cls) { private TestGroup findTests(ClassHolder cls) {
List<TestCase> cases = new ArrayList<>();
TestClassBuilder testClass = new TestClassBuilder(cls.getName());
for (MethodHolder method : cls.getMethods()) { for (MethodHolder method : cls.getMethods()) {
if (adapter.acceptMethod(method)) { if (adapter.acceptMethod(method)) {
MethodReference ref = new MethodReference(cls.getName(), method.getDescriptor()); MethodReference ref = new MethodReference(cls.getName(), method.getDescriptor());
testMethods.add(ref); String fileName = "tests/" + fileIndexGenerator++ + ".js";
List<MethodReference> group = groupedMethods.get(cls.getName());
if (group == null) { List<String> exceptions = new ArrayList<>();
group = new ArrayList<>(); for (String exception : adapter.getExpectedExceptions(method)) {
groupedMethods.put(cls.getName(), group); exceptions.add(exception);
} }
group.add(ref);
TestMethodBuilder testMethod = new TestMethodBuilder(ref, fileName, exceptions);
testClass.getMethods().add(testMethod);
String debugTable = debugInformationGenerated ? testMethod.getFileName() + ".teavmdbg" : null;
cases.add(new TestCase(ref.toString(), testMethod.getFileName(), debugTable,
testMethod.getExpectedExceptions()));
++testCount;
} }
} }
if (!testClass.getMethods().isEmpty()) {
testPlan.add(testClass);
return new TestGroup(cls.getName(), cases);
} else {
return null;
}
} }
private void includeAdditionalScripts(ClassLoader classLoader) throws TeaVMToolException { private void includeAdditionalScripts(ClassLoader classLoader) throws TeaVMToolException {
@ -332,7 +402,8 @@ public class TeaVMTestTool {
} }
private void decompileClassesForTest(ClassLoader classLoader, ClassHolderSource classSource, private void decompileClassesForTest(ClassLoader classLoader, ClassHolderSource classSource,
MethodReference methodRef, String targetName) throws IOException { TestMethodBuilder testMethod) throws IOException {
String targetName = testMethod.getFileName();
TeaVM vm = new TeaVMBuilder() TeaVM vm = new TeaVMBuilder()
.setClassLoader(classLoader) .setClassLoader(classLoader)
.setClassSource(classSource) .setClassSource(classSource)
@ -347,9 +418,11 @@ public class TeaVMTestTool {
for (ClassHolderTransformer transformer : transformers) { for (ClassHolderTransformer transformer : transformers) {
vm.add(transformer); vm.add(transformer);
} }
File file = new File(outputDir, targetName);
DebugInformationBuilder debugInfoBuilder = sourceMapsGenerated || debugInformationGenerated File file = new File(outputDir, testMethod.getFileName());
DebugInformationBuilder debugInfoBuilder = sourceMapsFileGenerated || debugInformationGenerated
? new DebugInformationBuilder() : null; ? new DebugInformationBuilder() : null;
MethodReference methodRef = testMethod.getMethod();
try (Writer innerWriter = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) { try (Writer innerWriter = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) {
MethodReference cons = new MethodReference(methodRef.getClassName(), "<init>", ValueType.VOID); MethodReference cons = new MethodReference(methodRef.getClassName(), "<init>", ValueType.VOID);
MethodReference exceptionMsg = new MethodReference(ExceptionHelper.class, "showException", MethodReference exceptionMsg = new MethodReference(ExceptionHelper.class, "showException",
@ -362,7 +435,7 @@ public class TeaVMTestTool {
vm.build(innerWriter, new DirectoryBuildTarget(outputDir)); vm.build(innerWriter, new DirectoryBuildTarget(outputDir));
innerWriter.append("\n"); innerWriter.append("\n");
innerWriter.append("\nJUnitClient.run();"); innerWriter.append("\nJUnitClient.run();");
if (sourceMapsGenerated) { if (sourceMapsFileGenerated) {
String sourceMapsFileName = targetName.substring(targetName.lastIndexOf('/') + 1) + ".map"; String sourceMapsFileName = targetName.substring(targetName.lastIndexOf('/') + 1) + ".map";
innerWriter.append("\n//# sourceMappingURL=").append(sourceMapsFileName); innerWriter.append("\n//# sourceMappingURL=").append(sourceMapsFileName);
} }
@ -376,13 +449,16 @@ public class TeaVMTestTool {
} }
} }
} }
if (sourceMapsGenerated) {
if (debugInformationGenerated) {
DebugInformation debugInfo = debugInfoBuilder.getDebugInformation(); DebugInformation debugInfo = debugInfoBuilder.getDebugInformation();
try (OutputStream debugInfoOut = new FileOutputStream(new File(outputDir, targetName + ".teavmdbg"))) { File debugTableFile = new File(outputDir, targetName + ".teavmdbg");
try (OutputStream debugInfoOut = new FileOutputStream(debugTableFile)) {
debugInfo.write(debugInfoOut); debugInfo.write(debugInfoOut);
} }
} }
if (sourceMapsGenerated) {
if (sourceMapsFileGenerated) {
DebugInformation debugInfo = debugInfoBuilder.getDebugInformation(); DebugInformation debugInfo = debugInfoBuilder.getDebugInformation();
String sourceMapsFileName = targetName + ".map"; String sourceMapsFileName = targetName + ".map";
try (Writer sourceMapsOut = new OutputStreamWriter(new FileOutputStream( try (Writer sourceMapsOut = new OutputStreamWriter(new FileOutputStream(
@ -393,6 +469,20 @@ public class TeaVMTestTool {
if (sourceFilesCopied && vm.getWrittenClasses() != null) { if (sourceFilesCopied && vm.getWrittenClasses() != null) {
sourceFilesCopier.addClasses(vm.getWrittenClasses()); sourceFilesCopier.addClasses(vm.getWrittenClasses());
} }
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 { private void escapeString(String string, Writer writer) throws IOException {

View File

@ -0,0 +1,25 @@
/*
* 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;
/**
*
* @author Alexey Andreev
*/
public interface TeaVMTestToolListener {
void testGenerated(TestCase testCase);
}

View File

@ -0,0 +1,66 @@
/*
* 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 TestCase {
private String testMethod;
private String testScript;
private String debugTable;
private List<String> expectedExceptions = new ArrayList<>();
@JsonCreator
public TestCase(
@JsonProperty("testMethod") String testMethod,
@JsonProperty("script") String testScript,
@JsonProperty("debugTable") String debugTable,
@JsonProperty("expectedExceptions") List<String> expectedExceptions) {
this.testMethod = testMethod;
this.testScript = testScript;
this.debugTable = debugTable;
this.expectedExceptions = Collections.unmodifiableList(new ArrayList<>(expectedExceptions));
}
@JsonGetter
public String getTestMethod() {
return testMethod;
}
@JsonGetter("script")
public String getTestScript() {
return testScript;
}
@JsonGetter
public String getDebugTable() {
return debugTable;
}
@JsonGetter
public List<String> getExpectedExceptions() {
return expectedExceptions;
}
}

View File

@ -0,0 +1,40 @@
/*
* 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 java.util.ArrayList;
import java.util.List;
/**
*
* @author Alexey Andreev
*/
class TestClassBuilder {
private String className;
private List<TestMethodBuilder> methods = new ArrayList<>();
public TestClassBuilder(String className) {
this.className = className;
}
public String getClassName() {
return className;
}
public List<TestMethodBuilder> getMethods() {
return methods;
}
}

View File

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

View File

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

@ -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 java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
class TestMethodBuilder {
private MethodReference method;
private String fileName;
private List<String> expectedExceptions = new ArrayList<>();
public TestMethodBuilder(MethodReference method, String fileName, List<String> expectedExceptions) {
this.method = method;
this.fileName = fileName;
this.expectedExceptions = Collections.unmodifiableList(new ArrayList<>(expectedExceptions));
}
public MethodReference getMethod() {
return method;
}
public String getFileName() {
return fileName;
}
public List<String> getExpectedExceptions() {
return expectedExceptions;
}
}

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.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 TestPlan {
private String runtimeScript;
private List<TestGroup> groups = new ArrayList<>();
@JsonCreator
public TestPlan(
@JsonProperty("runtimeScript") String runtimeScript,
@JsonProperty("groups") List<TestGroup> groups) {
this.runtimeScript = runtimeScript;
this.groups = Collections.unmodifiableList(new ArrayList<>(groups));
}
@JsonGetter
public String getRuntimeScript() {
return runtimeScript;
}
@JsonGetter
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/slf4j-api-1.7.7.jar,
lib/teavm-chrome-rdp-0.4.0-SNAPSHOT.jar, lib/teavm-chrome-rdp-0.4.0-SNAPSHOT.jar,
lib/teavm-core-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-api-9.2.1.v20140609.jar,
lib/websocket-client-9.2.1.v20140609.jar, lib/websocket-client-9.2.1.v20140609.jar,
lib/websocket-common-9.2.1.v20140609.jar, lib/websocket-common-9.2.1.v20140609.jar,
@ -70,5 +71,6 @@ Export-Package: org.teavm.cache,
org.teavm.resource, org.teavm.resource,
org.teavm.testing, org.teavm.testing,
org.teavm.tooling, org.teavm.tooling,
org.teavm.tooling.sources,
org.teavm.vm, org.teavm.vm,
org.teavm.vm.spi org.teavm.vm.spi

View File

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

View File

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

View File

@ -4,7 +4,7 @@ Bundle-Name: TeaVM plugin for m2e
Bundle-SymbolicName: teavm-eclipse-m2e-plugin;singleton:=true Bundle-SymbolicName: teavm-eclipse-m2e-plugin;singleton:=true
Bundle-Version: 0.4.0.qualifier Bundle-Version: 0.4.0.qualifier
Bundle-Vendor: Alexey Andreev <konsoletyper@gmail.com> Bundle-Vendor: Alexey Andreev <konsoletyper@gmail.com>
Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: teavm-eclipse-plugin;bundle-version="[0.4.0,0.5.0)", Require-Bundle: teavm-eclipse-plugin;bundle-version="[0.4.0,0.5.0)",
org.eclipse.m2e.core;bundle-version="[1.3,2)", org.eclipse.m2e.core;bundle-version="[1.3,2)",
org.eclipse.core.runtime;bundle-version="[3.8,4.0)", org.eclipse.core.runtime;bundle-version="[3.8,4.0)",

View File

@ -7,7 +7,7 @@
<artifactId>teavm-maven-plugin</artifactId> <artifactId>teavm-maven-plugin</artifactId>
<versionRange>0.4.0-SNAPSHOT</versionRange> <versionRange>0.4.0-SNAPSHOT</versionRange>
<goals> <goals>
<goal>build-javascript</goal> <goal>compile</goal>
</goals> </goals>
</pluginExecutionFilter> </pluginExecutionFilter>
<action> <action>

View File

@ -33,7 +33,7 @@ public class TeaVMProjectConfigurator extends AbstractProjectConfigurator {
private static final String TOOL_ID = "teavm-eclipse-m2e-plugin.tool"; private static final String TOOL_ID = "teavm-eclipse-m2e-plugin.tool";
private static final String TEAVM_ARTIFACT_ID = "teavm-maven-plugin"; private static final String TEAVM_ARTIFACT_ID = "teavm-maven-plugin";
private static final String TEAVM_GROUP_ID = "org.teavm"; private static final String TEAVM_GROUP_ID = "org.teavm";
private static final String TEAVM_MAIN_GOAL = "build-javascript"; private static final String TEAVM_MAIN_GOAL = "compile";
private int executionIdGenerator; private int executionIdGenerator;
private Set<String> usedExecutionIds = new HashSet<>(); private Set<String> usedExecutionIds = new HashSet<>();
private IMaven maven; private IMaven maven;

View File

@ -4,7 +4,7 @@ Bundle-Name: TeaVM plugin for Eclipse
Bundle-SymbolicName: teavm-eclipse-plugin;singleton:=true Bundle-SymbolicName: teavm-eclipse-plugin;singleton:=true
Bundle-Version: 0.4.0.qualifier Bundle-Version: 0.4.0.qualifier
Bundle-Vendor: Alexey Andreev <konsoletyper@gmail.com> Bundle-Vendor: Alexey Andreev <konsoletyper@gmail.com>
Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-Activator: org.teavm.eclipse.TeaVMEclipsePlugin Bundle-Activator: org.teavm.eclipse.TeaVMEclipsePlugin
Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.8.0,4.0)", Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.8.0,4.0)",
org.eclipse.debug.core;bundle-version="[3.7.0,4.0)", org.eclipse.debug.core;bundle-version="[3.7.0,4.0)",
@ -48,5 +48,6 @@ Import-Package: org.teavm.cache,
org.teavm.resource, org.teavm.resource,
org.teavm.testing, org.teavm.testing,
org.teavm.tooling, org.teavm.tooling,
org.teavm.tooling.sources,
org.teavm.vm, org.teavm.vm,
org.teavm.vm.spi org.teavm.vm.spi

View File

@ -21,22 +21,62 @@ import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.util.*; import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.eclipse.core.resources.*; import org.eclipse.core.resources.IContainer;
import org.eclipse.core.runtime.*; import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.variables.IStringVariableManager; import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.VariablesPlugin; import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.jdt.core.*; import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.Signature;
import org.teavm.callgraph.CallGraph; import org.teavm.callgraph.CallGraph;
import org.teavm.callgraph.CallGraphNode; import org.teavm.callgraph.CallGraphNode;
import org.teavm.callgraph.CallSite; import org.teavm.callgraph.CallSite;
import org.teavm.diagnostics.Problem; import org.teavm.diagnostics.Problem;
import org.teavm.diagnostics.ProblemTextConsumer; import org.teavm.diagnostics.ProblemTextConsumer;
import org.teavm.model.*; import org.teavm.model.CallLocation;
import org.teavm.tooling.*; import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.FieldReference;
import org.teavm.model.InstructionLocation;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.tooling.ClassAlias;
import org.teavm.tooling.RuntimeCopyOperation;
import org.teavm.tooling.TeaVMTool;
import org.teavm.tooling.TeaVMToolException;
import org.teavm.tooling.sources.DirectorySourceFileProvider;
import org.teavm.tooling.sources.JarSourceFileProvider;
import org.teavm.tooling.sources.SourceFileProvider;
/** /**
* *

View File

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

View File

@ -50,13 +50,30 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.teavm</groupId> <groupId>org.teavm</groupId>
<artifactId>teavm-core</artifactId> <artifactId>teavm-tooling</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-io</groupId> <groupId>commons-io</groupId>
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-remote-driver</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.18</version>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
@ -91,6 +108,14 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<configuration>
<configLocation>../../../checkstyle.xml</configLocation>
<propertyExpansion>config_loc=${basedir}/../../..</propertyExpansion>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

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,96 +16,42 @@
package org.teavm.maven; package org.teavm.maven;
import java.io.File; import java.io.File;
import java.lang.reflect.Constructor; import java.util.Arrays;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
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.MojoExecutionException;
import org.apache.maven.plugin.logging.Log; 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.Mojo;
import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject; import org.teavm.tooling.ClassAlias;
import org.apache.maven.repository.RepositorySystem; import org.teavm.tooling.MethodAlias;
import org.teavm.model.ClassHolderTransformer; import org.teavm.tooling.RuntimeCopyOperation;
import org.teavm.tooling.*; import org.teavm.tooling.TeaVMTool;
import org.teavm.tooling.TeaVMToolException;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
@Mojo(name = "build-javascript", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, @Mojo(name = "compile", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME) requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME,
public class BuildJavascriptMojo extends AbstractMojo { defaultPhase = LifecyclePhase.PROCESS_CLASSES)
@Component public class BuildJavascriptMojo extends AbstractJavascriptMojo {
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") @Parameter(defaultValue = "${project.build.directory}/javascript")
private File targetDirectory; private File targetDirectory;
@Parameter(defaultValue = "${project.build.outputDirectory}")
private File classFiles;
@Parameter
private List<String> compileScopes;
@Parameter @Parameter
private String targetFileName = "classes.js"; private String targetFileName = "classes.js";
@Parameter
private boolean minifying = true;
@Parameter @Parameter
private String mainClass; private String mainClass;
@Parameter
private RuntimeCopyOperation runtime = RuntimeCopyOperation.SEPARATE;
@Parameter
private Properties properties;
@Parameter @Parameter
private boolean mainPageIncluded; private boolean mainPageIncluded;
@Parameter @Parameter
private boolean bytecodeLogging; 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 @Parameter
private ClassAlias[] classAliases; private ClassAlias[] classAliases;
@ -115,144 +61,37 @@ public class BuildJavascriptMojo extends AbstractMojo {
@Parameter @Parameter
private boolean stopOnErrors = true; 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(); private TeaVMTool tool = new TeaVMTool();
public void setProject(MavenProject project) { @Override
this.project = project; protected File getTargetDirectory() {
} return targetDirectory;
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 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 @Override
public void execute() throws MojoExecutionException { public void execute() throws MojoExecutionException {
Log log = getLog(); Log log = getLog();
setupTool(tool);
tool.setLog(new MavenTeaVMToolLog(log)); tool.setLog(new MavenTeaVMToolLog(log));
try { try {
ClassLoader classLoader = prepareClassLoader();
tool.setClassLoader(classLoader);
tool.setBytecodeLogging(bytecodeLogging); tool.setBytecodeLogging(bytecodeLogging);
tool.setMainClass(mainClass); tool.setMainClass(mainClass);
tool.setMainPageIncluded(mainPageIncluded); tool.setMainPageIncluded(mainPageIncluded);
tool.setMinifying(minifying);
tool.setRuntime(runtime); tool.setRuntime(runtime);
tool.setTargetDirectory(targetDirectory);
tool.setTargetFileName(targetFileName); 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) { if (classAliases != null) {
tool.getClassAliases().addAll(Arrays.asList(classAliases)); tool.getClassAliases().addAll(Arrays.asList(classAliases));
} }
if (methodAliases != null) { if (methodAliases != null) {
tool.getMethodAliases().addAll(Arrays.asList(methodAliases)); tool.getMethodAliases().addAll(Arrays.asList(methodAliases));
} }
if (properties != null) {
tool.getProperties().putAll(properties);
}
tool.setCacheDirectory(cacheDirectory); tool.setCacheDirectory(cacheDirectory);
tool.setIncremental(incremental);
tool.setDebugInformationGenerated(debugInformationGenerated);
tool.setSourceMapsFileGenerated(sourceMapsGenerated);
tool.setSourceFilesCopied(sourceFilesCopied);
tool.generate(); tool.generate();
if (stopOnErrors && !tool.getProblemProvider().getSevereProblems().isEmpty()) { if (stopOnErrors && !tool.getProblemProvider().getSevereProblems().isEmpty()) {
throw new MojoExecutionException("Build error"); throw new MojoExecutionException("Build error");
@ -263,75 +102,4 @@ public class BuildJavascriptMojo extends AbstractMojo {
throw new MojoExecutionException("IO error occured", e); 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

@ -15,67 +15,50 @@
*/ */
package org.teavm.maven; package org.teavm.maven;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.util.Arrays;
import java.net.URLClassLoader; import java.util.Enumeration;
import java.util.*; import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.apache.maven.artifact.Artifact; 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.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log; 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.Mojo;
import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope; 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.JUnitTestAdapter;
import org.teavm.testing.TestAdapter; import org.teavm.testing.TestAdapter;
import org.teavm.tooling.SourceFileProvider;
import org.teavm.tooling.TeaVMTestTool;
import org.teavm.tooling.TeaVMToolException; import org.teavm.tooling.TeaVMToolException;
import org.teavm.tooling.testing.TeaVMTestTool;
import org.teavm.tooling.testing.TestPlan;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
@Mojo(name = "build-test-javascript", requiresDependencyResolution = ResolutionScope.TEST, @Mojo(name = "testCompile", requiresDependencyResolution = ResolutionScope.TEST,
requiresDependencyCollection = ResolutionScope.TEST) requiresDependencyCollection = ResolutionScope.TEST,
public class BuildJavascriptTestMojo extends AbstractMojo { defaultPhase = LifecyclePhase.PROCESS_TEST_CLASSES)
public class BuildJavascriptTestMojo extends AbstractJavascriptMojo {
private static Set<String> testScopes = new HashSet<>(Arrays.asList( private static Set<String> testScopes = new HashSet<>(Arrays.asList(
Artifact.SCOPE_COMPILE, Artifact.SCOPE_TEST, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_COMPILE, Artifact.SCOPE_TEST, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME,
Artifact.SCOPE_PROVIDED)); 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") @Parameter(defaultValue = "${project.build.directory}/javascript-test")
private File outputDir; private File targetDirectory;
@Parameter(defaultValue = "${project.build.outputDirectory}")
private File classFiles;
@Parameter(defaultValue = "${project.build.testOutputDirectory}") @Parameter(defaultValue = "${project.build.testOutputDirectory}")
private File testFiles; private File testFiles;
@ -86,9 +69,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
@Parameter @Parameter
private String[] excludeWildcards = new String[0]; private String[] excludeWildcards = new String[0];
@Parameter
private boolean minifying = true;
@Parameter @Parameter
private boolean scanDependencies; private boolean scanDependencies;
@ -98,153 +78,47 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
@Parameter @Parameter
private String adapterClass = JUnitTestAdapter.class.getName(); private String adapterClass = JUnitTestAdapter.class.getName();
@Parameter
private String[] transformers;
@Parameter @Parameter
private String[] additionalScripts; private String[] additionalScripts;
@Parameter
private Properties properties;
@Parameter
private boolean incremental;
@Parameter
private boolean debugInformationGenerated;
@Parameter
private boolean sourceMapsGenerated;
@Parameter
private boolean sourceFilesCopied;
private TeaVMTestTool tool = new TeaVMTestTool(); 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;
}
@Override @Override
public void execute() throws MojoExecutionException, MojoFailureException { public void execute() throws MojoExecutionException, MojoFailureException {
if (System.getProperty("maven.test.skip", "false").equals("true") || if (System.getProperty("maven.test.skip", "false").equals("true")
System.getProperty("skipTests") != null) { || System.getProperty("skipTests") != null) {
getLog().info("Tests build skipped as specified by system property"); getLog().info("Tests build skipped as specified by system property");
return; return;
} }
setupTool(tool);
try { try {
final ClassLoader classLoader = prepareClassLoader();
getLog().info("Searching for tests in the directory `" + testFiles.getAbsolutePath() + "'"); getLog().info("Searching for tests in the directory `" + testFiles.getAbsolutePath() + "'");
tool.setClassLoader(classLoader);
tool.setAdapter(createAdapter(classLoader)); tool.setAdapter(createAdapter(classLoader));
findTestClasses(classLoader, testFiles, ""); findTestClasses(classLoader, testFiles, "");
if (scanDependencies) { if (scanDependencies) {
findTestsInDependencies(classLoader); findTestsInDependencies(classLoader);
} }
tool.getTransformers().addAll(instantiateTransformers(classLoader));
tool.setLog(new MavenTeaVMToolLog(getLog()));
tool.setOutputDir(outputDir);
tool.setNumThreads(numThreads); 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) { if (additionalScripts != null) {
tool.getAdditionalScripts().addAll(Arrays.asList(additionalScripts)); tool.getAdditionalScripts().addAll(Arrays.asList(additionalScripts));
} }
tool.generate(); writePlan(tool.generate());
} catch (TeaVMToolException e) { } catch (TeaVMToolException e) {
throw new MojoFailureException("Error occured generating JavaScript files", e); throw new MojoFailureException("Error occured generating JavaScript files", e);
} }
} }
private void writePlan(TestPlan plan) throws MojoExecutionException {
File file = new File(targetDirectory, "plan.json");
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) {
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(writer, plan);
} catch (IOException e) {
throw new MojoExecutionException("Error writing test plan", e);
}
}
private TestAdapter createAdapter(ClassLoader classLoader) throws MojoExecutionException { private TestAdapter createAdapter(ClassLoader classLoader) throws MojoExecutionException {
Class<?> adapterClsRaw; Class<?> adapterClsRaw;
try { try {
@ -253,8 +127,8 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
throw new MojoExecutionException("Adapter not found: " + adapterClass, e); throw new MojoExecutionException("Adapter not found: " + adapterClass, e);
} }
if (!TestAdapter.class.isAssignableFrom(adapterClsRaw)) { if (!TestAdapter.class.isAssignableFrom(adapterClsRaw)) {
throw new MojoExecutionException("Adapter " + adapterClass + " does not implement " + throw new MojoExecutionException("Adapter " + adapterClass + " does not implement "
TestAdapter.class.getName()); + TestAdapter.class.getName());
} }
Class<? extends TestAdapter> adapterCls = adapterClsRaw.asSubclass(TestAdapter.class); Class<? extends TestAdapter> adapterCls = adapterClsRaw.asSubclass(TestAdapter.class);
Constructor<? extends TestAdapter> cons; Constructor<? extends TestAdapter> cons;
@ -272,38 +146,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 { private void findTestsInDependencies(ClassLoader classLoader) throws MojoExecutionException {
try { try {
Log log = getLog(); Log log = getLog();
@ -384,39 +226,18 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
} }
} }
@Override
protected File getTargetDirectory() {
return targetDirectory;
}
private List<ClassHolderTransformer> instantiateTransformers(ClassLoader classLoader) @Override
throws MojoExecutionException { protected List<File> getAdditionalClassPath() {
List<ClassHolderTransformer> transformerInstances = new ArrayList<>(); return Arrays.asList(testFiles);
if (transformers == null) { }
return transformerInstances;
} @Override
for (String transformerName : transformers) { protected boolean isSupportedScope(String scope) {
Class<?> transformerRawType; return testScopes.contains(scope);
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;
} }
} }

View File

@ -0,0 +1,107 @@
/*
* 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 com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebWindow;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import net.sourceforge.htmlunit.corejs.javascript.Function;
import net.sourceforge.htmlunit.corejs.javascript.NativeJavaObject;
import org.apache.commons.io.IOUtils;
import org.apache.maven.plugin.logging.Log;
import org.teavm.tooling.testing.TestCase;
/**
*
* @author Alexey Andreev
*/
public class HtmlUnitRunStrategy implements TestRunStrategy {
private File directory;
public HtmlUnitRunStrategy(File directory) {
this.directory = directory;
}
@Override
public void beforeThread() {
}
@Override
public void afterThread() {
}
@Override
public String runTest(Log log, String runtimeScript, TestCase testCase) throws IOException {
try (WebClient webClient = new WebClient(BrowserVersion.CHROME)) {
HtmlPage page = webClient.getPage("about:blank");
page.executeJavaScript(readFile(new File(directory, runtimeScript)));
AsyncResult asyncResult = new AsyncResult();
Function function = (Function) page.executeJavaScript(readResource("teavm-htmlunit-adapter.js"))
.getJavaScriptResult();
Object[] args = new Object[] { new NativeJavaObject(function, asyncResult, AsyncResult.class) };
page.executeJavaScriptFunctionIfPossible(function, function, args, page);
page.executeJavaScript(readFile(new File(directory, testCase.getTestScript())));
page.cleanUp();
for (WebWindow window : webClient.getWebWindows()) {
window.getJobManager().removeAllJobs();
}
return (String) asyncResult.getResult();
}
}
private String readFile(File file) throws IOException {
try (InputStream input = new FileInputStream(file)) {
return IOUtils.toString(input, "UTF-8");
}
}
private String readResource(String resourceName) throws IOException {
try (InputStream input = BuildJavascriptTestMojo.class.getClassLoader().getResourceAsStream(resourceName)) {
if (input == null) {
return "";
}
return IOUtils.toString(input, "UTF-8");
}
}
public class AsyncResult {
private CountDownLatch latch = new CountDownLatch(1);
private Object result;
public void complete(Object result) {
this.result = result;
latch.countDown();
}
public Object getResult() {
try {
latch.await(5, TimeUnit.SECONDS);
return result;
} catch (InterruptedException e) {
return null;
}
}
}
}

View File

@ -26,9 +26,9 @@ import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult; import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem; import org.apache.maven.repository.RepositorySystem;
import org.teavm.tooling.DirectorySourceFileProvider; import org.teavm.tooling.sources.DirectorySourceFileProvider;
import org.teavm.tooling.JarSourceFileProvider; import org.teavm.tooling.sources.JarSourceFileProvider;
import org.teavm.tooling.SourceFileProvider; import org.teavm.tooling.sources.SourceFileProvider;
/** /**
* *
@ -85,7 +85,12 @@ public class MavenSourceFileProviderLookup {
ArtifactResolutionResult result = repositorySystem.resolve(request); ArtifactResolutionResult result = repositorySystem.resolve(request);
for (Artifact resolvedArtifact : result.getArtifacts()) { for (Artifact resolvedArtifact : result.getArtifacts()) {
if (resolvedArtifact.getFile() != null) { if (resolvedArtifact.getFile() != null) {
providers.add(new JarSourceFileProvider(resolvedArtifact.getFile())); File file = resolvedArtifact.getFile();
if (!file.isDirectory()) {
providers.add(new JarSourceFileProvider(file));
} else {
providers.add(new DirectorySourceFileProvider(file));
}
} }
} }
} }

View File

@ -1,3 +1,18 @@
/*
* 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; package org.teavm.maven;
import org.apache.maven.plugin.logging.Log; import org.apache.maven.plugin.logging.Log;

View File

@ -0,0 +1,128 @@
/*
* 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 com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.teavm.tooling.testing.TestPlan;
/**
*
* @author Alexey Andreev
*/
@Mojo(name = "test", defaultPhase = LifecyclePhase.TEST)
public class RunTestsMojo extends AbstractMojo {
@Parameter(defaultValue = "${project.build.directory}/javascript-test")
private File testDirectory;
@Parameter(defaultValue = "${project.build.directory}/teavm-test-report.json")
private File reportFile;
@Parameter
private String seleniumURL;
@Parameter
private int numThreads = 1;
@Parameter
private boolean skip;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
if (skip) {
getLog().info("Tests run skipped as specified by skip property");
return;
}
if (System.getProperty("maven.test.skip", "false").equals("true")
|| System.getProperty("skipTests") != null) {
getLog().info("Tests run skipped as specified by system property");
return;
}
TestRunner runner = new TestRunner(pickStrategy());
runner.setLog(getLog());
runner.setNumThreads(numThreads);
TestPlan plan;
ObjectMapper mapper = new ObjectMapper();
File file = new File(testDirectory, "plan.json");
try (Reader reader = new InputStreamReader(new FileInputStream(file), "UTF-8")) {
plan = mapper.readValue(reader, TestPlan.class);
} catch (IOException e) {
throw new MojoExecutionException("Error reading test plan", e);
}
runner.run(plan);
processReport(runner.getReport());
}
private TestRunStrategy pickStrategy() throws MojoFailureException {
if (seleniumURL != null) {
try {
return new SeleniumRunStrategy(new URL(seleniumURL), testDirectory);
} catch (MalformedURLException e) {
throw new MojoFailureException("Can't parse URL: " + seleniumURL, e);
}
} else {
return new HtmlUnitRunStrategy(testDirectory);
}
}
private void processReport(TestReport report) throws MojoExecutionException, MojoFailureException {
if (report.getResults().isEmpty()) {
getLog().info("No tests ran");
return;
}
int failedTests = 0;
for (TestResult result : report.getResults()) {
if (result.getStatus() != TestStatus.PASSED) {
failedTests++;
}
}
if (failedTests > 0) {
throw new MojoExecutionException(failedTests + " of " + report.getResults().size() + " test(s) failed");
} else {
getLog().info("All of " + report.getResults().size() + " tests successfully passed");
}
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
try (Writer writer = new OutputStreamWriter(new FileOutputStream(reportFile), "UTF-8")) {
mapper.writeValue(writer, report);
} catch (IOException e) {
throw new MojoFailureException("Error writing test report", e);
}
}
}

View File

@ -0,0 +1,95 @@
/*
* 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.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.maven.plugin.logging.Log;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.teavm.tooling.testing.TestCase;
/**
*
* @author Alexey Andreev
*/
public class SeleniumRunStrategy implements TestRunStrategy {
private URL url;
private File directory;
private ThreadLocal<WebDriver> webDriver = new ThreadLocal<>();
public SeleniumRunStrategy(URL url, File directory) {
this.url = url;
this.directory = directory;
}
@Override
public void beforeThread() {
RemoteWebDriver driver = new RemoteWebDriver(url, DesiredCapabilities.chrome());
webDriver.set(driver);
}
@Override
public void afterThread() {
webDriver.get().close();
webDriver.remove();
}
@Override
public String runTest(Log log, String runtimeScript, TestCase testCase) throws IOException {
webDriver.get().manage().timeouts().setScriptTimeout(2, TimeUnit.SECONDS);
JavascriptExecutor js = (JavascriptExecutor) webDriver.get();
try {
return (String) js.executeAsyncScript(
readResource("teavm-selenium.js"),
readFile(new File(directory, runtimeScript)),
readFile(new File(directory, testCase.getTestScript())),
readResource("teavm-selenium-adapter.js"));
} catch (WebDriverException e) {
log.error("Error occured running test " + testCase.getTestMethod(), e);
@SuppressWarnings("unchecked")
List<Object> errors = (List<Object>) js.executeScript("return window.jsErrors;");
for (Object error : errors) {
log.error(" -- additional error: " + error);
}
return null;
}
}
private String readFile(File file) throws IOException {
try (InputStream input = new FileInputStream(file)) {
return IOUtils.toString(input, "UTF-8");
}
}
private String readResource(String resourceName) throws IOException {
try (InputStream input = BuildJavascriptTestMojo.class.getClassLoader().getResourceAsStream(resourceName)) {
if (input == null) {
return "";
}
return IOUtils.toString(input, "UTF-8");
}
}
}

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.util.ArrayList;
import java.util.List;
/**
*
* @author Alexey Andreev
*/
public class TestReport {
private List<TestResult> results = new ArrayList<>();
public List<TestResult> getResults() {
return results;
}
}

View File

@ -0,0 +1,78 @@
/*
* 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 com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public class TestResult {
private MethodReference method;
private TestStatus status;
private String exception;
private String stack;
@JsonCreator
TestResult(
@JsonProperty("method") MethodReference method,
@JsonProperty("status") TestStatus status,
@JsonInclude(Include.NON_NULL) @JsonProperty("exception") String exception,
@JsonInclude(Include.NON_NULL) @JsonProperty("stack") String stack) {
this.method = method;
this.status = status;
this.exception = exception;
this.stack = stack;
}
public static TestResult passed(MethodReference method) {
return new TestResult(method, TestStatus.PASSED, null, null);
}
public static TestResult exceptionNotThrown(MethodReference method) {
return new TestResult(method, TestStatus.EXCEPTION_NOT_THROWN, null, null);
}
public static TestResult error(MethodReference method, String exception, String stack) {
return new TestResult(method, TestStatus.ERROR, exception, stack);
}
@JsonGetter
public MethodReference getMethod() {
return method;
}
@JsonGetter
public TestStatus getStatus() {
return status;
}
@JsonGetter
public String getException() {
return exception;
}
@JsonGetter
public String getStack() {
return stack;
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.IOException;
import org.apache.maven.plugin.logging.Log;
import org.teavm.tooling.testing.TestCase;
/**
*
* @author Alexey Andreev
*/
public interface TestRunStrategy {
void beforeThread();
void afterThread();
String runTest(Log log, String runtimeScript, TestCase testCase) throws IOException;
}

View File

@ -0,0 +1,164 @@
/*
* 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 com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.apache.maven.plugin.logging.Log;
import org.teavm.model.MethodReference;
import org.teavm.tooling.testing.TestCase;
import org.teavm.tooling.testing.TestGroup;
import org.teavm.tooling.testing.TestPlan;
/**
*
* @author Alexey Andreev
*/
public class TestRunner {
private int numThreads = 1;
private TestRunStrategy strategy;
private BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
private CountDownLatch latch;
private volatile boolean stopped;
private Log log;
private List<TestResult> report = new CopyOnWriteArrayList<>();
private ThreadLocal<List<TestResult>> localReport = new ThreadLocal<>();
public TestRunner(TestRunStrategy strategy) {
this.strategy = strategy;
}
public void setLog(Log log) {
this.log = log;
}
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);
}
}
stopSelenium();
waitForCompletion();
}
private void initSelenium() {
latch = new CountDownLatch(numThreads);
for (int i = 0; i < numThreads; ++i) {
new Thread(() -> {
strategy.beforeThread();
localReport.set(new ArrayList<>());
while (!stopped || !taskQueue.isEmpty()) {
Runnable task;
try {
task = taskQueue.poll(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
break;
}
if (task != null) {
task.run();
}
}
report.addAll(localReport.get());
localReport.remove();
strategy.afterThread();
latch.countDown();
}).start();
}
}
private void addTask(Runnable runnable) {
taskQueue.add(runnable);
}
private void stopSelenium() {
stopped = true;
}
private void waitForCompletion() {
try {
latch.await();
} catch (InterruptedException e) {
return;
}
}
private void run(String runtimeScript, TestCase testCase) {
addTask(() -> runImpl(runtimeScript, testCase));
}
private void runImpl(String runtimeScript, TestCase testCase) {
MethodReference ref = MethodReference.parse(testCase.getTestMethod());
try {
String result = strategy.runTest(log, runtimeScript, testCase);
if (result == null) {
log.info("Test failed: " + testCase.getTestMethod());
localReport.get().add(TestResult.error(ref, null, null));
}
ObjectMapper mapper = new ObjectMapper();
ObjectNode resultObject = (ObjectNode) mapper.readTree(result);
String status = resultObject.get("status").asText();
switch (status) {
case "ok":
if (testCase.getExpectedExceptions().isEmpty()) {
log.info("Test passed: " + testCase.getTestMethod());
localReport.get().add(TestResult.passed(ref));
} else {
log.info("Test failed: " + testCase.getTestMethod());
localReport.get().add(TestResult.exceptionNotThrown(ref));
}
break;
case "exception": {
String stack = resultObject.get("stack").asText();
String exception = resultObject.get("exception").asText();
if (!testCase.getExpectedExceptions().contains(exception)) {
log.info("Test failed: " + testCase.getTestMethod());
localReport.get().add(TestResult.error(ref, exception, stack));
} else {
log.info("Test passed: " + testCase.getTestMethod());
localReport.get().add(TestResult.passed(ref));
}
break;
}
}
} catch (IOException e) {
log.error(e);
}
}
public TestReport getReport() {
TestReport report = new TestReport();
report.getResults().addAll(this.report);
return report;
}
}

View File

@ -0,0 +1,26 @@
/*
* 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;
/**
*
* @author Alexey Andreev
*/
public enum TestStatus {
PASSED,
ERROR,
EXCEPTION_NOT_THROWN
}

View File

@ -0,0 +1,65 @@
function(callback) {
var JUnitClient = {}
JUnitClient.run = function() {
$rt_startThread(function() {
var thread = $rt_nativeThread();
var instance;
var ptr = 0;
var message;
if (thread.isResuming()) {
ptr = thread.pop();
instance = thread.pop();
}
loop: while (true) { switch (ptr) {
case 0:
instance = new TestClass();
ptr = 1;
case 1:
try {
initInstance(instance);
} catch (e) {
message = {};
JUnitClient.makeErrorMessage(message, e);
break loop;
}
if (thread.isSuspending()) {
thread.push(instance);
thread.push(ptr);
return;
}
ptr = 2;
case 2:
try {
runTest(instance);
} catch (e) {
message = {};
JUnitClient.makeErrorMessage(message, e);
break loop;
}
if (thread.isSuspending()) {
thread.push(instance);
thread.push(ptr);
return;
}
message = {};
message.status = "ok";
break loop;
}}
callback.complete(JSON.stringify(message));
})
}
JUnitClient.makeErrorMessage = function(message, e) {
message.status = "exception";
var stack = e.stack;
if (e.$javaException && e.$javaException.constructor.$meta) {
message.exception = e.$javaException.constructor.$meta.name;
message.stack = e.$javaException.constructor.$meta.name + ": ";
var exceptionMessage = extractException(e.$javaException);
message.stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
}
message.stack += "\n" + stack;
}
window.JUnitClient = JUnitClient;
}

View File

@ -0,0 +1,61 @@
var JUnitClient = {}
JUnitClient.run = function() {
$rt_startThread(function() {
var thread = $rt_nativeThread();
var instance;
var ptr = 0;
var message;
if (thread.isResuming()) {
ptr = thread.pop();
instance = thread.pop();
}
loop: while (true) { switch (ptr) {
case 0:
instance = new TestClass();
ptr = 1;
case 1:
try {
initInstance(instance);
} catch (e) {
message = {};
JUnitClient.makeErrorMessage(message, e);
break loop;
}
if (thread.isSuspending()) {
thread.push(instance);
thread.push(ptr);
return;
}
ptr = 2;
case 2:
try {
runTest(instance);
} catch (e) {
message = {};
JUnitClient.makeErrorMessage(message, e);
break loop;
}
if (thread.isSuspending()) {
thread.push(instance);
thread.push(ptr);
return;
}
message = {};
message.status = "ok";
break loop;
}}
window.parent.postMessage(JSON.stringify(message), "*");
})
}
JUnitClient.makeErrorMessage = function(message, e) {
message.status = "exception";
var stack = e.stack;
if (e.$javaException && e.$javaException.constructor.$meta) {
message.exception = e.$javaException.constructor.$meta.name;
message.stack = e.$javaException.constructor.$meta.name + ": ";
var exceptionMessage = extractException(e.$javaException);
message.stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
}
message.stack += "\n" + stack;
}

View File

@ -0,0 +1,43 @@
var runtimeSource = arguments[0]
var testSource = arguments[1]
var adapterSource = arguments[2]
var seleniumCallback = arguments[arguments.length - 1]
var iframe = document.createElement("iframe")
document.body.appendChild(iframe)
var doc = iframe.contentDocument
window.jsErrors = []
window.onerror = reportError
iframe.contentWindow.onerror = reportError
loadScripts([ runtimeSource, adapterSource, testSource ])
window.addEventListener("message", handleMessage)
function handleMessage(event) {
window.removeEventListener("message", handleMessage)
document.body.removeChild(iframe)
seleniumCallback(event.data)
}
function loadScript(script, callback) {
callback()
}
function loadScripts(scripts) {
for (var i = 0; i < scripts.length; ++i) {
var elem = doc.createElement("script")
elem.type = "text/javascript"
doc.head.appendChild(elem)
elem.text = scripts[i]
}
}
function reportError(error, url, line) {
window.jsErrors.push(error + " at " + line)
}
function report(error) {
window.jsErrors.push(error)
}
function globalEval(window, arg) {
eval.apply(window, [arg])
}

View File

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

View File

@ -8,7 +8,7 @@
<packaging>war</packaging> <packaging>war</packaging>
<properties> <properties>
<java.version>1.7</java.version> <java.version>1.8</java.version>
<teavm.version>0.4.0-SNAPSHOT</teavm.version> <teavm.version>0.4.0-SNAPSHOT</teavm.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
@ -25,15 +25,7 @@
<!-- JavaScriptObjects (JSO) - a JavaScript binding for TeaVM --> <!-- JavaScriptObjects (JSO) - a JavaScript binding for TeaVM -->
<dependency> <dependency>
<groupId>org.teavm</groupId> <groupId>org.teavm</groupId>
<artifactId>teavm-jso</artifactId> <artifactId>teavm-jso-apis</artifactId>
<version>${teavm.version}</version>
<scope>provided</scope>
</dependency>
<!-- Different browser APIs for TeaVM in terms of JSO -->
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-dom</artifactId>
<version>${teavm.version}</version> <version>${teavm.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@ -80,9 +72,8 @@
<executions> <executions>
<execution> <execution>
<id>web-client</id> <id>web-client</id>
<phase>prepare-package</phase>
<goals> <goals>
<goal>build-javascript</goal> <goal>compile</goal>
</goals> </goals>
<configuration> <configuration>
<!-- Directory where TeaVM should put generated files. This configuration conforms to the settings <!-- Directory where TeaVM should put generated files. This configuration conforms to the settings
@ -92,9 +83,6 @@
<!-- Main class, containing static void main(String[]) --> <!-- Main class, containing static void main(String[]) -->
<mainClass>${package}.Client</mainClass> <mainClass>${package}.Client</mainClass>
<!-- How to attach runtime.js. Possible values are: SEPARATE, MERGED and NONE -->
<runtime>SEPARATE</runtime>
<!-- Whether TeaVM should produce minified JavaScript. Can reduce JavaScript file size more than <!-- Whether TeaVM should produce minified JavaScript. Can reduce JavaScript file size more than
two times --> two times -->
<minifying>true</minifying> <minifying>true</minifying>