1 package org.apache.maven.shared.dependency.analyzer;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import org.apache.maven.artifact.Artifact;
22 import org.apache.maven.artifact.DefaultArtifact;
23 import org.apache.maven.artifact.handler.ArtifactHandler;
24 import org.apache.maven.artifact.handler.DefaultArtifactHandler;
25 import org.apache.maven.artifact.versioning.VersionRange;
26 import org.apache.maven.project.MavenProject;
27 import org.apache.maven.shared.invoker.InvocationRequest;
28 import org.apache.maven.shared.invoker.InvocationResult;
29 import org.apache.maven.shared.test.plugin.BuildTool;
30 import org.apache.maven.shared.test.plugin.ProjectTool;
31 import org.apache.maven.shared.test.plugin.RepositoryTool;
32 import org.apache.maven.shared.test.plugin.TestToolsException;
33 import org.codehaus.plexus.PlexusTestCase;
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.junit.runner.RunWith;
37 import org.junit.runners.JUnit4;
38
39 import java.io.File;
40 import java.util.Arrays;
41 import java.util.Collections;
42 import java.util.HashSet;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.Properties;
46 import java.util.Set;
47
48
49
50
51
52
53
54 @RunWith( JUnit4.class )
55 public class DefaultProjectDependencyAnalyzerTest
56 extends PlexusTestCase
57 {
58 private BuildTool buildTool;
59
60 private ProjectTool projectTool;
61
62 private ProjectDependencyAnalyzer analyzer;
63
64 private static File localRepo;
65
66
67
68
69 @Before
70 public void setUp()
71 throws Exception
72 {
73 super.setUp();
74
75 buildTool = (BuildTool) lookup( BuildTool.ROLE );
76
77 projectTool = (ProjectTool) lookup( ProjectTool.ROLE );
78
79 if ( localRepo == null )
80 {
81 RepositoryTool repositoryTool = (RepositoryTool) lookup( RepositoryTool.ROLE );
82 localRepo = repositoryTool.findLocalRepositoryDirectory();
83 System.out.println( "Local repository: " + localRepo );
84 }
85
86 analyzer = (ProjectDependencyAnalyzer) lookup( ProjectDependencyAnalyzer.class.getName() );
87 }
88
89 @Test
90 public void testPom()
91 throws TestToolsException, ProjectDependencyAnalyzerException
92 {
93 compileProject( "pom/pom.xml" );
94
95 MavenProject project = getProject( "pom/pom.xml" );
96
97 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
98
99 ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis();
100
101 assertEquals( expectedAnalysis, actualAnalysis );
102 }
103
104 @Test
105 public void testJarWithNoDependencies()
106 throws TestToolsException, ProjectDependencyAnalyzerException
107 {
108 compileProject( "jarWithNoDependencies/pom.xml" );
109
110 MavenProject project = getProject( "jarWithNoDependencies/pom.xml" );
111
112 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
113
114 ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis();
115
116 assertEquals( expectedAnalysis, actualAnalysis );
117 }
118
119 @Test
120 public void testJava8methodRefs()
121 throws TestToolsException, ProjectDependencyAnalyzerException
122 {
123
124 compileProject( "java8methodRefs/pom.xml" );
125
126 MavenProject project = getProject( "java8methodRefs/pom.xml" );
127
128 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
129
130 Artifact project1 = createArtifact( "commons-io", "commons-io", "jar", "2.4", "compile" );
131 Artifact project2 = createArtifact( "commons-lang", "commons-lang", "jar", "2.6", "compile" );
132 Set<Artifact> usedDeclaredArtifacts = new HashSet<>( Arrays.asList( project1, project2 ) );
133
134 ProjectDependencyAnalysis expectedAnalysis =
135 new ProjectDependencyAnalysis( usedDeclaredArtifacts, new HashSet<>(), new HashSet<>(),
136 new HashSet<>() );
137
138 assertEquals( expectedAnalysis, actualAnalysis );
139 }
140
141 @Test
142 public void testInlinedStaticReference()
143 throws TestToolsException, ProjectDependencyAnalyzerException
144 {
145
146 compileProject( "inlinedStaticReference/pom.xml" );
147
148 MavenProject project = getProject( "inlinedStaticReference/pom.xml" );
149
150 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
151
152 Artifact project1 = createArtifact( "dom4j", "dom4j", "jar", "1.6.1", "compile" );
153 Set<Artifact> usedDeclaredArtifacts = Collections.singleton( project1 );
154
155 ProjectDependencyAnalysis expectedAnalysis =
156 new ProjectDependencyAnalysis( usedDeclaredArtifacts, new HashSet<>(), new HashSet<>(),
157 new HashSet<>() );
158
159 assertEquals( expectedAnalysis, actualAnalysis );
160 }
161
162 @Test
163 public void testJarWithCompileDependency()
164 throws TestToolsException, ProjectDependencyAnalyzerException
165 {
166 compileProject( "jarWithCompileDependency/pom.xml" );
167
168 MavenProject project2 = getProject( "jarWithCompileDependency/project2/pom.xml" );
169
170 if ( project2.getBuild().getOutputDirectory().contains( "${" ) )
171 {
172
173 throw new TestToolsException( "output directory was not interpolated: "
174 + project2.getBuild().getOutputDirectory() );
175 }
176
177 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project2 );
178
179 assertTrue( "Incorrectly classified Guava as testonly",
180 actualAnalysis.getTestArtifactsWithNonTestScope().isEmpty() );
181
182 Artifact project1 = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
183 "jarWithCompileDependency1", "jar", "1.0", "compile" );
184 Artifact guava = createArtifact( "com.google.guava", "guava", "jar", "30.1.1-android", "compile" );
185 Set<Artifact> usedDeclaredArtifacts = new HashSet<>( Arrays.asList( project1, guava ) );
186 ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, (Set<Artifact>) null, null,
187 null );
188
189 assertEquals( expectedAnalysis, actualAnalysis );
190 }
191
192 @Test
193 public void testForceDeclaredDependenciesUsage()
194 throws TestToolsException, ProjectDependencyAnalyzerException
195 {
196 compileProject( "jarWithTestDependency/pom.xml" );
197
198 MavenProject project2 = getProject( "jarWithTestDependency/project2/pom.xml" );
199
200 ProjectDependencyAnalysis analysis = analyzer.analyze( project2 );
201
202 try
203 {
204 analysis.forceDeclaredDependenciesUsage( new String[] {
205 "org.apache.maven.shared.dependency-analyzer.tests:jarWithTestDependency1" } );
206 fail( "failure expected since junit dependency is declared-used" );
207 }
208 catch ( ProjectDependencyAnalyzerException pdae )
209 {
210 assertTrue( pdae.getMessage().contains( "Trying to force use of dependencies which are "
211 + "declared but already detected as used: "
212 + "[org.apache.maven.shared.dependency-analyzer.tests:jarWithTestDependency1]" ) );
213 }
214
215 try
216 {
217 analysis.forceDeclaredDependenciesUsage( new String[] { "undefined:undefined" } );
218 fail( "failure expected since undefined dependency is not declared" );
219 }
220 catch ( ProjectDependencyAnalyzerException pdae )
221 {
222 assertTrue( pdae.getMessage().contains( "Trying to force use of dependencies which are "
223 + "not declared: [undefined:undefined]" ) );
224 }
225 }
226
227 @Test
228 public void testJarWithTestDependency()
229 throws TestToolsException, ProjectDependencyAnalyzerException
230 {
231 compileProject( "jarWithTestDependency/pom.xml" );
232
233 MavenProject project2 = getProject( "jarWithTestDependency/project2/pom.xml" );
234
235 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project2 );
236
237 Artifact project1 = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
238 "jarWithTestDependency1", "jar", "1.0", "test" );
239 Artifact junit = createArtifact( "junit", "junit", "jar", "3.8.1", "test" );
240
241 Set<Artifact> usedDeclaredArtifacts = new HashSet<>( Arrays.asList( project1, junit ) );
242 ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, (Set<Artifact>) null, null, null );
243
244 assertEquals( expectedAnalysis, actualAnalysis );
245 }
246
247 @Test
248 public void testJarWithXmlTransitiveDependency()
249 throws TestToolsException, ProjectDependencyAnalyzerException
250 {
251 compileProject( "jarWithXmlTransitiveDependency/pom.xml" );
252
253 MavenProject project = getProject( "jarWithXmlTransitiveDependency/pom.xml" );
254
255 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
256
257 Artifact jdom = createArtifact( "dom4j", "dom4j", "jar", "1.6.1", "compile" );
258 Set<Artifact> usedDeclaredArtifacts = Collections.singleton( jdom );
259
260 ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, (Set<Artifact>) null, null,
261 null );
262
263
264
265 }
266
267 @Test
268 public void testJarWithCompileScopedTestDependency()
269 throws TestToolsException, ProjectDependencyAnalyzerException
270 {
271 compileProject( "jarWithCompileScopedTestDependency/pom.xml" );
272
273 MavenProject project2 = getProject( "jarWithCompileScopedTestDependency/project2/pom.xml" );
274
275 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project2 );
276
277 Artifact artifact1 = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
278 "jarWithCompileScopedTestDependency1", "jar", "1.0", "test" );
279 Artifact junit = createArtifact( "junit", "junit", "jar", "3.8.1", "compile" );
280
281 Set<Artifact> usedDeclaredArtifacts = new HashSet<>( Arrays.asList( artifact1, junit ) );
282 Set<Artifact> nonTestScopedTestArtifacts = Collections.singleton( junit );
283 ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, (Set<Artifact>) null, null,
284 nonTestScopedTestArtifacts );
285
286 assertEquals( expectedAnalysis, actualAnalysis );
287 }
288
289 @Test
290 public void testJarWithRuntimeScopedTestDependency() throws TestToolsException, ProjectDependencyAnalyzerException
291 {
292
293 compileProject( "jarWithRuntimeScopedTestDependency/pom.xml" );
294
295 MavenProject project2 = getProject( "jarWithRuntimeScopedTestDependency/project2/pom.xml" );
296
297 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project2 );
298
299 Artifact artifact1 = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
300 "jarWithRuntimeScopedTestDependency1", "jar", "1.0", "test" );
301 Artifact junit = createArtifact( "junit", "junit", "jar", "3.8.1", "runtime" );
302
303 Set<Artifact> usedDeclaredArtifacts = new HashSet<>( Arrays.asList( artifact1, junit ) );
304 ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, (Set<Artifact>) null, null,
305 null );
306
307 assertEquals( expectedAnalysis, actualAnalysis );
308 }
309
310 @Test
311 public void testMultimoduleProject()
312 throws TestToolsException, ProjectDependencyAnalyzerException
313 {
314 compileProject( "multimoduleProject/pom.xml" );
315
316
317
318 MavenProject project = getProject( "multimoduleProject/module2/pom.xml" );
319 @SuppressWarnings( "unchecked" )
320 Set<Artifact> dependencyArtifacts = project.getArtifacts();
321 for ( Artifact artifact : dependencyArtifacts )
322 {
323 if ( artifact.getArtifactId().equals( "test-module1" ) )
324 {
325 File dir = getTestFile( "target/test-classes/", "multimoduleProject/module1/target/classes/" );
326 artifact.setFile( dir );
327 }
328 }
329
330 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
331
332 Artifact junit = createArtifact( "org.apache.maven.its.dependency", "test-module1", "jar", "1.0", "compile" );
333 Set<Artifact> usedDeclaredArtifacts = Collections.singleton( junit );
334
335 ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( usedDeclaredArtifacts, (Set<Artifact>) null, null,
336 null );
337
338 assertEquals( expectedAnalysis, actualAnalysis );
339 }
340
341 @Test
342 public void testTypeUseAnnotationDependency()
343 throws TestToolsException, ProjectDependencyAnalyzerException
344 {
345 Properties properties = new Properties();
346 properties.put( "maven.compiler.source", "1.8" );
347 properties.put( "maven.compiler.target", "1.8" );
348 compileProject( "typeUseAnnotationDependency/pom.xml", properties);
349
350 MavenProject usage = getProject( "typeUseAnnotationDependency/usage/pom.xml" );
351
352 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( usage );
353
354 Artifact annotation = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
355 "typeUseAnnotationDependencyAnnotation", "jar", "1.0", "compile" );
356 Set<Artifact> usedDeclaredArtifacts = Collections.singleton( annotation );
357 ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis(usedDeclaredArtifacts, (Set<Artifact>) null, null,
358 null );
359
360 assertEquals( expectedAnalysis, actualAnalysis );
361 }
362
363 @Test
364 public void testTypeUseAnnotationDependencyOnLocalVariable()
365 throws TestToolsException, ProjectDependencyAnalyzerException
366 {
367 Properties properties = new Properties();
368 properties.put( "maven.compiler.source", "1.8" );
369 properties.put( "maven.compiler.target", "1.8" );
370 compileProject( "typeUseAnnotationDependency/pom.xml", properties);
371
372 MavenProject usage = getProject( "typeUseAnnotationDependency/usageLocalVar/pom.xml" );
373
374 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( usage );
375
376 Artifact annotation = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
377 "typeUseAnnotationDependencyAnnotation", "jar", "1.0", "compile" );
378 Set<Artifact> usedDeclaredArtifacts = Collections.singleton( annotation );
379 ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis(usedDeclaredArtifacts, (Set<Artifact>) null, null,
380 null);
381
382 assertEquals( expectedAnalysis, actualAnalysis );
383 }
384
385 @Test
386 public void testUnnamedPackageClassReference()
387 throws TestToolsException, ProjectDependencyAnalyzerException
388 {
389
390 compileProject( "unnamedPackageClassReference/pom.xml" );
391
392 MavenProject project = getProject( "unnamedPackageClassReference/pom.xml" );
393
394 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
395
396 Artifact dnsjava = createArtifact( "dnsjava", "dnsjava", "jar", "2.1.8", "compile" );
397
398 Set<Artifact> unusedDeclaredArtifacts = Collections.singleton( dnsjava );
399
400 ProjectDependencyAnalysis expectedAnalysis =
401 new ProjectDependencyAnalysis( new HashSet<>(), new HashSet<>(), unusedDeclaredArtifacts,
402 new HashSet<>() );
403
404 assertEquals( expectedAnalysis, actualAnalysis );
405 }
406
407 @Test
408 public void testJarWithClassInUnnamedPackage()
409 throws TestToolsException, ProjectDependencyAnalyzerException
410 {
411 compileProject( "jarWithClassInUnnamedPackage/pom.xml" );
412
413 MavenProject project2 = getProject( "jarWithClassInUnnamedPackage/project2/pom.xml" );
414
415 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project2 );
416
417 Artifact project1 = createArtifact( "org.apache.maven.shared.dependency-analyzer.tests",
418 "jarWithClassInUnnamedPackage1", "jar", "1.0", "compile" );
419 Set<Artifact> unusedDeclaredArtifacts = Collections.singleton( project1 );
420 ProjectDependencyAnalysis expectedAnalysis = new ProjectDependencyAnalysis( null, null, unusedDeclaredArtifacts );
421
422 assertEquals( expectedAnalysis, actualAnalysis );
423 }
424
425 @Test
426 public void testUsedUndeclaredClassReference()
427 throws TestToolsException, ProjectDependencyAnalyzerException
428 {
429 compileProject( "usedUndeclaredReference/pom.xml" );
430
431 MavenProject project = getProject( "usedUndeclaredReference/pom.xml" );
432
433 ProjectDependencyAnalysis actualAnalysis = analyzer.analyze( project );
434
435 Artifact xmlApis = createArtifact( "xml-apis", "xml-apis", "jar", "1.0.b2", "compile" );
436 Set<Artifact> expectedUsedUndeclaredArtifacts = Collections.singleton( xmlApis );
437
438 assertEquals( expectedUsedUndeclaredArtifacts, actualAnalysis.getUsedUndeclaredArtifacts() );
439
440 Map<Artifact, Set<String>> expectedUsedUndeclaredArtifactsWithClasses =
441 Collections.singletonMap(xmlApis, Collections.singleton("org.apache.xmlcommons.Version") );
442
443 assertEquals( expectedUsedUndeclaredArtifactsWithClasses, actualAnalysis.getUsedUndeclaredArtifactsWithClasses() );
444 }
445
446
447
448 private void compileProject( String pomPath )
449 throws TestToolsException
450 {
451 compileProject( pomPath, new Properties() );
452 }
453
454 private void compileProject(String pomPath, Properties properties) throws TestToolsException {
455 File pom = getTestFile( "target/test-classes/", pomPath );
456 if ( !properties.containsKey( "maven.compiler.source" ) )
457 {
458 properties.put( "maven.compiler.source", "1.8" );
459 properties.put( "maven.compiler.target", "1.8" );
460 }
461
462 String httpsProtocols = System.getProperty( "https.protocols" );
463 if ( httpsProtocols != null )
464 {
465 properties.put( "https.protocols", httpsProtocols );
466 }
467
468 List<String> goals = Arrays.asList( "clean", "install" );
469 File log = new File( pom.getParentFile(), "build.log" );
470
471
472 InvocationRequest request = buildTool.createBasicInvocationRequest( pom, properties, goals, log );
473 request.setLocalRepositoryDirectory( localRepo );
474 InvocationResult result = buildTool.executeMaven( request );
475
476 assertNull( "Error compiling test project", result.getExecutionException() );
477 assertEquals( "Error compiling test project", 0, result.getExitCode() );
478 }
479
480 private MavenProject getProject( String pomPath )
481 throws TestToolsException
482 {
483 File pom = getTestFile( "target/test-classes/", pomPath );
484
485 return projectTool.readProjectWithDependencies( pom );
486 }
487
488 private Artifact createArtifact( String groupId, String artifactId, String type, String version, String scope )
489 {
490 VersionRange versionRange = VersionRange.createFromVersion( version );
491 ArtifactHandler handler = new DefaultArtifactHandler();
492
493 return new DefaultArtifact( groupId, artifactId, versionRange, scope, type, null, handler );
494 }
495 }