View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugin.compiler;
20  
21  import java.io.File;
22  import java.net.URI;
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collections;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Set;
29  
30  import org.apache.maven.artifact.Artifact;
31  import org.apache.maven.artifact.handler.ArtifactHandler;
32  import org.apache.maven.execution.MavenSession;
33  import org.apache.maven.plugin.MojoExecution;
34  import org.apache.maven.plugin.compiler.stubs.CompilerManagerStub;
35  import org.apache.maven.plugin.compiler.stubs.DebugEnabledLog;
36  import org.apache.maven.plugin.descriptor.MojoDescriptor;
37  import org.apache.maven.plugin.descriptor.PluginDescriptor;
38  import org.apache.maven.plugin.logging.Log;
39  import org.apache.maven.plugin.testing.AbstractMojoTestCase;
40  import org.apache.maven.plugin.testing.stubs.ArtifactStub;
41  import org.apache.maven.project.MavenProject;
42  
43  import static org.mockito.ArgumentMatchers.startsWith;
44  import static org.mockito.Mockito.mock;
45  import static org.mockito.Mockito.never;
46  import static org.mockito.Mockito.verify;
47  import static org.mockito.Mockito.when;
48  
49  public class CompilerMojoTestCase extends AbstractMojoTestCase {
50  
51      /**
52       * tests the ability of the plugin to compile a basic file
53       *
54       * @throws Exception
55       */
56      public void testCompilerBasic() throws Exception {
57          CompilerMojo compileMojo = getCompilerMojo("target/test-classes/unit/compiler-basic-test/plugin-config.xml");
58  
59          Log log = mock(Log.class);
60  
61          compileMojo.setLog(log);
62  
63          compileMojo.execute();
64  
65          File testClass = new File(compileMojo.getOutputDirectory(), "foo/TestCompile0.class");
66  
67          assertTrue(testClass.exists());
68  
69          TestCompilerMojo testCompileMojo =
70                  getTestCompilerMojo(compileMojo, "target/test-classes/unit/compiler-basic-test/plugin-config.xml");
71  
72          testCompileMojo.execute();
73  
74          Artifact projectArtifact = (Artifact) getVariableValueFromObject(compileMojo, "projectArtifact");
75          assertNotNull(
76                  "MCOMPILER-94: artifact file should only be null if there is nothing to compile",
77                  projectArtifact.getFile());
78  
79          testClass = new File(testCompileMojo.getOutputDirectory(), "foo/TestCompile0Test.class");
80  
81          verify(log).warn(startsWith("No explicit value set for target or release!"));
82  
83          assertTrue(testClass.exists());
84      }
85  
86      public void testCompilerBasicSourceTarget() throws Exception {
87          CompilerMojo compileMojo =
88                  getCompilerMojo("target/test-classes/unit/compiler-basic-sourcetarget/plugin-config.xml");
89  
90          Log log = mock(Log.class);
91  
92          compileMojo.setLog(log);
93  
94          compileMojo.execute();
95  
96          verify(log, never()).warn(startsWith("No explicit value set for target or release!"));
97      }
98  
99      /**
100      * tests the ability of the plugin to respond to empty source
101      *
102      * @throws Exception
103      */
104     public void testCompilerEmptySource() throws Exception {
105         CompilerMojo compileMojo =
106                 getCompilerMojo("target/test-classes/unit/compiler-empty-source-test/plugin-config.xml");
107 
108         compileMojo.execute();
109 
110         assertFalse(compileMojo.getOutputDirectory().exists());
111 
112         Artifact projectArtifact = (Artifact) getVariableValueFromObject(compileMojo, "projectArtifact");
113         assertNull(
114                 "MCOMPILER-94: artifact file should be null if there is nothing to compile", projectArtifact.getFile());
115 
116         TestCompilerMojo testCompileMojo = getTestCompilerMojo(
117                 compileMojo, "target/test-classes/unit/compiler-empty-source-test/plugin-config.xml");
118 
119         testCompileMojo.execute();
120 
121         assertFalse(testCompileMojo.getOutputDirectory().exists());
122     }
123 
124     /**
125      * tests the ability of the plugin to respond to includes and excludes correctly
126      *
127      * @throws Exception
128      */
129     public void testCompilerIncludesExcludes() throws Exception {
130         CompilerMojo compileMojo =
131                 getCompilerMojo("target/test-classes/unit/compiler-includes-excludes-test/plugin-config.xml");
132 
133         Set<String> includes = new HashSet<>();
134         includes.add("**/TestCompile4*.java");
135         setVariableValueToObject(compileMojo, "includes", includes);
136 
137         Set<String> excludes = new HashSet<>();
138         excludes.add("**/TestCompile2*.java");
139         excludes.add("**/TestCompile3*.java");
140         setVariableValueToObject(compileMojo, "excludes", excludes);
141 
142         compileMojo.execute();
143 
144         File testClass = new File(compileMojo.getOutputDirectory(), "foo/TestCompile2.class");
145         assertFalse(testClass.exists());
146 
147         testClass = new File(compileMojo.getOutputDirectory(), "foo/TestCompile3.class");
148         assertFalse(testClass.exists());
149 
150         testClass = new File(compileMojo.getOutputDirectory(), "foo/TestCompile4.class");
151         assertTrue(testClass.exists());
152 
153         TestCompilerMojo testCompileMojo = getTestCompilerMojo(
154                 compileMojo, "target/test-classes/unit/compiler-includes-excludes-test/plugin-config.xml");
155 
156         setVariableValueToObject(testCompileMojo, "testIncludes", includes);
157         setVariableValueToObject(testCompileMojo, "testExcludes", excludes);
158 
159         testCompileMojo.execute();
160 
161         testClass = new File(testCompileMojo.getOutputDirectory(), "foo/TestCompile2TestCase.class");
162         assertFalse(testClass.exists());
163 
164         testClass = new File(testCompileMojo.getOutputDirectory(), "foo/TestCompile3TestCase.class");
165         assertFalse(testClass.exists());
166 
167         testClass = new File(testCompileMojo.getOutputDirectory(), "foo/TestCompile4TestCase.class");
168         assertTrue(testClass.exists());
169     }
170 
171     /**
172      * tests the ability of the plugin to fork and successfully compile
173      *
174      * @throws Exception
175      */
176     public void testCompilerFork() throws Exception {
177         CompilerMojo compileMojo = getCompilerMojo("target/test-classes/unit/compiler-fork-test/plugin-config.xml");
178 
179         // JAVA_HOME doesn't have to be on the PATH.
180         setVariableValueToObject(
181                 compileMojo, "executable", new File(System.getenv("JAVA_HOME"), "bin/javac").getPath());
182 
183         compileMojo.execute();
184 
185         File testClass = new File(compileMojo.getOutputDirectory(), "foo/TestCompile1.class");
186         assertTrue(testClass.exists());
187 
188         TestCompilerMojo testCompileMojo =
189                 getTestCompilerMojo(compileMojo, "target/test-classes/unit/compiler-fork-test/plugin-config.xml");
190 
191         // JAVA_HOME doesn't have to be on the PATH.
192         setVariableValueToObject(
193                 testCompileMojo, "executable", new File(System.getenv("JAVA_HOME"), "bin/javac").getPath());
194 
195         testCompileMojo.execute();
196 
197         testClass = new File(testCompileMojo.getOutputDirectory(), "foo/TestCompile1TestCase.class");
198         assertTrue(testClass.exists());
199     }
200 
201     public void testOneOutputFileForAllInput() throws Exception {
202         CompilerMojo compileMojo =
203                 getCompilerMojo("target/test-classes/unit/compiler-one-output-file-test/plugin-config.xml");
204 
205         setVariableValueToObject(compileMojo, "compilerManager", new CompilerManagerStub());
206 
207         compileMojo.execute();
208 
209         File testClass = new File(compileMojo.getOutputDirectory(), "compiled.class");
210         assertTrue(testClass.exists());
211 
212         TestCompilerMojo testCompileMojo = getTestCompilerMojo(
213                 compileMojo, "target/test-classes/unit/compiler-one-output-file-test/plugin-config.xml");
214 
215         setVariableValueToObject(testCompileMojo, "compilerManager", new CompilerManagerStub());
216 
217         testCompileMojo.execute();
218 
219         testClass = new File(testCompileMojo.getOutputDirectory(), "compiled.class");
220         assertTrue(testClass.exists());
221     }
222 
223     public void testCompilerArgs() throws Exception {
224         CompilerMojo compileMojo = getCompilerMojo("target/test-classes/unit/compiler-args-test/plugin-config.xml");
225 
226         setVariableValueToObject(compileMojo, "compilerManager", new CompilerManagerStub());
227 
228         compileMojo.execute();
229 
230         File testClass = new File(compileMojo.getOutputDirectory(), "compiled.class");
231         assertTrue(testClass.exists());
232         assertEquals(
233                 Arrays.asList("key1=value1", "-Xlint", "-my&special:param-with+chars/not>allowed_in_XML_element_names"),
234                 compileMojo.compilerArgs);
235     }
236 
237     public void testImplicitFlagNone() throws Exception {
238         CompilerMojo compileMojo =
239                 getCompilerMojo("target/test-classes/unit/compiler-implicit-test/plugin-config-none.xml");
240 
241         assertEquals("none", compileMojo.getImplicit());
242     }
243 
244     public void testImplicitFlagNotSet() throws Exception {
245         CompilerMojo compileMojo =
246                 getCompilerMojo("target/test-classes/unit/compiler-implicit-test/plugin-config-not-set.xml");
247 
248         assertNull(compileMojo.getImplicit());
249     }
250 
251     public void testOneOutputFileForAllInput2() throws Exception {
252         CompilerMojo compileMojo =
253                 getCompilerMojo("target/test-classes/unit/compiler-one-output-file-test2/plugin-config.xml");
254 
255         setVariableValueToObject(compileMojo, "compilerManager", new CompilerManagerStub());
256 
257         Set<String> includes = new HashSet<>();
258         includes.add("**/TestCompile4*.java");
259         setVariableValueToObject(compileMojo, "includes", includes);
260 
261         Set<String> excludes = new HashSet<>();
262         excludes.add("**/TestCompile2*.java");
263         excludes.add("**/TestCompile3*.java");
264         setVariableValueToObject(compileMojo, "excludes", excludes);
265 
266         compileMojo.execute();
267 
268         File testClass = new File(compileMojo.getOutputDirectory(), "compiled.class");
269         assertTrue(testClass.exists());
270 
271         TestCompilerMojo testCompileMojo = getTestCompilerMojo(
272                 compileMojo, "target/test-classes/unit/compiler-one-output-file-test2/plugin-config.xml");
273 
274         setVariableValueToObject(testCompileMojo, "compilerManager", new CompilerManagerStub());
275         setVariableValueToObject(testCompileMojo, "testIncludes", includes);
276         setVariableValueToObject(testCompileMojo, "testExcludes", excludes);
277 
278         testCompileMojo.execute();
279 
280         testClass = new File(testCompileMojo.getOutputDirectory(), "compiled.class");
281         assertTrue(testClass.exists());
282     }
283 
284     public void testCompileFailure() throws Exception {
285         CompilerMojo compileMojo = getCompilerMojo("target/test-classes/unit/compiler-fail-test/plugin-config.xml");
286 
287         setVariableValueToObject(compileMojo, "compilerManager", new CompilerManagerStub(true));
288 
289         try {
290             compileMojo.execute();
291 
292             fail("Should throw an exception");
293         } catch (CompilationFailureException e) {
294             // expected
295         }
296     }
297 
298     public void testCompileFailOnError() throws Exception {
299         CompilerMojo compileMojo =
300                 getCompilerMojo("target/test-classes/unit/compiler-failonerror-test/plugin-config.xml");
301 
302         setVariableValueToObject(compileMojo, "compilerManager", new CompilerManagerStub(true));
303 
304         try {
305             compileMojo.execute();
306             assertTrue(true);
307         } catch (CompilationFailureException e) {
308             fail("The compilation error should have been consumed because failOnError = false");
309         }
310     }
311 
312     /**
313      * Tests that setting 'skipMain' to true skips compilation of the main Java source files, but that test Java source
314      * files are still compiled.
315      * @throws Exception
316      */
317     public void testCompileSkipMain() throws Exception {
318         CompilerMojo compileMojo = getCompilerMojo("target/test-classes/unit/compiler-skip-main/plugin-config.xml");
319         setVariableValueToObject(compileMojo, "skipMain", true);
320         compileMojo.execute();
321         File testClass = new File(compileMojo.getOutputDirectory(), "foo/TestSkipMainCompile0.class");
322         assertFalse(testClass.exists());
323 
324         TestCompilerMojo testCompileMojo =
325                 getTestCompilerMojo(compileMojo, "target/test-classes/unit/compiler-skip-main/plugin-config.xml");
326         testCompileMojo.execute();
327         testClass = new File(testCompileMojo.getOutputDirectory(), "foo/TestSkipMainCompile0Test.class");
328         assertTrue(testClass.exists());
329     }
330 
331     /**
332      * Tests that setting 'skip' to true skips compilation of the test Java source files, but that main Java source
333      * files are still compiled.
334      * @throws Exception
335      */
336     public void testCompileSkipTest() throws Exception {
337         CompilerMojo compileMojo = getCompilerMojo("target/test-classes/unit/compiler-skip-test/plugin-config.xml");
338         compileMojo.execute();
339         File testClass = new File(compileMojo.getOutputDirectory(), "foo/TestSkipTestCompile0.class");
340         assertTrue(testClass.exists());
341 
342         TestCompilerMojo testCompileMojo =
343                 getTestCompilerMojo(compileMojo, "target/test-classes/unit/compiler-skip-test/plugin-config.xml");
344         setVariableValueToObject(testCompileMojo, "skip", true);
345         testCompileMojo.execute();
346         testClass = new File(testCompileMojo.getOutputDirectory(), "foo/TestSkipTestCompile0Test.class");
347         assertFalse(testClass.exists());
348     }
349 
350     private CompilerMojo getCompilerMojo(String pomXml) throws Exception {
351         File testPom = new File(getBasedir(), pomXml);
352 
353         CompilerMojo mojo = (CompilerMojo) lookupMojo("compile", testPom);
354 
355         setVariableValueToObject(mojo, "log", new DebugEnabledLog());
356         setVariableValueToObject(mojo, "projectArtifact", new ArtifactStub());
357         setVariableValueToObject(mojo, "compilePath", Collections.EMPTY_LIST);
358         setVariableValueToObject(mojo, "session", getMockMavenSession());
359         setVariableValueToObject(mojo, "project", getMockMavenProject());
360         setVariableValueToObject(mojo, "mojoExecution", getMockMojoExecution());
361         setVariableValueToObject(mojo, "source", AbstractCompilerMojo.DEFAULT_SOURCE);
362         setVariableValueToObject(mojo, "target", AbstractCompilerMojo.DEFAULT_TARGET);
363 
364         return mojo;
365     }
366 
367     private TestCompilerMojo getTestCompilerMojo(CompilerMojo compilerMojo, String pomXml) throws Exception {
368         File testPom = new File(getBasedir(), pomXml);
369 
370         TestCompilerMojo mojo = (TestCompilerMojo) lookupMojo("testCompile", testPom);
371 
372         setVariableValueToObject(mojo, "log", new DebugEnabledLog());
373 
374         File buildDir = (File) getVariableValueFromObject(compilerMojo, "buildDirectory");
375         File testClassesDir = new File(buildDir, "test-classes");
376         setVariableValueToObject(mojo, "outputDirectory", testClassesDir);
377 
378         List<String> testClasspathList = new ArrayList<>();
379 
380         Artifact junitArtifact = mock(Artifact.class);
381         ArtifactHandler handler = mock(ArtifactHandler.class);
382         when(handler.isAddedToClasspath()).thenReturn(true);
383         when(junitArtifact.getArtifactHandler()).thenReturn(handler);
384 
385         String junitURI = org.junit.Test.class.getResource("Test.class").toURI().toString();
386         junitURI = junitURI.substring("jar:".length(), junitURI.indexOf('!'));
387         File artifactFile = new File(URI.create(junitURI));
388         when(junitArtifact.getFile()).thenReturn(artifactFile);
389 
390         testClasspathList.add(artifactFile.getAbsolutePath());
391         testClasspathList.add(compilerMojo.getOutputDirectory().getPath());
392 
393         String testSourceRoot = testPom.getParent() + "/src/test/java";
394         setVariableValueToObject(mojo, "compileSourceRoots", Collections.singletonList(testSourceRoot));
395 
396         MavenProject project = getMockMavenProject();
397         project.setFile(testPom);
398         project.addCompileSourceRoot("/src/main/java");
399         project.setArtifacts(Collections.singleton(junitArtifact));
400         project.getBuild().setOutputDirectory(new File(buildDir, "classes").getAbsolutePath());
401         setVariableValueToObject(mojo, "project", project);
402         setVariableValueToObject(mojo, "testPath", testClasspathList);
403         setVariableValueToObject(mojo, "session", getMockMavenSession());
404         setVariableValueToObject(mojo, "mojoExecution", getMockMojoExecution());
405         setVariableValueToObject(mojo, "source", AbstractCompilerMojo.DEFAULT_SOURCE);
406         setVariableValueToObject(mojo, "target", AbstractCompilerMojo.DEFAULT_TARGET);
407 
408         return mojo;
409     }
410 
411     private MavenProject getMockMavenProject() {
412         MavenProject mp = new MavenProject();
413         mp.getBuild().setDirectory("target");
414         mp.getBuild().setOutputDirectory("target/classes");
415         mp.getBuild().setSourceDirectory("src/main/java");
416         mp.getBuild().setTestOutputDirectory("target/test-classes");
417         return mp;
418     }
419 
420     private MavenSession getMockMavenSession() {
421         MavenSession session = mock(MavenSession.class);
422         // when( session.getPluginContext( isA(PluginDescriptor.class), isA(MavenProject.class) ) ).thenReturn(
423         // Collections.emptyMap() );
424         when(session.getCurrentProject()).thenReturn(getMockMavenProject());
425         return session;
426     }
427 
428     private MojoExecution getMockMojoExecution() {
429         MojoDescriptor md = new MojoDescriptor();
430         md.setGoal("compile");
431 
432         MojoExecution me = new MojoExecution(md);
433 
434         PluginDescriptor pd = new PluginDescriptor();
435         pd.setArtifactId("maven-compiler-plugin");
436         md.setPluginDescriptor(pd);
437 
438         return me;
439     }
440 }