package io.takari.maven.plugins.compile; import static io.takari.maven.plugins.compile.ClassfileMatchers.hasAnnotation; import static io.takari.maven.plugins.compile.ClassfileMatchers.hasDebugLines; import static io.takari.maven.plugins.compile.ClassfileMatchers.hasDebugSource; import static io.takari.maven.plugins.compile.ClassfileMatchers.hasDebugVars; import static io.takari.maven.plugins.compile.ClassfileMatchers.hasMethodParameterWithName; import static io.takari.maven.testing.TestResources.cp; import static io.takari.maven.testing.TestResources.touch; import static org.hamcrest.core.AllOf.allOf; import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.assertThat; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.PrintStream; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; import com.google.common.base.Charsets; import com.google.common.io.Files; public class CompileTest extends AbstractCompileTest { public CompileTest(String compilerId) { super(compilerId); } @Test public void testBasic() throws Exception { File basedir = compile("compile/basic"); File classes = new File(basedir, "target/classes"); mojos.assertBuildOutputs(classes, "basic/Basic.class"); } @Test public void testBasic_testCompile() throws Exception { File basedir = compile("compile/basic"); File testClasses = new File(basedir, "target/test-classes"); MavenProject project = mojos.readMavenProject(basedir); MavenSession session = mojos.newMavenSession(project); MojoExecution execution = mojos.newMojoExecution("testCompile"); execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); mojos.executeMojo(session, project, execution); mojos.assertBuildOutputs(testClasses, "basic/BasicTest.class"); } @Test public void testBasic_verbose() throws Exception { PrintStream origOut = System.out; try { ByteArrayOutputStream buf = new ByteArrayOutputStream(); System.setOut(new PrintStream(buf, true)); File basedir = compile("compile/basic", newParameter("verbose", "true")); mojos.assertBuildOutputs(basedir, "target/classes/basic/Basic.class"); String output = new String(buf.toByteArray()); Assert.assertTrue(output.contains("parsing ")); } finally { System.setOut(origOut); } } @Test public void testBasic_debugInfo() throws Exception { File basedir; // all basedir = compile("compile/basic"); assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(hasDebugSource(), hasDebugLines(), hasDebugVars())); basedir = compile("compile/basic", newParameter("debug", "all")); assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(hasDebugSource(), hasDebugLines(), hasDebugVars())); basedir = compile("compile/basic", newParameter("debug", "true")); assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(hasDebugSource(), hasDebugLines(), hasDebugVars())); // none basedir = compile("compile/basic", newParameter("debug", "none")); assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(not(hasDebugSource()), not(hasDebugLines()), not(hasDebugVars()))); basedir = compile("compile/basic", newParameter("debug", "false")); assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(not(hasDebugSource()), not(hasDebugLines()), not(hasDebugVars()))); // keywords basedir = compile("compile/basic", newParameter("debug", "source")); assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(hasDebugSource(), not(hasDebugLines()), not(hasDebugVars()))); basedir = compile("compile/basic", newParameter("debug", "source,lines")); assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(hasDebugSource(), hasDebugLines(), not(hasDebugVars()))); basedir = compile("compile/basic", newParameter("debug", "source,lines,vars")); assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(hasDebugSource(), hasDebugLines(), hasDebugVars())); } @Test public void testBasic_skipMain() throws Exception { File basedir = compile("compile/basic", newParameter("skipMain", "true")); File classes = new File(basedir, "target/classes"); mojos.assertBuildOutputs(classes, new String[0]); compile(basedir); mojos.assertBuildOutputs(classes, "basic/Basic.class"); compile(basedir, newParameter("skipMain", "true")); mojos.assertBuildOutputs(classes, new String[0]); mojos.assertDeletedOutputs(classes, new String[0]); } @Test public void testBasic_skip() throws Exception { File basedir = compile("compile/basic"); File testClasses = new File(basedir, "target/test-classes"); MavenProject project = mojos.readMavenProject(basedir); MavenSession session = mojos.newMavenSession(project); MojoExecution execution = mojos.newMojoExecution("testCompile"); execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); execution.getConfiguration().addChild(newParameter("skip", "true")); mojos.executeMojo(session, project, execution); mojos.assertBuildOutputs(testClasses, new String[0]); execution = mojos.newMojoExecution("testCompile"); execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); mojos.executeMojo(session, project, execution); mojos.assertBuildOutputs(testClasses, "basic/BasicTest.class"); execution = mojos.newMojoExecution("testCompile"); execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); execution.getConfiguration().addChild(newParameter("skip", "true")); mojos.executeMojo(session, project, execution); mojos.assertBuildOutputs(testClasses, new String[0]); mojos.assertDeletedOutputs(testClasses, new String[0]); } @Test public void testIncludes() throws Exception { Xpp3Dom includes = new Xpp3Dom("includes"); includes.addChild(newParameter("include", "basic/Basic.java")); File basedir = compile("compile/source-filtering", includes); mojos.assertBuildOutputs(new File(basedir, "target/classes"), "basic/Basic.class"); } @Test public void testExcludes() throws Exception { Xpp3Dom excludes = new Xpp3Dom("excludes"); excludes.addChild(newParameter("exclude", "basic/Garbage.java")); File basedir = compile("compile/source-filtering", excludes); mojos.assertBuildOutputs(new File(basedir, "target/classes"), "basic/Basic.class"); } @Test public void testClasspath() throws Exception { File dependency = new File(compile("compile/basic"), "target/classes"); File basedir = resources.getBasedir("compile/classpath"); MavenProject project = mojos.readMavenProject(basedir); MavenSession session = mojos.newMavenSession(project); MojoExecution execution = mojos.newMojoExecution(); addDependency(project, "dependency", dependency); mojos.executeMojo(session, project, execution); mojos.assertBuildOutputs(new File(basedir, "target/classes"), "classpath/Classpath.class"); } @Test public void testClasspath_dependencySourceTypes_ignore() throws Exception { // dependency has both .java and .class files, but .java file is corrupted // assert the compiler uses .class file when dependencySourceTypes=ignore File dependency = compile("compile/basic"); Files.write("corrupted", new File(dependency, "target/classes/basic/Basic.java"), Charsets.UTF_8); touch(new File(dependency, "target/classes/basic/Basic.java")); // javac will pick newer file by default File basedir = resources.getBasedir("compile/classpath"); MavenProject project = mojos.readMavenProject(basedir); addDependency(project, "dependency", new File(dependency, "target/classes")); mojos.compile(project, newParameter("dependencySourceTypes", "ignore")); mojos.assertBuildOutputs(new File(basedir, "target/classes"), "classpath/Classpath.class"); } @Test public void testSpace() throws Exception { File basedir = compile("compile/spa ce"); Assert.assertTrue(basedir.getAbsolutePath().contains(" ")); mojos.assertBuildOutputs(new File(basedir, "target/classes"), "space/Space.class"); } @Test public void testError() throws Exception { ErrorMessage expected = new ErrorMessage(compilerId); expected.setSnippets("jdt", "ERROR Error.java [4:11] Foo cannot be resolved to a type"); expected.setSnippets("javac", "ERROR Error.java [4:11]", "cannot find symbol", "class Foo", "location", "class basic.Error"); File basedir = resources.getBasedir("compile/error"); try { compile(basedir); Assert.fail(); } catch (MojoExecutionException e) { // expected } mojos.assertBuildOutputs(basedir, new String[0]); mojos.assertMessage(basedir, "src/main/java/error/Error.java", expected); } @Test public void testWarn() throws Exception { File basedir = resources.getBasedir("compile/warn"); compile(basedir); // no warnings by default mojos.assertBuildOutputs(new File(basedir, "target/classes"), "warn/Warn.class"); mojos.assertMessages(basedir, "src/main/java/warn/Warn.java", new String[0]); ErrorMessage expected = new ErrorMessage(compilerId); expected.setSnippets("jdt", "WARNING Warn.java [5:3] List is a raw type. References to generic type List<E> should be parameterized"); expected.setSnippets("javac", "WARNING Warn.java [5:12] found raw type: java.util.List\n missing type arguments for generic class java.util.List<E>"); compile(basedir, newParameter("showWarnings", "true")); mojos.assertBuildOutputs(new File(basedir, "target/classes"), "warn/Warn.class"); mojos.assertMessage(basedir, "src/main/java/warn/Warn.java", expected); } @Test public void testSourceTargetVersion() throws Exception { ErrorMessage expected = new ErrorMessage(compilerId); expected.setSnippets("jdt", "ERROR RequiresJava7.java [9:40] '<>' operator is not allowed for source level below 1.7"); expected.setSnippets("javac", "ERROR RequiresJava7.java [9:50] diamond operator is not supported in -source 1.6\n" + " (use -source 7 or higher to enable diamond operator)"); File basedir = resources.getBasedir("compile/source-target-version"); try { compile(basedir, newParameter("source", "1.6")); Assert.fail(); } catch (MojoExecutionException e) { // expected } mojos.assertMessage(basedir, "src/main/java/version/RequiresJava7.java", expected); mojos.assertBuildOutputs(new File(basedir, "target/classes"), new String[0]); compile(basedir, newParameter("source", "1.7")); mojos.assertBuildOutputs(new File(basedir, "target/classes"), "version/RequiresJava7.class"); } @Test public void testEncoding() throws Exception { File basedir = resources.getBasedir("compile/encoding"); try { compile(basedir, newParameter("encoding", "ISO-8859-5")); Assert.fail(); } catch (MojoExecutionException e) { // } mojos.assertMessage(new File(basedir, "src/main/java/encoding/ISO8859p5.java"), "\u043f\u043e\u0440\u0443\u0441\u0441\u043a\u0438"); // "inrussian" in UTF8 Russian } @Test public void testParameters() throws Exception { File basedir = resources.getBasedir("compile/parameters"); compile(basedir, newParameter("parameters", "true"), newParameter("source", "1.8")); assertThat(new File(basedir, "target/classes/parameters/MethodParameter.class"), hasMethodParameterWithName("myNamedParameter")); } @Test public void testEmpty() throws Exception { File basedir = compile("compile/empty"); mojos.assertBuildOutputs(basedir, new String[0]); Assert.assertFalse("outputDirectory was not created", new File(basedir, "target/classes").exists()); } @Test public void testIncludeNonJavaSources() throws Exception { File basedir = resources.getBasedir("compile/unexpected-sources"); try { compile(basedir); } catch (MojoExecutionException e) { Assert.assertEquals("<includes> patterns must end with .java. Illegal patterns: [**]", e.getMessage()); } mojos.assertBuildOutputs(basedir, new String[0]); } @Test public void testMultipleExecutions() throws Exception { File basedir = resources.getBasedir("compile/multiple-executions"); MavenProject project = mojos.readMavenProject(basedir); MavenSession session = mojos.newMavenSession(project); // compile "other" sources, execution id="other" MojoExecution execution = mojos.newMojoExecution(); Xpp3Dom configuration = execution.getConfiguration(); Xpp3Dom otherIncludes = new Xpp3Dom("includes"); otherIncludes.addChild(newParameter("include", "other/*.java")); configuration.addChild(otherIncludes); execution = new MojoExecution(execution.getMojoDescriptor(), "other", execution.getSource()); execution.setConfiguration(configuration); mojos.executeMojo(session, project, execution); mojos.assertBuildOutputs(new File(basedir, "target/classes"), "other/Other.class"); // compile main sources Xpp3Dom includes = new Xpp3Dom("includes"); includes.addChild(newParameter("include", "main/*.java")); compile(basedir, includes); mojos.assertBuildOutputs(new File(basedir, "target/classes"), "main/Main.class"); } @Test public void testBinaryTypeMessage() throws Exception { // javac (tested with 1.8.0_05 and 1.7.0_45) produce warning messages for dependency .class files in some cases // the point of this test is to verify compile mojo tolerates this messages, i.e. does not fail // in this particular test, the message is triggered by missing @annotation referenced from a dependency class File basedir = resources.getBasedir("compile/binary-class-message"); MavenProject project = mojos.readMavenProject(new File(basedir, "project")); MavenSession session = mojos.newMavenSession(project); MojoExecution execution = mojos.newMojoExecution(); addDependency(project, "dependency", new File(basedir, "annotated.zip")); mojos.executeMojo(session, project, execution); mojos.assertBuildOutputs(new File(basedir, "project/target/classes"), "project/Project.class"); } @Test public void testImplicitClassfileGeneration() throws Exception { // javac automatically generates class files from sources found on classpath in some cases // the point of this test is to make sure this behaviour is disabled File dependency = compile("compile/basic"); cp(dependency, "src/main/java/basic/Basic.java", "target/classes/basic/Basic.java"); touch(dependency, "target/classes/basic/Basic.java"); // must be newer than .class file File basedir = resources.getBasedir("compile/implicit-classfile"); MavenProject project = mojos.readMavenProject(basedir); MavenSession session = mojos.newMavenSession(project); MojoExecution execution = mojos.newMojoExecution(); addDependency(project, "dependency", new File(dependency, "target/classes")); mojos.executeMojo(session, project, execution); mojos.assertBuildOutputs(new File(basedir, "target/classes"), "implicit/Implicit.class"); } @Test public void testAnnotation() throws Exception { File basedir = compile("compile/annotation"); assertThat(new File(basedir, "target/classes/annotation/AnnotatedClass.class"), hasAnnotation("annotation.Annotation")); } @Test @Ignore("The test is useful but needs to be reimplemented") public void testInnerTypeDependency_sourceDependencies() throws Exception { File basedir = resources.getBasedir("compile/inner-type-dependency"); MavenProject project = mojos.readMavenProject(basedir); addDependency(project, "dependency", new File(basedir, "dependency/src/main/java")); mojos.compile(project, newParameter("dependencySourceTypes", "prefer")); mojos.assertBuildOutputs(new File(basedir, "target/classes"), "innertyperef/InnerTypeRef.class"); } }