diff --git a/teavm-core/pom.xml b/teavm-core/pom.xml index d06b52d41..249886d86 100644 --- a/teavm-core/pom.xml +++ b/teavm-core/pom.xml @@ -29,7 +29,7 @@ junit junit 4.10 - test + provided commons-io diff --git a/teavm-core/src/main/java/org/teavm/testing/JUnitTestAdapter.java b/teavm-core/src/main/java/org/teavm/testing/JUnitTestAdapter.java new file mode 100644 index 000000000..8f99a42dc --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/testing/JUnitTestAdapter.java @@ -0,0 +1,59 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.testing; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Collections; +import org.junit.Test; +import org.teavm.model.AnnotationReader; +import org.teavm.model.AnnotationValue; +import org.teavm.model.MethodReader; +import org.teavm.model.ValueType; + +/** + * + * @author Alexey Andreev + */ +public class JUnitTestAdapter implements TestAdapter { + @Override + public boolean acceptClass(Class cls) { + for (Method method : cls.getDeclaredMethods()) { + for (Annotation annot : method.getAnnotations()) { + if (annot.annotationType().getName().equals(Test.class.getName())) { + return true; + } + } + } + return false; + } + + @Override + public boolean acceptMethod(MethodReader method) { + return method.getAnnotations().get(Test.class.getName()) != null; + } + + @Override + public Iterable getExpectedExceptions(MethodReader method) { + AnnotationReader annot = method.getAnnotations().get(Test.class.getName()); + AnnotationValue expectedAnnot = annot.getValue("expected"); + if (expectedAnnot != null) { + String className = ((ValueType.Object)expectedAnnot.getJavaClass()).getClassName(); + return Collections.singletonList(className); + } + return Collections.emptyList(); + } +} diff --git a/teavm-core/src/main/java/org/teavm/testing/TestAdapter.java b/teavm-core/src/main/java/org/teavm/testing/TestAdapter.java new file mode 100644 index 000000000..703339a75 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/testing/TestAdapter.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.testing; + +import org.teavm.model.MethodReader; + +/** + * + * @author Alexey Andreev + */ +public interface TestAdapter { + boolean acceptClass(Class cls); + + boolean acceptMethod(MethodReader method); + + Iterable getExpectedExceptions(MethodReader method); +} diff --git a/teavm-maven-plugin/pom.xml b/teavm-maven-plugin/pom.xml index af45512ee..03729eec9 100644 --- a/teavm-maven-plugin/pom.xml +++ b/teavm-maven-plugin/pom.xml @@ -48,6 +48,11 @@ teavm-core ${project.version} + + commons-io + commons-io + 2.4 + junit junit diff --git a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptJUnitMojo.java b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java similarity index 87% rename from teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptJUnitMojo.java rename to teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java index 1675a3815..2c02ea738 100644 --- a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptJUnitMojo.java +++ b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java @@ -16,8 +16,8 @@ package org.teavm.maven; import java.io.*; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; @@ -33,7 +33,6 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; -import org.junit.Test; import org.teavm.common.FiniteExecutor; import org.teavm.common.SimpleFiniteExecutor; import org.teavm.common.ThreadPoolFiniteExecutor; @@ -42,6 +41,8 @@ import org.teavm.javascript.JavascriptBuilder; import org.teavm.javascript.JavascriptBuilderFactory; import org.teavm.model.*; import org.teavm.parsing.ClasspathClassHolderSource; +import org.teavm.testing.JUnitTestAdapter; +import org.teavm.testing.TestAdapter; /** * @@ -49,7 +50,7 @@ import org.teavm.parsing.ClasspathClassHolderSource; */ @Mojo(name = "build-junit", requiresDependencyResolution = ResolutionScope.TEST, requiresDependencyCollection = ResolutionScope.TEST) -public class BuildJavascriptJUnitMojo extends AbstractMojo { +public class BuildJavascriptTestMojo extends AbstractMojo { private static Set testScopes = new HashSet<>(Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_TEST, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_PROVIDED)); @@ -57,6 +58,7 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo { private Map fileNames = new HashMap<>(); private List testMethods = new ArrayList<>(); private List testClasses = new ArrayList<>(); + private TestAdapter adapter; @Component private MavenProject project; @@ -70,12 +72,18 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo { @Parameter(defaultValue = "${project.build.testOutputDirectory}") private File testFiles; + @Parameter + private String[] testFilePatterns = { "*Test", "*UnitTest" }; + @Parameter private boolean minifying = true; @Parameter private int numThreads = 1; + @Parameter + private Class adapterClass = JUnitTestAdapter.class; + public void setProject(MavenProject project) { this.project = project; } @@ -100,9 +108,14 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo { this.numThreads = numThreads; } + public void setAdapterClass(Class adapterClass) { + this.adapterClass = adapterClass; + } + @Override public void execute() throws MojoExecutionException, MojoFailureException { Runnable finalizer = null; + createAdapter(); try { final ClassLoader classLoader = prepareClassLoader(); getLog().info("Searching for tests in the directory `" + testFiles.getAbsolutePath() + "'"); @@ -145,11 +158,13 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo { scriptName + "\", expected : ["); MethodHolder methodHolder = classSource.get(testClass).getMethod( methodRef.getDescriptor()); - AnnotationHolder annot = methodHolder.getAnnotations().get("org.junit.Test"); - AnnotationValue expectedAnnot = annot.getValues().get("expected"); - if (expectedAnnot != null) { - String className = ((ValueType.Object)expectedAnnot.getJavaClass()).getClassName(); - allTestsWriter.append("\"" + className + "\""); + boolean firstException = true; + for (String exception : adapter.getExpectedExceptions(methodHolder)) { + if (!firstException) { + allTestsWriter.append(", "); + } + firstException = false; + allTestsWriter.append("\"" + exception + "\""); } allTestsWriter.append("] }"); } @@ -195,6 +210,23 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo { } } + private void createAdapter() throws MojoExecutionException { + Constructor cons; + try { + cons = adapterClass.getConstructor(); + } catch (NoSuchMethodException e) { + throw new MojoExecutionException("No default constructor found for test adapter " + + adapterClass.getName(), e); + } + try { + adapter = cons.newInstance(); + } catch (IllegalAccessException | InstantiationException e) { + throw new MojoExecutionException("Error creating test adapter", e); + } catch (InvocationTargetException e) { + throw new MojoExecutionException("Error creating test adapter", e.getTargetException()); + } + } + private ClassLoader prepareClassLoader() throws MojoExecutionException { try { Log log = getLog(); @@ -221,7 +253,7 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo { urls.add(classFiles.toURI().toURL()); log.info("Using the following classpath for JavaScript JUnit generation: " + classpath); return new URLClassLoader(urls.toArray(new URL[urls.size()]), - BuildJavascriptJUnitMojo.class.getClassLoader()); + BuildJavascriptTestMojo.class.getClassLoader()); } catch (MalformedURLException e) { throw new MojoExecutionException("Error gathering classpath information", e); } @@ -304,12 +336,6 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo { } private void findTestClasses(ClassLoader classLoader, File folder, String prefix) { - Class testAnnot; - try { - testAnnot = Class.forName(Test.class.getName(), true, classLoader).asSubclass(Annotation.class); - } catch (ClassNotFoundException e) { - throw new RuntimeException("Could not load `" + Test.class.getName() + "` annotation"); - } for (File file : folder.listFiles()) { if (file.isDirectory()) { String newPrefix = prefix.isEmpty() ? file.getName() : prefix + "." + file.getName(); @@ -321,14 +347,7 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo { } try { Class candidate = Class.forName(className, true, classLoader); - boolean hasTests = false; - for (Method method : candidate.getDeclaredMethods()) { - if (method.isAnnotationPresent(testAnnot)) { - hasTests = true; - break; - } - } - if (hasTests) { + if (adapter.acceptClass(candidate)) { testClasses.add(candidate.getName()); getLog().info("Test class detected: " + candidate.getName()); } @@ -341,7 +360,7 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo { private void findTests(ClassHolder cls) { for (MethodHolder method : cls.getMethods()) { - if (method.getAnnotations().get("org.junit.Test") != null) { + if (adapter.acceptMethod(method)) { MethodReference ref = new MethodReference(cls.getName(), method.getDescriptor()); testMethods.add(ref); List group = groupedMethods.get(cls.getName()); @@ -355,7 +374,7 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo { } private void resourceToFile(String resource, String fileName) throws IOException { - try (InputStream input = BuildJavascriptJUnitMojo.class.getClassLoader().getResourceAsStream(resource)) { + try (InputStream input = BuildJavascriptTestMojo.class.getClassLoader().getResourceAsStream(resource)) { try (OutputStream output = new FileOutputStream(new File(outputDir, fileName))) { IOUtils.copy(input, output); }