1 package org.apache.maven.plugins.javadoc;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.StringReader;
25 import java.lang.reflect.Method;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Properties;
30
31 import org.apache.maven.execution.MavenSession;
32 import org.apache.maven.plugin.logging.Log;
33 import org.apache.maven.plugin.testing.AbstractMojoTestCase;
34 import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
35 import org.apache.maven.plugins.javadoc.AbstractFixJavadocMojo.JavaEntityTags;
36 import org.apache.maven.shared.invoker.MavenInvocationException;
37 import org.codehaus.plexus.languages.java.version.JavaVersion;
38 import org.codehaus.plexus.util.FileUtils;
39 import org.codehaus.plexus.util.StringUtils;
40
41 import com.thoughtworks.qdox.JavaProjectBuilder;
42 import com.thoughtworks.qdox.model.DocletTag;
43 import com.thoughtworks.qdox.model.JavaClass;
44 import com.thoughtworks.qdox.model.JavaMethod;
45
46 import static org.apache.commons.lang3.reflect.MethodUtils.invokeMethod;
47
48
49
50
51 public class FixJavadocMojoTest
52 extends AbstractMojoTestCase
53 {
54
55 private static final String EOL = System.getProperty( "line.separator" );
56
57
58 private static boolean TEST_REPO_CREATED = false;
59
60
61 @Override
62 protected void setUp()
63 throws Exception
64 {
65 super.setUp();
66
67 createTestRepo();
68 }
69
70
71
72
73
74
75 private void createTestRepo()
76 throws Exception
77 {
78 if ( TEST_REPO_CREATED )
79 {
80 return;
81 }
82
83 File localRepo = new File( getBasedir(), "target/local-repo/" );
84 localRepo.mkdirs();
85
86
87
88
89
90 File sourceDir = new File( getBasedir(), "src/test/resources/unit/fix-test/repo/" );
91 assertTrue( sourceDir.exists() );
92 FileUtils.copyDirectoryStructure( sourceDir, localRepo );
93
94
95
96 List<String> files =
97 FileUtils.getFileAndDirectoryNames( localRepo, FileUtils.getDefaultExcludesAsString(), null, true,
98 true, true, true );
99 for ( String filename : files )
100 {
101 File file = new File( filename );
102
103 if ( file.isDirectory() )
104 {
105 FileUtils.deleteDirectory( file );
106 }
107 else
108 {
109 file.delete();
110 }
111 }
112
113 TEST_REPO_CREATED = true;
114 }
115
116
117
118
119 public void testFix()
120 throws Exception
121 {
122 File testPomBasedir = new File( getBasedir(), "target/test/unit/fix-test" );
123
124 executeMojoAndTest( testPomBasedir, new String[] { "ClassWithJavadoc.java", "ClassWithNoJavadoc.java",
125 "InterfaceWithJavadoc.java", "InterfaceWithNoJavadoc.java" } );
126 }
127
128
129
130
131
132
133
134
135 public void testAutodetectIndentation()
136 throws Exception
137 {
138 Method method = AbstractFixJavadocMojo.class.getDeclaredMethod( "autodetectIndentation", String.class );
139 method.setAccessible( true );
140
141 String s = null;
142 assertEquals( "", (String) method.invoke( null, s ) );
143
144 s = "no indentation";
145 assertEquals( "", (String) method.invoke( null, s ) );
146
147 s = "no indentation with right spaces ";
148 assertEquals( "", (String) method.invoke( null, s ) );
149
150 s = " indentation";
151 assertEquals( " ", (String) method.invoke( null, s ) );
152
153 s = " indentation with right spaces ";
154 assertEquals( " ", (String) method.invoke( null, s ) );
155
156 s = "\ttab indentation";
157 assertEquals( "\t", (String) method.invoke( null, s ) );
158
159 s = " \n indentation with right spaces ";
160 assertEquals( " \n ", (String) method.invoke( null, s ) );
161 }
162
163
164
165
166 public void testTrimLeft()
167 throws Exception
168 {
169 Method method = AbstractFixJavadocMojo.class.getDeclaredMethod( "trimLeft", String.class );
170 method.setAccessible( true );
171
172 assertEquals( "", (String) method.invoke( null, (String) null ) );
173 assertEquals( "", (String) method.invoke( null, " " ) );
174 assertEquals( "", (String) method.invoke( null, " \t " ) );
175 assertEquals( "a", (String) method.invoke( null, "a" ) );
176 assertEquals( "a", (String) method.invoke( null, " a" ) );
177 assertEquals( "a", (String) method.invoke( null, "\ta" ) );
178 assertEquals( "a ", (String) method.invoke( null, " a " ) );
179 assertEquals( "a\t", (String) method.invoke( null, "\ta\t" ) );
180 }
181
182
183
184
185 public void testTrimRight()
186 throws Exception
187 {
188 Method method = AbstractFixJavadocMojo.class.getDeclaredMethod( "trimRight", String.class );
189 method.setAccessible( true );
190
191 assertEquals( "", (String) method.invoke( null, (String)null ) );
192 assertEquals( "", (String) method.invoke( null, " " ) );
193 assertEquals( "", (String) method.invoke( null, " \t " ) );
194 assertEquals( "a", (String) method.invoke( null, "a" ) );
195 assertEquals( "a", (String) method.invoke( null, "a " ) );
196 assertEquals( "a", (String) method.invoke( null, "a\t" ) );
197 assertEquals( " a", (String) method.invoke( null, " a " ) );
198 assertEquals( "\ta", (String) method.invoke( null, "\ta\t" ) );
199 }
200
201
202
203
204 public void testHasInheritedTag()
205 throws Exception
206 {
207 Method method = AbstractFixJavadocMojo.class.getDeclaredMethod( "hasInheritedTag", String.class );
208 method.setAccessible( true );
209
210 String content = "/** {@inheritDoc} */";
211 Boolean has = (Boolean) method.invoke( null, content );
212 assertEquals( Boolean.TRUE, has );
213
214 content = "/**{@inheritDoc}*/";
215 has = (Boolean) method.invoke( null, content );
216 assertEquals( Boolean.TRUE, has );
217
218 content = "/**{@inheritDoc } */";
219 has = (Boolean) method.invoke( null, content );
220 assertEquals( Boolean.TRUE, has );
221
222 content = "/** {@inheritDoc } */";
223 has = (Boolean) method.invoke( null, content );
224 assertEquals( Boolean.TRUE, has );
225
226 content = "/** */";
227 has = (Boolean) method.invoke( null, content );
228 assertEquals( Boolean.FALSE, has );
229
230 content = "/**{ @inheritDoc }*/";
231 has = (Boolean) method.invoke( null, content );
232 assertEquals( Boolean.FALSE, has );
233
234 content = "/**{@ inheritDoc}*/";
235 has = (Boolean) method.invoke( null, content );
236 assertEquals( Boolean.FALSE, has );
237 }
238
239
240
241
242 public void testJavadocComment()
243 throws Throwable
244 {
245 String content = "/**" + EOL +
246 " * Dummy Class." + EOL +
247 " */" + EOL +
248 "public class DummyClass" + EOL +
249 "{" + EOL +
250 " /**" + EOL +
251 " *" + EOL +
252 " * Dummy" + EOL +
253 " *" + EOL +
254 " * Method." + EOL +
255 " *" + EOL +
256 " * @param args not" + EOL +
257 " *" + EOL +
258 " * null" + EOL +
259 " * @param i non negative" + EOL +
260 " * @param object could" + EOL +
261 " * be" + EOL +
262 " * null" + EOL +
263 " * @return a" + EOL +
264 " * String" + EOL +
265 " *" + EOL +
266 " * @throws Exception if" + EOL +
267 " * any" + EOL +
268 " *" + EOL +
269 " */" + EOL +
270 " public static String dummyMethod( String[] args, int i, Object object )" + EOL +
271 " throws Exception" + EOL +
272 " {" + EOL +
273 " return null;" + EOL +
274 " }" + EOL +
275 "}";
276
277 JavaProjectBuilder builder = new JavaProjectBuilder();
278 builder.setEncoding( "UTF-8" );
279 builder.addSource( new StringReader( content ) );
280
281 JavaClass clazz = builder.addSource( new StringReader( content ) ).getClassByName( "DummyClass" );
282
283 JavaMethod javaMethod = clazz.getMethods().get( 0 );
284
285 String javadoc = AbstractFixJavadocMojo.extractOriginalJavadoc( content, javaMethod );
286 assertEquals( " /**" + EOL +
287 " *" + EOL +
288 " * Dummy" + EOL +
289 " *" + EOL +
290 " * Method." + EOL +
291 " *" + EOL +
292 " * @param args not" + EOL +
293 " *" + EOL +
294 " * null" + EOL +
295 " * @param i non negative" + EOL +
296 " * @param object could" + EOL +
297 " * be" + EOL +
298 " * null" + EOL +
299 " * @return a" + EOL +
300 " * String" + EOL +
301 " *" + EOL +
302 " * @throws Exception if" + EOL +
303 " * any" + EOL +
304 " *" + EOL +
305 " */", javadoc );
306
307 String javadocContent = AbstractFixJavadocMojo.extractOriginalJavadocContent( content, javaMethod );
308 assertEquals( " *" + EOL +
309 " * Dummy" + EOL +
310 " *" + EOL +
311 " * Method." + EOL +
312 " *" + EOL +
313 " * @param args not" + EOL +
314 " *" + EOL +
315 " * null" + EOL +
316 " * @param i non negative" + EOL +
317 " * @param object could" + EOL +
318 " * be" + EOL +
319 " * null" + EOL +
320 " * @return a" + EOL +
321 " * String" + EOL +
322 " *" + EOL +
323 " * @throws Exception if" + EOL +
324 " * any" + EOL +
325 " *", javadocContent );
326
327 Method method = AbstractFixJavadocMojo.class.getDeclaredMethod( "removeLastEmptyJavadocLines", String.class );
328 method.setAccessible( true );
329
330 String withoutEmptyJavadocLines = (String) method.invoke( null, javadocContent );
331 assertTrue( withoutEmptyJavadocLines.endsWith( "any" ) );
332
333 String methodJavadoc = AbstractFixJavadocMojo.getJavadocComment( content, javaMethod );
334 assertEquals( " *" + EOL +
335 " * Dummy" + EOL +
336 " *" + EOL +
337 " * Method." + EOL +
338 " *", methodJavadoc );
339 withoutEmptyJavadocLines = (String) method.invoke( null, methodJavadoc );
340 assertTrue( withoutEmptyJavadocLines.endsWith( "Method." ) );
341
342 assertEquals( 5, javaMethod.getTags().size() );
343
344 AbstractFixJavadocMojo mojoInstance = new FixJavadocMojo();
345 setVariableValueToObject( mojoInstance, "fixTagsSplitted", new String[] { "all" } );
346
347 DocletTag tag = javaMethod.getTags().get( 0 );
348 String tagJavadoc = mojoInstance.getJavadocComment( content, javaMethod, tag);
349 assertEquals( " * @param args not" + EOL +
350 " *" + EOL +
351 " * null", tagJavadoc );
352 withoutEmptyJavadocLines = (String) method.invoke( null, tagJavadoc );
353 assertTrue( withoutEmptyJavadocLines.endsWith( "null" ) );
354
355 tag = javaMethod.getTags().get( 1 );
356 tagJavadoc = mojoInstance.getJavadocComment( content, javaMethod, tag );
357 assertEquals( " * @param i non negative", tagJavadoc );
358 withoutEmptyJavadocLines = (String) method.invoke( null, tagJavadoc );
359 assertTrue( withoutEmptyJavadocLines.endsWith( "negative" ) );
360
361 tag = javaMethod.getTags().get( 2 );
362 tagJavadoc = mojoInstance.getJavadocComment( content, javaMethod, tag );
363 assertEquals( " * @param object could" + EOL +
364 " * be" + EOL +
365 " * null", tagJavadoc );
366 withoutEmptyJavadocLines = (String) method.invoke( null, tagJavadoc );
367 assertTrue( withoutEmptyJavadocLines.endsWith( "null" ) );
368
369 tag = javaMethod.getTags().get( 3 );
370 tagJavadoc = mojoInstance.getJavadocComment( content, javaMethod, tag );
371 assertEquals( " * @return a" + EOL +
372 " * String" + EOL +
373 " *", tagJavadoc );
374 withoutEmptyJavadocLines = (String) method.invoke( null, tagJavadoc );
375 assertTrue( withoutEmptyJavadocLines.endsWith( "String" ) );
376
377 tag = javaMethod.getTags().get( 4 );
378 tagJavadoc = mojoInstance.getJavadocComment( content, javaMethod, tag );
379 assertEquals( " * @throws Exception if" + EOL +
380 " * any" + EOL +
381 " *", tagJavadoc );
382 withoutEmptyJavadocLines = (String) method.invoke( null, tagJavadoc );
383 assertTrue( withoutEmptyJavadocLines.endsWith( "any" ) );
384 }
385
386 public void testJavadocCommentJdk5()
387 throws Exception
388 {
389 String content = "/**" + EOL +
390 " * Dummy Class." + EOL +
391 " */" + EOL +
392 "public class DummyClass" + EOL +
393 "{" + EOL +
394 " /**" + EOL +
395 " * Dummy method." + EOL +
396 " *" + EOL +
397 " * @param <K> The Key type for the method" + EOL +
398 " * @param <V> The Value type for the method" + EOL +
399 " * @param name The name." + EOL +
400 " * @return A map configured." + EOL +
401 " */" + EOL +
402 " public <K, V> java.util.Map<K, V> dummyMethod( String name )" + EOL +
403 " {" + EOL +
404 " return null;" + EOL +
405 " }" + EOL +
406 "}";
407
408 JavaProjectBuilder builder = new JavaProjectBuilder();
409 builder.setEncoding( "UTF-8" );
410 JavaClass clazz = builder.addSource( new StringReader( content ) ).getClassByName( "DummyClass" );
411
412 JavaMethod javaMethod = clazz.getMethods().get( 0 );
413
414 String methodJavadoc = AbstractFixJavadocMojo.getJavadocComment( content, javaMethod );
415 assertEquals( " * Dummy method." + EOL +
416 " *", methodJavadoc );
417
418 assertEquals( 4, javaMethod.getTags().size() );
419
420 AbstractFixJavadocMojo mojoInstance = new FixJavadocMojo();
421 setVariableValueToObject( mojoInstance, "fixTagsSplitted", new String[] { "all" } );
422
423 DocletTag tag = javaMethod.getTags().get( 0 );
424 String tagJavadoc = mojoInstance.getJavadocComment( content, javaMethod, tag );
425 assertEquals( " * @param <K> The Key type for the method", tagJavadoc );
426
427 tag = javaMethod.getTags().get( 1 );
428 tagJavadoc = mojoInstance.getJavadocComment( content, javaMethod, tag );
429 assertEquals( " * @param <V> The Value type for the method", tagJavadoc );
430
431 tag = javaMethod.getTags().get( 2 );
432 tagJavadoc = mojoInstance.getJavadocComment( content, javaMethod, tag );
433 assertEquals( " * @param name The name.", tagJavadoc );
434
435 tag = javaMethod.getTags().get( 3 );
436 tagJavadoc = mojoInstance.getJavadocComment( content, javaMethod, tag );
437 assertEquals( " * @return A map configured.", tagJavadoc );
438 }
439
440 public void testInitParameters()
441 throws Throwable
442 {
443 AbstractFixJavadocMojo mojoInstance = new FixJavadocMojo();
444 setVariableValueToObject( mojoInstance, "fixTags", "author, version, since, param, return, throws, link" );
445 setVariableValueToObject(mojoInstance, "defaultSince", "1.0");
446 setVariableValueToObject(mojoInstance, "level", "protected");
447
448 invokeMethod( mojoInstance, true, "init" );
449
450 String[] fixTags = (String[]) getVariableValueFromObject(mojoInstance, "fixTagsSplitted");
451
452 assertEquals("author", fixTags[0]);
453 assertEquals("version", fixTags[1]);
454 assertEquals("since", fixTags[2]);
455 assertEquals("param", fixTags[3]);
456 assertEquals("return", fixTags[4]);
457 assertEquals("throws", fixTags[5]);
458 assertEquals("link", fixTags[6]);
459 assertEquals(7, fixTags.length);
460
461 setVariableValueToObject( mojoInstance, "fixTags", "return, fake_value" );
462 invokeMethod( mojoInstance, true, "init" );
463 fixTags = (String[]) getVariableValueFromObject(mojoInstance, "fixTagsSplitted");
464
465 assertEquals("return", fixTags[0]);
466 assertEquals(1, fixTags.length);
467 }
468
469 public void testRemoveUnknownExceptions() throws Exception
470 {
471 AbstractFixJavadocMojo mojoInstance = new FixJavadocMojo();
472 setVariableValueToObject( mojoInstance, "fixTagsSplitted", new String[] { "all" } );
473 setVariableValueToObject( mojoInstance, "project", new MavenProjectStub() );
474
475 String source = "package a.b.c;" + EOL
476 + "public class Clazz {" + EOL
477 + " /**" + EOL
478 + " * @throws java.lang.RuntimeException" + EOL
479 + " * @throws NumberFormatException" + EOL
480 + " * @throws java.lang.Exception" + EOL
481 + " * @throws com.foo.FatalException" + EOL
482 + " */" + EOL
483 + " public void method() {}" + EOL
484 + "}";
485
486 JavaProjectBuilder builder = new JavaProjectBuilder();
487 JavaMethod javaMethod = builder.addSource( new StringReader( source ) ).getClassByName( "Clazz" ).getMethods().get( 0 );
488
489 JavaEntityTags javaEntityTags = mojoInstance.parseJavadocTags( source, javaMethod, "", true );
490
491 StringBuilder sb = new StringBuilder();
492 mojoInstance.writeThrowsTag( sb, javaMethod, javaEntityTags, Collections.singletonList("java.lang" +
493 ".RuntimeException"));
494 assertEquals( " * @throws java.lang.RuntimeException", sb.toString() );
495
496 sb = new StringBuilder();
497 mojoInstance.writeThrowsTag( sb, javaMethod, javaEntityTags, Collections.singletonList("NumberFormatException"));
498 assertEquals( " * @throws java.lang.NumberFormatException", sb.toString() );
499
500 sb = new StringBuilder();
501 mojoInstance.writeThrowsTag( sb, javaMethod, javaEntityTags, Collections.singletonList("java.lang.Exception"));
502 assertEquals( "", sb.toString() );
503
504 setVariableValueToObject( mojoInstance, "removeUnknownThrows", true );
505 sb = new StringBuilder();
506 mojoInstance.writeThrowsTag( sb, javaMethod, javaEntityTags, Collections.singletonList("com.foo.FatalException"));
507 assertEquals( "", sb.toString() );
508
509 setVariableValueToObject( mojoInstance, "removeUnknownThrows", false );
510 sb = new StringBuilder();
511 mojoInstance.writeThrowsTag( sb, javaMethod, javaEntityTags, Collections.singletonList("com.foo.FatalException"));
512 assertEquals( " * @throws com.foo.FatalException if any.", sb.toString() );
513 }
514
515
516
517
518
519
520
521
522
523
524 private void executeMojoAndTest( File testPomBasedir, String[] clazzToCompare )
525 throws Exception
526 {
527 prepareTestProjects( testPomBasedir.getName() );
528
529 File testPom = new File( testPomBasedir, "pom.xml" );
530 assertTrue( testPom.getAbsolutePath() + " should exist", testPom.exists() );
531
532 FixJavadocMojo mojo = (FixJavadocMojo) lookupMojo( "fix", testPom );
533 assertNotNull( mojo );
534
535 MavenSession session = newMavenSession( mojo.getProject() );
536
537 File globalSettingsFile = new File( getBasedir(), "target/test-classes/unit/settings.xml" );
538 session.getRequest().setGlobalSettingsFile( globalSettingsFile );
539 setVariableValueToObject( mojo, "session", session );
540
541
542 invokeCompileGoal( testPom, globalSettingsFile, mojo.getLog() );
543 assertTrue( new File( testPomBasedir, "target/classes" ).exists() );
544
545 mojo.execute();
546
547 File expectedDir = new File( testPomBasedir, "expected/src/main/java/fix/test" );
548 assertTrue( expectedDir.exists() );
549
550 File generatedDir = new File( testPomBasedir, "target/generated/fix/test" );
551 assertTrue( generatedDir.exists() );
552
553 for (String className : clazzToCompare) {
554 assertEquals(new File(expectedDir, className), new File(generatedDir, className));
555 }
556 }
557
558
559
560
561
562
563
564
565 private void invokeCompileGoal( File testPom, File globalSettingsFile, Log log )
566 throws Exception
567 {
568 List<String> goals = new ArrayList<>();
569 goals.add( "clean" );
570 goals.add( "compile" );
571 File invokerDir = new File( getBasedir(), "target/invoker" );
572 invokerDir.mkdirs();
573 File invokerLogFile = FileUtils.createTempFile( "FixJavadocMojoTest", ".txt", invokerDir );
574
575 Properties properties = new Properties();
576
577 if ( JavaVersion.JAVA_SPECIFICATION_VERSION.isAtLeast( "12" ) )
578 {
579 properties.put( "maven.compiler.source", "1.7" );
580 properties.put( "maven.compiler.target", "1.7" );
581 }
582 else if ( JavaVersion.JAVA_SPECIFICATION_VERSION.isAtLeast( "9" ) )
583 {
584 properties.put( "maven.compiler.source", "1.6" );
585 properties.put( "maven.compiler.target", "1.6" );
586 }
587
588
589 if ( JavaVersion.JAVA_SPECIFICATION_VERSION.isBefore( "8" ) )
590 {
591
592 properties.put( "https.protocols", "TLSv1.2" );
593 }
594
595 JavadocUtil.invokeMaven( log, new File( getBasedir(), "target/local-repo" ), testPom, goals, properties,
596 invokerLogFile, globalSettingsFile );
597 }
598
599
600
601
602
603
604
605
606
607
608 private static void assertEquals( File expected, File actual )
609 throws Exception
610 {
611 assertTrue( " Expected file DNE: " + expected, expected.exists() );
612 String expectedContent = StringUtils.unifyLineSeparators( readFile( expected ) );
613
614 assertTrue( " Actual file DNE: " + actual, actual.exists() );
615 String actualContent = StringUtils.unifyLineSeparators( readFile( actual ) );
616
617 assertEquals( "Expected file: " + expected.getAbsolutePath() + ", actual file: "
618 + actual.getAbsolutePath(), expectedContent, actualContent );
619 }
620
621
622
623
624
625 private static void prepareTestProjects( String testProjectDirName )
626 throws Exception
627 {
628 File testPomBasedir = new File( getBasedir(), "target/test/unit/" + testProjectDirName );
629
630
631 FileUtils
632 .copyDirectoryStructure(
633 new File( getBasedir(), "src/test/resources/unit/" + testProjectDirName ),
634 testPomBasedir );
635 List<String> scmFiles = FileUtils.getDirectoryNames( testPomBasedir, "**/.svn", null, true );
636 for ( String filename : scmFiles )
637 {
638 File dir = new File( filename );
639
640 if ( dir.isDirectory() )
641 {
642 FileUtils.deleteDirectory( dir );
643 }
644 }
645 }
646
647
648
649
650
651
652 private static String readFile( File file )
653 throws Exception
654 {
655 String content = FileUtils.fileRead( file, "UTF-8" );
656 return content;
657 }
658 }