View Javadoc
1   package org.codehaus.plexus.compiler.javac;
2   
3   /**
4    * The MIT License
5    *
6    * Copyright (c) 2005, The Codehaus
7    *
8    * Permission is hereby granted, free of charge, to any person obtaining a copy of
9    * this software and associated documentation files (the "Software"), to deal in
10   * the Software without restriction, including without limitation the rights to
11   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12   * of the Software, and to permit persons to whom the Software is furnished to do
13   * so, subject to the following conditions:
14   *
15   * The above copyright notice and this permission notice shall be included in all
16   * copies or substantial portions of the Software.
17   *
18   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24   * SOFTWARE.
25   */
26  import java.io.File;
27  import java.util.ArrayList;
28  import java.util.Arrays;
29  import java.util.Collection;
30  import java.util.LinkedHashMap;
31  import java.util.List;
32  import java.util.Map;
33  
34  import org.codehaus.plexus.compiler.AbstractCompilerTest;
35  import org.codehaus.plexus.compiler.CompilerConfiguration;
36  import org.codehaus.plexus.util.StringUtils;
37  import org.junit.jupiter.api.BeforeEach;
38  import org.junit.jupiter.api.Test;
39  
40  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
41  
42  /**
43   * @author <a href="mailto:jason@plexus.org">Jason van Zyl</a>
44   */
45  public abstract class AbstractJavacCompilerTest extends AbstractCompilerTest {
46      private static final String PS = File.pathSeparator;
47  
48      @BeforeEach
49      public void setUp() {
50          setCompilerDebug(true);
51          setCompilerDeprecationWarnings(true);
52      }
53  
54      @Override
55      protected String getRoleHint() {
56          return "javac";
57      }
58  
59      @Override
60      protected int expectedErrors() {
61          String javaVersion = getJavaVersion();
62          if (javaVersion.contains("11")
63                  || javaVersion.contains("17")
64                  || javaVersion.contains("21")
65                  || javaVersion.contains("25")) {
66              return 5;
67          }
68          // javac output changed for misspelled modifiers starting in 1.6...they now generate 2 errors per occurrence,
69          // not one.
70          if ("1.5".compareTo(javaVersion) < 0) {
71              return 4;
72          } else {
73              return 3;
74          }
75      }
76  
77      @Override
78      protected int expectedWarnings() {
79          String javaVersion = getJavaVersion();
80          if (javaVersion.contains("11")
81                  || javaVersion.contains("17")
82                  || javaVersion.contains("21")
83                  || javaVersion.contains("25")) {
84              return 1;
85          }
86          if (javaVersion.contains("1.8")) {
87              // lots of new warnings about obsoletions for future releases
88              return 30;
89          }
90  
91          if ("1.6".compareTo(javaVersion) < 0) {
92              // with 1.7 some warning with bootstrap class path not set in conjunction with -source 1.3
93              return 9;
94          }
95  
96          return 2;
97      }
98  
99      @Override
100     public String getTargetVersion() {
101         String javaVersion = getJavaVersion();
102         if (javaVersion.contains("9.0")) {
103             return "1.7";
104         } else if (javaVersion.contains("11")) {
105             return "11";
106         } else if (javaVersion.contains("14")) {
107             return "14";
108         } else if (javaVersion.contains("15")) {
109             return "15";
110         } else if (javaVersion.contains("16")) {
111             return "16";
112         } else if (javaVersion.contains("17")) {
113             return "17";
114         } else if (javaVersion.contains("18")) {
115             return "18";
116         } else if (javaVersion.contains("19")) {
117             return "19";
118         } else if (javaVersion.contains("20")) {
119             return "20";
120         } else if (javaVersion.contains("21")) {
121             return "21";
122         } else if (javaVersion.contains("22")) {
123             return "22";
124         } else if (javaVersion.contains("23")) {
125             return "23";
126         } else if (javaVersion.contains("24")) {
127             return "24";
128         } else if (javaVersion.contains("25")) {
129             return "25";
130         }
131         return super.getTargetVersion();
132     }
133 
134     @Override
135     public String getSourceVersion() {
136         String javaVersion = getJavaVersion();
137         if (javaVersion.contains("9.0")) {
138             return "1.7";
139         } else if (javaVersion.contains("11")) {
140             return "11";
141         } else if (javaVersion.contains("14")) {
142             return "14";
143         } else if (javaVersion.contains("15")) {
144             return "15";
145         } else if (javaVersion.contains("16")) {
146             return "16";
147         } else if (javaVersion.contains("17")) {
148             return "17";
149         } else if (javaVersion.contains("18")) {
150             return "18";
151         } else if (javaVersion.contains("19")) {
152             return "19";
153         } else if (javaVersion.contains("20")) {
154             return "20";
155         } else if (javaVersion.contains("21")) {
156             return "21";
157         } else if (javaVersion.contains("22")) {
158             return "22";
159         } else if (javaVersion.contains("23")) {
160             return "23";
161         } else if (javaVersion.contains("24")) {
162             return "24";
163         } else if (javaVersion.contains("25")) {
164             return "25";
165         }
166         return super.getSourceVersion();
167     }
168 
169     @Override
170     protected Collection<String> expectedOutputFiles() {
171         String javaVersion = getJavaVersion();
172         if (javaVersion.contains("11")
173                 || javaVersion.contains("17")
174                 || javaVersion.contains("21")
175                 || javaVersion.contains("25")) {
176             return Arrays.asList(
177                     "org/codehaus/foo/Deprecation.class",
178                     "org/codehaus/foo/ExternalDeps.class",
179                     "org/codehaus/foo/Person.class");
180         }
181         return Arrays.asList(
182                 "org/codehaus/foo/Deprecation.class",
183                 "org/codehaus/foo/ExternalDeps.class",
184                 "org/codehaus/foo/Person.class",
185                 "org/codehaus/foo/ReservedWord.class");
186     }
187 
188     protected void internalTest(
189             CompilerConfiguration compilerConfiguration, List<String> expectedArguments, String javacVersion) {
190         internalTest(compilerConfiguration, expectedArguments, new String[0], javacVersion);
191     }
192 
193     public void internalTest(
194             CompilerConfiguration compilerConfiguration,
195             List<String> expectedArguments,
196             String[] sources,
197             String javacVersion) {
198         String[] actualArguments = JavacCompiler.buildCompilerArguments(compilerConfiguration, sources, javacVersion);
199 
200         assertArrayEquals(actualArguments, expectedArguments.toArray(new String[0]));
201     }
202 
203     @Test
204     public void testBuildCompilerArgs13() {
205         List<String> expectedArguments = new ArrayList<>();
206 
207         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
208 
209         populateArguments(compilerConfiguration, expectedArguments, true, true, false);
210 
211         internalTest(compilerConfiguration, expectedArguments, "1.3");
212     }
213 
214     @Test
215     public void testBuildCompilerArgs14() {
216         List<String> expectedArguments = new ArrayList<>();
217 
218         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
219 
220         populateArguments(compilerConfiguration, expectedArguments, false, false, false);
221 
222         internalTest(compilerConfiguration, expectedArguments, "1.4");
223     }
224 
225     @Test
226     public void testBuildCompilerArgs15() {
227         List<String> expectedArguments = new ArrayList<>();
228 
229         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
230 
231         populateArguments(compilerConfiguration, expectedArguments, false, false, false);
232 
233         internalTest(compilerConfiguration, expectedArguments, "1.5");
234     }
235 
236     @Test
237     public void testBuildCompilerArgs18() {
238         List<String> expectedArguments = new ArrayList<>();
239 
240         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
241 
242         populateArguments(compilerConfiguration, expectedArguments, false, false, true);
243 
244         internalTest(compilerConfiguration, expectedArguments, "1.8");
245     }
246 
247     @Test
248     public void testBuildCompilerArgsUnspecifiedVersion() {
249         List<String> expectedArguments = new ArrayList<>();
250 
251         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
252 
253         populateArguments(compilerConfiguration, expectedArguments, false, false, true);
254 
255         internalTest(compilerConfiguration, expectedArguments, "unknown");
256     }
257 
258     @Test
259     public void testBuildCompilerDebugLevel() {
260         List<String> expectedArguments = new ArrayList<>();
261 
262         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
263 
264         compilerConfiguration.setDebug(true);
265 
266         compilerConfiguration.setDebugLevel("none");
267 
268         populateArguments(compilerConfiguration, expectedArguments, false, false, true);
269 
270         internalTest(compilerConfiguration, expectedArguments, "1.8");
271     }
272 
273     // PLXCOMP-190
274     @Test
275     public void testJRuntimeArguments() {
276         List<String> expectedArguments = new ArrayList<>();
277 
278         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
279 
280         // outputLocation
281         compilerConfiguration.setOutputLocation("/output");
282         expectedArguments.add("-d");
283         expectedArguments.add(new File("/output").getAbsolutePath());
284 
285         // targetVersion
286         compilerConfiguration.setTargetVersion("1.3");
287         expectedArguments.add("-target");
288         expectedArguments.add("1.3");
289 
290         // sourceVersion
291         compilerConfiguration.setSourceVersion("1.3");
292         expectedArguments.add("-source");
293         expectedArguments.add("1.3");
294 
295         // unshared table
296         expectedArguments.add("-XDuseUnsharedTable=true");
297 
298         // customCompilerArguments
299         Map<String, String> customCompilerArguments = new LinkedHashMap<>();
300         customCompilerArguments.put("-J-Duser.language=en_us", null);
301         compilerConfiguration.setCustomCompilerArgumentsAsMap(customCompilerArguments);
302         // don't expect this argument!!
303 
304         internalTest(compilerConfiguration, expectedArguments, "1.8");
305     }
306 
307     @Test
308     public void testModulePathAnnotations() throws Exception {
309         List<String> expectedArguments = new ArrayList<>();
310 
311         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
312 
313         final String[] source = {"module-info.java"};
314 
315         // outputLocation
316         compilerConfiguration.setOutputLocation("/output");
317         expectedArguments.add("-d");
318         expectedArguments.add(new File("/output").getAbsolutePath());
319 
320         // failOnWarning
321         compilerConfiguration.setModulepathEntries(Arrays.asList("/repo/a/b/1.0/b-1.0.jar", "/repo/c/d/1.0/d-1.0.jar"));
322         expectedArguments.add("--module-path");
323         expectedArguments.add(
324                 "/repo/a/b/1.0/b-1.0.jar" + File.pathSeparator + "/repo/c/d/1.0/d-1.0.jar" + File.pathSeparator);
325 
326         compilerConfiguration.setProcessorModulePathEntries(
327                 Arrays.asList("/repo/a/b/1.0/annotations-1.0.jar", "/repo/f/a/1.0/annotations-4.0.jar"));
328         expectedArguments.add("--processor-module-path");
329         expectedArguments.add("/repo/a/b/1.0/annotations-1.0.jar" + File.pathSeparator
330                 + "/repo/f/a/1.0/annotations-4.0.jar" + File.pathSeparator);
331 
332         // releaseVersion
333         compilerConfiguration.setReleaseVersion("9");
334         expectedArguments.add("--release");
335         expectedArguments.add("9");
336 
337         // unshared table
338         expectedArguments.add("-XDuseUnsharedTable=true");
339 
340         internalTest(compilerConfiguration, expectedArguments, source, "11.0.1");
341     }
342 
343     @Test
344     public void testModulePath() throws Exception {
345         List<String> expectedArguments = new ArrayList<>();
346 
347         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
348 
349         // outputLocation
350         compilerConfiguration.setOutputLocation("/output");
351         expectedArguments.add("-d");
352         expectedArguments.add(new File("/output").getAbsolutePath());
353 
354         // failOnWarning
355         compilerConfiguration.setModulepathEntries(Arrays.asList("/repo/a/b/1.0/b-1.0.jar", "/repo/c/d/1.0/d-1.0.jar"));
356         expectedArguments.add("--module-path");
357         expectedArguments.add(
358                 "/repo/a/b/1.0/b-1.0.jar" + File.pathSeparator + "/repo/c/d/1.0/d-1.0.jar" + File.pathSeparator);
359 
360         // default source + target
361         expectedArguments.add("-target");
362         expectedArguments.add("1.1");
363         expectedArguments.add("-source");
364         expectedArguments.add("1.3");
365 
366         // unshared table
367         expectedArguments.add("-XDuseUnsharedTable=true");
368 
369         internalTest(compilerConfiguration, expectedArguments, "11.0.1");
370     }
371 
372     @Test
373     public void testModuleVersion() {
374         List<String> expectedArguments = new ArrayList<>();
375 
376         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
377 
378         // outputLocation
379         compilerConfiguration.setOutputLocation("/output");
380         expectedArguments.add("-d");
381         expectedArguments.add(new File("/output").getAbsolutePath());
382 
383         // default source + target
384         expectedArguments.add("-target");
385         expectedArguments.add("1.1");
386         expectedArguments.add("-source");
387         expectedArguments.add("1.3");
388 
389         // module version
390         compilerConfiguration.setModuleVersion("1.2.0-SNAPSHOT");
391         expectedArguments.add("--module-version");
392         expectedArguments.add("1.2.0-SNAPSHOT");
393 
394         // unshared table
395         expectedArguments.add("-XDuseUnsharedTable=true");
396 
397         internalTest(compilerConfiguration, expectedArguments, "11.0.1");
398     }
399 
400     @Test
401     public void testReleaseVersion() {
402         List<String> expectedArguments = new ArrayList<>();
403 
404         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
405 
406         // outputLocation
407         compilerConfiguration.setOutputLocation("/output");
408         expectedArguments.add("-d");
409         expectedArguments.add(new File("/output").getAbsolutePath());
410 
411         // releaseVersion
412         compilerConfiguration.setReleaseVersion("6");
413         expectedArguments.add("--release");
414         expectedArguments.add("6");
415 
416         // unshared table
417         expectedArguments.add("-XDuseUnsharedTable=true");
418 
419         internalTest(compilerConfiguration, expectedArguments, "11.0.1");
420     }
421 
422     @Test
423     public void testFailOnWarning() {
424         List<String> expectedArguments = new ArrayList<>();
425 
426         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
427 
428         // outputLocation
429         compilerConfiguration.setOutputLocation("/output");
430         expectedArguments.add("-d");
431         expectedArguments.add(new File("/output").getAbsolutePath());
432 
433         // failOnWarning
434         compilerConfiguration.setFailOnWarning(true);
435         expectedArguments.add("-Werror");
436 
437         // default source + target
438         expectedArguments.add("-target");
439         expectedArguments.add("1.1");
440         expectedArguments.add("-source");
441         expectedArguments.add("1.3");
442 
443         // unshared table
444         expectedArguments.add("-XDuseUnsharedTable=true");
445 
446         internalTest(compilerConfiguration, expectedArguments, "1.8");
447     }
448 
449     @Test
450     public void testMultipleAddExports() {
451         List<String> expectedArguments = new ArrayList<>();
452 
453         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
454 
455         // outputLocation
456         compilerConfiguration.setOutputLocation("/output");
457         expectedArguments.add("-d");
458         expectedArguments.add(new File("/output").getAbsolutePath());
459 
460         // default source + target
461         expectedArguments.add("-target");
462         expectedArguments.add("1.1");
463         expectedArguments.add("-source");
464         expectedArguments.add("1.3");
465 
466         // add multiple --add-exports
467         compilerConfiguration.addCompilerCustomArgument("--add-exports", "FROM-MOD/package1=OTHER-MOD");
468         expectedArguments.add("--add-exports");
469         expectedArguments.add("FROM-MOD/package1=OTHER-MOD");
470         compilerConfiguration.addCompilerCustomArgument("--add-exports", "FROM-MOD/package2=OTHER-MOD");
471         expectedArguments.add("--add-exports");
472         expectedArguments.add("FROM-MOD/package2=OTHER-MOD");
473 
474         // unshared table
475         expectedArguments.add("-XDuseUnsharedTable=true");
476 
477         internalTest(compilerConfiguration, expectedArguments, "1.8");
478     }
479 
480     @Test
481     public void testWithGivenUnsharedTable() {
482         List<String> expectedArguments = new ArrayList<>();
483 
484         CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
485 
486         // outputLocation
487         compilerConfiguration.setOutputLocation("/output");
488         expectedArguments.add("-d");
489         expectedArguments.add(new File("/output").getAbsolutePath());
490 
491         // releaseVersion
492         compilerConfiguration.setReleaseVersion("6");
493         expectedArguments.add("--release");
494         expectedArguments.add("6");
495 
496         // unshared table
497         compilerConfiguration.addCompilerCustomArgument("-XDuseUnsharedTable=false", null);
498         expectedArguments.add("-XDuseUnsharedTable=false");
499 
500         internalTest(compilerConfiguration, expectedArguments, "11.0.1");
501     }
502 
503     /* This test fails on Java 1.4. The multiple parameters of the same source file cause an error, as it is interpreted as a DuplicateClass
504      * Setting the size of the array to 3 is fine, but does not exactly test what it is supposed to - disabling the test for now
505     public void testCommandLineTooLongWhenForking()
506         throws Exception
507     {
508         JavacCompiler compiler = (JavacCompiler) lookup( org.codehaus.plexus.compiler.Compiler.ROLE, getRoleHint() );
509 
510         File destDir = new File( "target/test-classes-cmd" );
511         destDir.mkdirs();
512 
513         // fill the cmd line arguments, 300 is enough to make it break
514         String[] args = new String[400];
515         args[0] = "-d";
516         args[1] = destDir.getAbsolutePath();
517         for ( int i = 2; i < args.length; i++ )
518         {
519             args[i] = "org/codehaus/foo/Person.java";
520         }
521 
522         CompilerConfiguration config = new CompilerConfiguration();
523         config.setWorkingDirectory( new File( getBasedir() + "/src/test-input/src/main" ) );
524         config.setFork( true );
525 
526         List messages = compiler.compileOutOfProcess( config, "javac", args );
527 
528         assertEquals( "There were errors launching the external compiler: " + messages, 0, messages.size() );
529     }
530     */
531 
532     private void populateArguments(
533             CompilerConfiguration compilerConfiguration,
534             List<String> expectedArguments,
535             boolean suppressSourceVersion,
536             boolean suppressEncoding,
537             boolean parameters) {
538         // outputLocation
539 
540         compilerConfiguration.setOutputLocation("/output");
541 
542         expectedArguments.add("-d");
543 
544         expectedArguments.add(new File("/output").getAbsolutePath());
545 
546         // classpathEntires
547 
548         List<String> classpathEntries = new ArrayList<>();
549 
550         classpathEntries.add("/myjar1.jar");
551 
552         classpathEntries.add("/myjar2.jar");
553 
554         compilerConfiguration.setClasspathEntries(classpathEntries);
555 
556         expectedArguments.add("-classpath");
557 
558         expectedArguments.add("/myjar1.jar" + PS + "/myjar2.jar" + PS);
559 
560         // sourceRoots
561 
562         List<String> compileSourceRoots = new ArrayList<>();
563 
564         compileSourceRoots.add("/src/main/one");
565 
566         compileSourceRoots.add("/src/main/two");
567 
568         compilerConfiguration.setSourceLocations(compileSourceRoots);
569 
570         expectedArguments.add("-sourcepath");
571 
572         expectedArguments.add("/src/main/one" + PS + "/src/main/two" + PS);
573 
574         // debug
575 
576         compilerConfiguration.setDebug(true);
577 
578         if (StringUtils.isNotEmpty(compilerConfiguration.getDebugLevel())) {
579             expectedArguments.add("-g:" + compilerConfiguration.getDebugLevel());
580         } else {
581             expectedArguments.add("-g");
582         }
583 
584         // parameters
585 
586         compilerConfiguration.setParameters(true);
587 
588         if (parameters) {
589             expectedArguments.add("-parameters");
590         }
591 
592         // showDeprecation
593 
594         compilerConfiguration.setShowDeprecation(true);
595 
596         expectedArguments.add("-deprecation");
597 
598         // targetVersion
599 
600         compilerConfiguration.setTargetVersion("1.3");
601 
602         expectedArguments.add("-target");
603 
604         expectedArguments.add("1.3");
605 
606         // sourceVersion
607 
608         compilerConfiguration.setSourceVersion("1.3");
609 
610         if (!suppressSourceVersion) {
611             expectedArguments.add("-source");
612 
613             expectedArguments.add("1.3");
614         }
615 
616         // sourceEncoding
617 
618         compilerConfiguration.setSourceEncoding("iso-8859-1");
619 
620         if (!suppressEncoding) {
621             expectedArguments.add("-encoding");
622 
623             expectedArguments.add("iso-8859-1");
624         }
625 
626         // customerCompilerArguments
627 
628         Map<String, String> customerCompilerArguments = new LinkedHashMap<>();
629 
630         customerCompilerArguments.put("arg1", null);
631 
632         customerCompilerArguments.put("foo", "bar");
633 
634         compilerConfiguration.setCustomCompilerArgumentsAsMap(customerCompilerArguments);
635 
636         expectedArguments.add("arg1");
637 
638         expectedArguments.add("foo");
639 
640         expectedArguments.add("bar");
641 
642         expectedArguments.add("-XDuseUnsharedTable=true");
643     }
644 }