View Javadoc
1   package org.apache.maven.repository.legacy.resolver;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.LinkedHashSet;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Set;
31  
32  import javax.inject.Inject;
33  
34  import org.apache.maven.artifact.Artifact;
35  import org.apache.maven.artifact.factory.ArtifactFactory;
36  import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
37  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
38  import org.apache.maven.artifact.metadata.ResolutionGroup;
39  import org.apache.maven.artifact.repository.ArtifactRepository;
40  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
41  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
42  import org.apache.maven.artifact.resolver.CyclicDependencyException;
43  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
44  import org.apache.maven.artifact.resolver.filter.ExclusionSetFilter;
45  import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
46  import org.apache.maven.artifact.versioning.ArtifactVersion;
47  import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
48  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
49  import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
50  import org.apache.maven.artifact.versioning.VersionRange;
51  import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
52  import org.codehaus.plexus.testing.PlexusTest;
53  import org.junit.jupiter.api.BeforeEach;
54  import org.junit.jupiter.api.Disabled;
55  import org.junit.jupiter.api.Test;
56  
57  import static org.junit.jupiter.api.Assertions.assertEquals;
58  import static org.junit.jupiter.api.Assertions.assertNotNull;
59  import static org.junit.jupiter.api.Assertions.assertThrows;
60  import static org.junit.jupiter.api.Assertions.assertTrue;
61  
62  /**
63   * Test the default artifact collector.
64   *
65   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
66   */
67  @PlexusTest
68  public class DefaultArtifactCollectorTest
69  {
70      @Inject
71      private LegacyArtifactCollector artifactCollector;
72  
73      @Inject
74      private ArtifactFactory artifactFactory;
75  
76      private ArtifactSpec projectArtifact;
77  
78      private Source source;
79  
80      private static final String GROUP_ID = "test";
81  
82      @BeforeEach
83      public void setUp()
84          throws Exception
85      {
86          source = new Source();
87  
88          projectArtifact = createArtifactSpec( "project", "1.0", null );
89      }
90  
91      @Test
92      @Disabled("works, but we don't fail on cycles presently")
93      public void testCircularDependencyNotIncludingCurrentProject()
94          throws ArtifactResolutionException, InvalidVersionSpecificationException
95      {
96          ArtifactSpec a = createArtifactSpec( "a", "1.0" );
97          ArtifactSpec b = a.addDependency( "b", "1.0" );
98          b.addDependency( "a", "1.0" );
99          assertThrows(
100                 CyclicDependencyException.class,
101                 () -> collect( a ),
102                 "Should have failed on cyclic dependency not involving project" );
103     }
104 
105     @Test
106     @Disabled("works, but we don't fail on cycles presently")
107     public void testCircularDependencyIncludingCurrentProject()
108         throws ArtifactResolutionException, InvalidVersionSpecificationException
109     {
110         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
111         ArtifactSpec b = a.addDependency( "b", "1.0" );
112         b.addDependency( "project", "1.0" );
113         assertThrows(
114                 CyclicDependencyException.class,
115                 () -> collect( a ),
116                 "Should have failed on cyclic dependency not involving project" );
117     }
118 
119     @Test
120     public void testResolveWithFilter()
121         throws ArtifactResolutionException, InvalidVersionSpecificationException
122     {
123         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
124         ArtifactSpec b = a.addDependency( "b", "1.0" );
125         ArtifactSpec c = a.addDependency( "c", "3.0" );
126 
127         b.addDependency( "c", "2.0" );
128         ArtifactSpec d = b.addDependency( "d", "4.0" );
129 
130         ArtifactResolutionResult res = collect( a );
131         assertEquals( createSet( new Object[] { a.artifact, b.artifact, c.artifact, d.artifact } ), res.getArtifacts(),
132                     "Check artifact list" );
133 
134         ArtifactFilter filter = new ExclusionSetFilter( new String[] { "b" } );
135         res = collect( a, filter );
136         assertEquals( createSet( new Object[] { a.artifact, c.artifact } ), res.getArtifacts(), "Check artifact list" );
137     }
138 
139     @Test
140     public void testResolveCorrectDependenciesWhenDifferentDependenciesOnNearest()
141         throws ArtifactResolutionException, InvalidVersionSpecificationException
142     {
143         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
144         ArtifactSpec b = a.addDependency( "b", "1.0" );
145         ArtifactSpec c2 = b.addDependency( "c", "2.0" );
146         c2.addDependency( "d", "1.0" );
147 
148         ArtifactSpec e = createArtifactSpec( "e", "1.0" );
149         ArtifactSpec c1 = e.addDependency( "c", "1.0" );
150         ArtifactSpec f = c1.addDependency( "f", "1.0" );
151 
152         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, e.artifact } ) );
153         assertEquals( createSet( new Object[] { a.artifact, b.artifact, e.artifact, c1.artifact, f.artifact } ),
154                       res.getArtifacts(), "Check artifact list" );
155         assertEquals( "1.0", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
156     }
157 
158     @Test
159     @Disabled
160     public void testResolveCorrectDependenciesWhenDifferentDependenciesOnNewest()
161         throws ArtifactResolutionException, InvalidVersionSpecificationException
162     {
163         // TODO use newest conflict resolver
164         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
165         ArtifactSpec b = a.addDependency( "b", "1.0" );
166         ArtifactSpec c2 = b.addDependency( "c", "2.0" );
167         ArtifactSpec d = c2.addDependency( "d", "1.0" );
168 
169         ArtifactSpec e = createArtifactSpec( "e", "1.0" );
170         ArtifactSpec c1 = e.addDependency( "c", "1.0" );
171         c1.addDependency( "f", "1.0" );
172 
173         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, e.artifact } ) );
174         assertEquals( createSet( new Object[] { a.artifact, b.artifact, e.artifact, c2.artifact, d.artifact } ), res.getArtifacts(), "Check artifact list" );
175         assertEquals( "2.0", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
176     }
177 
178     @Test
179     @Disabled
180     public void testResolveCorrectDependenciesWhenDifferentDependenciesOnNewestVersionReplaced()
181         throws ArtifactResolutionException, InvalidVersionSpecificationException
182     {
183         // TODO use newest conflict resolver
184         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
185         ArtifactSpec b1 = a.addDependency( "b", "1.0" );
186         ArtifactSpec c = a.addDependency( "c", "1.0" );
187         ArtifactSpec d2 = b1.addDependency( "d", "2.0" );
188         d2.addDependency( "h", "1.0" );
189         ArtifactSpec d1 = c.addDependency( "d", "1.0" );
190         ArtifactSpec b2 = c.addDependency( "b", "2.0" );
191         ArtifactSpec e = b2.addDependency( "e", "1.0" );
192         ArtifactSpec g = d1.addDependency( "g", "1.0" );
193 
194         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact } ) );
195         Object[] artifacts = new Object[] { a.artifact, c.artifact, d1.artifact, b2.artifact, e.artifact, g.artifact };
196         assertEquals( createSet( artifacts ), res.getArtifacts(), "Check artifact list" );
197         assertEquals( "1.0", getArtifact( "d", res.getArtifacts() ).getVersion(), "Check version" );
198         assertEquals( "2.0", getArtifact( "b", res.getArtifacts() ).getVersion(), "Check version" );
199     }
200 
201     @Test
202     public void testResolveNearestNewestIsNearest()
203         throws ArtifactResolutionException, InvalidVersionSpecificationException
204     {
205         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
206         ArtifactSpec b = a.addDependency( "b", "1.0" );
207         ArtifactSpec c = a.addDependency( "c", "3.0" );
208 
209         b.addDependency( "c", "2.0" );
210 
211         ArtifactResolutionResult res = collect( a );
212         assertEquals( createSet( new Object[] { a.artifact, b.artifact, c.artifact } ), res.getArtifacts(), "Check artifact list" );
213         assertEquals( "3.0", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
214     }
215 
216     @Test
217     public void testResolveNearestOldestIsNearest()
218         throws ArtifactResolutionException, InvalidVersionSpecificationException
219     {
220         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
221         ArtifactSpec b = a.addDependency( "b", "1.0" );
222         ArtifactSpec c = a.addDependency( "c", "2.0" );
223 
224         b.addDependency( "c", "3.0" );
225 
226         ArtifactResolutionResult res = collect( a );
227         assertEquals( createSet( new Object[] { a.artifact, b.artifact, c.artifact } ), res.getArtifacts(), "Check artifact list" );
228         assertEquals( "2.0", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
229     }
230 
231     @Test
232     public void testResolveLocalNewestIsLocal()
233         throws ArtifactResolutionException, InvalidVersionSpecificationException
234     {
235         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
236         a.addDependency( "b", "2.0" );
237         ArtifactSpec b = createArtifactSpec( "b", "3.0" );
238 
239         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
240         assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
241         assertEquals( "3.0", getArtifact( "b", res.getArtifacts() ).getVersion(), "Check version" );
242     }
243 
244     @Test
245     public void testResolveLocalOldestIsLocal()
246         throws ArtifactResolutionException, InvalidVersionSpecificationException
247     {
248         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
249         a.addDependency( "b", "3.0" );
250         ArtifactSpec b = createArtifactSpec( "b", "2.0" );
251 
252         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
253         assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
254         assertEquals( "2.0", getArtifact( "b", res.getArtifacts() ).getVersion(), "Check version" );
255     }
256 
257     @Test
258     public void testResolveLocalWithNewerVersionButLesserScope()
259         throws ArtifactResolutionException, InvalidVersionSpecificationException
260     {
261         ArtifactSpec a = createArtifactSpec( "commons-logging", "1.0" );
262         a.addDependency( "junit", "3.7" );
263         ArtifactSpec b = createArtifactSpec( "junit", "3.8.1", Artifact.SCOPE_TEST );
264 
265         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
266         assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
267         assertEquals( "3.8.1", getArtifact( "junit", res.getArtifacts() ).getVersion(), "Check version" );
268         assertEquals( Artifact.SCOPE_TEST, getArtifact( "junit", res.getArtifacts() ).getScope(), "Check artifactScope" );
269     }
270 
271     @Test
272     public void testResolveLocalWithNewerVersionButLesserScopeResolvedFirst()
273         throws ArtifactResolutionException, InvalidVersionSpecificationException
274     {
275         ArtifactSpec b = createArtifactSpec( "junit", "3.8.1", Artifact.SCOPE_TEST );
276         ArtifactSpec a = createArtifactSpec( "commons-logging", "1.0" );
277         a.addDependency( "junit", "3.7" );
278 
279         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
280         assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
281         assertEquals( "3.8.1", getArtifact( "junit", res.getArtifacts() ).getVersion(), "Check version" );
282         assertEquals( Artifact.SCOPE_TEST, getArtifact( "junit", res.getArtifacts() ).getScope(), "Check artifactScope" );
283     }
284 
285     @Test
286     public void testResolveNearestWithRanges()
287         throws ArtifactResolutionException, InvalidVersionSpecificationException
288     {
289         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
290         ArtifactSpec b = a.addDependency( "b", "1.0" );
291         ArtifactSpec c = a.addDependency( "c", "2.0" );
292 
293         b.addDependency( "c", "[1.0,3.0]" );
294 
295         ArtifactResolutionResult res = collect( a );
296         assertEquals( createSet( new Object[] { a.artifact, b.artifact, c.artifact } ), res.getArtifacts(), "Check artifact list" );
297         assertEquals( "2.0", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
298     }
299 
300     @Test
301     public void testResolveRangeWithManagedVersion()
302         throws ArtifactResolutionException, InvalidVersionSpecificationException
303     {
304         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
305         ArtifactSpec b = a.addDependency( "b", "[1.0,3.0]" );
306 
307         ArtifactSpec managedB = createArtifactSpec( "b", "5.0" );
308 
309         ArtifactResolutionResult res = collect( a, managedB.artifact );
310         assertEquals( createSet( new Object[] { a.artifact, managedB.artifact } ), res.getArtifacts(), "Check artifact list" );
311         assertEquals( "5.0", getArtifact( "b", res.getArtifacts() ).getVersion(), "Check version" );
312     }
313 
314     @Test
315     public void testCompatibleRanges()
316         throws ArtifactResolutionException, InvalidVersionSpecificationException
317     {
318         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
319         ArtifactSpec b = a.addDependency( "b", "1.0" );
320         a.addDependency( "c", "[2.0,2.5]" );
321         b.addDependency( "c", "[1.0,3.0]" );
322         ArtifactSpec c = createArtifactSpec( "c", "2.5" );
323 
324         ArtifactResolutionResult res = collect( a );
325 
326         assertEquals( createSet( new Object[] { a.artifact, b.artifact, c.artifact } ), res.getArtifacts(), "Check artifact list" );
327         assertEquals( "2.5", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
328     }
329 
330     @Test
331     public void testIncompatibleRanges()
332         throws ArtifactResolutionException, InvalidVersionSpecificationException
333     {
334         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
335         ArtifactSpec b = a.addDependency( "b", "1.0" );
336         a.addDependency( "c", "[2.4,3.0]" );
337 
338         b.addDependency( "c", "[1.0,2.0]" );
339 
340         ArtifactResolutionResult res = collect( a );
341 
342         assertTrue( res.hasVersionRangeViolations() );
343     }
344 
345     @Test
346     public void testUnboundedRangeWhenVersionUnavailable()
347         throws ArtifactResolutionException, InvalidVersionSpecificationException
348     {
349         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
350         ArtifactSpec b = a.addDependency( "b", "1.0" );
351         a.addDependency( "c", "[2.0,]" );
352         b.addDependency( "c", "[1.0,]" );
353 
354         ArtifactResolutionResult res = collect( a );
355 
356         assertTrue( res.hasVersionRangeViolations() );
357     }
358 
359     @Test
360     public void testUnboundedRangeBelowLastRelease()
361         throws ArtifactResolutionException, InvalidVersionSpecificationException
362     {
363         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
364         createArtifactSpec( "c", "1.5" );
365         ArtifactSpec c = createArtifactSpec( "c", "2.0" );
366         createArtifactSpec( "c", "1.1" );
367         a.addDependency( "c", "[1.0,)" );
368 
369         ArtifactResolutionResult res = collect( a );
370 
371         assertEquals( createSet( new Object[] { a.artifact, c.artifact } ), res.getArtifacts(), "Check artifact list" );
372         assertEquals( "2.0", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
373     }
374 
375     @Test
376     public void testUnboundedRangeAboveLastRelease()
377         throws ArtifactResolutionException, InvalidVersionSpecificationException
378     {
379         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
380         createArtifactSpec( "c", "2.0" );
381         a.addDependency( "c", "[10.0,)" );
382 
383         ArtifactResolutionResult res = collect( a );
384 
385         assertTrue( res.hasVersionRangeViolations() );
386     }
387 
388     @Test
389     public void testResolveManagedVersion()
390         throws ArtifactResolutionException, InvalidVersionSpecificationException
391     {
392         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
393         a.addDependency( "b", "3.0", Artifact.SCOPE_RUNTIME );
394 
395         Artifact managedVersion = createArtifactSpec( "b", "5.0" ).artifact;
396         Artifact modifiedB = createArtifactSpec( "b", "5.0", Artifact.SCOPE_RUNTIME ).artifact;
397 
398         ArtifactResolutionResult res = collect( a, managedVersion );
399         assertEquals( createSet( new Object[] { a.artifact, modifiedB } ), res.getArtifacts(), "Check artifact list" );
400     }
401 
402     @Test
403     public void testCollectChangesVersionOfOriginatingArtifactIfInDependencyManagementHasDifferentVersion()
404         throws ArtifactResolutionException, InvalidVersionSpecificationException
405     {
406         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
407 
408         Artifact artifact = projectArtifact.artifact;
409         Artifact managedVersion = createArtifactSpec( artifact.getArtifactId(), "2.0" ).artifact;
410 
411         ArtifactResolutionResult result = collect( a, managedVersion );
412 
413         assertEquals( "1.0", artifact.getVersion(), "collect has modified version in originating artifact" );
414 
415         Artifact resolvedArtifact = result.getArtifacts().iterator().next();
416 
417         assertEquals( "1.0", resolvedArtifact.getVersion(), "Resolved version don't match original artifact version" );
418     }
419 
420     @Test
421     public void testResolveCompileScopeOverTestScope()
422         throws ArtifactResolutionException, InvalidVersionSpecificationException
423     {
424         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
425         ArtifactSpec c = createArtifactSpec( "c", "3.0", Artifact.SCOPE_TEST );
426 
427         a.addDependency( "c", "2.0", Artifact.SCOPE_COMPILE );
428 
429         Artifact modifiedC = createArtifactSpec( "c", "3.0", Artifact.SCOPE_COMPILE ).artifact;
430 
431         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, c.artifact } ) );
432         assertEquals( createSet( new Object[] { a.artifact, modifiedC } ), res.getArtifacts(), "Check artifact list" );
433         Artifact artifact = getArtifact( "c", res.getArtifacts() );
434         // local wins now, and irrelevant if not local as test/provided aren't transitive
435         // assertEquals( Artifact.SCOPE_COMPILE, artifact.getArtifactScope(), "Check artifactScope" );
436         assertEquals( Artifact.SCOPE_TEST, artifact.getScope(), "Check artifactScope" );
437     }
438 
439     @Test
440     public void testResolveRuntimeScopeOverTestScope()
441         throws ArtifactResolutionException, InvalidVersionSpecificationException
442     {
443         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
444         ArtifactSpec c = createArtifactSpec( "c", "3.0", Artifact.SCOPE_TEST );
445 
446         a.addDependency( "c", "2.0", Artifact.SCOPE_RUNTIME );
447 
448         Artifact modifiedC = createArtifactSpec( "c", "3.0", Artifact.SCOPE_RUNTIME ).artifact;
449 
450         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, c.artifact } ) );
451         assertEquals( createSet( new Object[] { a.artifact, modifiedC } ), res.getArtifacts(), "Check artifact list" );
452         Artifact artifact = getArtifact( "c", res.getArtifacts() );
453         // local wins now, and irrelevant if not local as test/provided aren't transitive
454         // assertEquals( Artifact.SCOPE_RUNTIME, artifact.getArtifactScope(), "Check artifactScope" );
455         assertEquals( Artifact.SCOPE_TEST, artifact.getScope(), "Check artifactScope" );
456     }
457 
458     @Test
459     public void testResolveCompileScopeOverRuntimeScope()
460         throws ArtifactResolutionException, InvalidVersionSpecificationException
461     {
462         ArtifactSpec root = createArtifactSpec( "root", "1.0" );
463         ArtifactSpec a = root.addDependency( "a", "1.0" );
464         root.addDependency( "c", "3.0", Artifact.SCOPE_RUNTIME );
465 
466         a.addDependency( "c", "2.0", Artifact.SCOPE_COMPILE );
467 
468         Artifact modifiedC = createArtifactSpec( "c", "3.0", Artifact.SCOPE_COMPILE ).artifact;
469 
470         ArtifactResolutionResult res = collect( createSet( new Object[] { root.artifact } ) );
471         assertEquals( createSet( new Object[] { a.artifact, root.artifact, modifiedC } ), res.getArtifacts(), "Check artifact list" );
472         Artifact artifact = getArtifact( "c", res.getArtifacts() );
473         assertEquals( Artifact.SCOPE_COMPILE, artifact.getScope(), "Check artifactScope" );
474     }
475 
476     @Test
477     public void testResolveCompileScopeOverProvidedScope()
478         throws ArtifactResolutionException, InvalidVersionSpecificationException
479     {
480         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
481         ArtifactSpec c = createArtifactSpec( "c", "3.0", Artifact.SCOPE_PROVIDED );
482 
483         a.addDependency( "c", "2.0", Artifact.SCOPE_COMPILE );
484 
485         Artifact modifiedC = createArtifactSpec( "c", "3.0", Artifact.SCOPE_COMPILE ).artifact;
486 
487         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, c.artifact } ) );
488         assertEquals( createSet( new Object[] { a.artifact, modifiedC } ), res.getArtifacts(), "Check artifact list" );
489         Artifact artifact = getArtifact( "c", res.getArtifacts() );
490         // local wins now, and irrelevant if not local as test/provided aren't transitive
491         // assertEquals( Artifact.SCOPE_COMPILE, artifact.getArtifactScope(), "Check artifactScope" );
492         assertEquals( Artifact.SCOPE_PROVIDED, artifact.getScope(), "Check artifactScope" );
493     }
494 
495     @Test
496     public void testResolveRuntimeScopeOverProvidedScope()
497         throws ArtifactResolutionException, InvalidVersionSpecificationException
498     {
499         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
500         ArtifactSpec c = createArtifactSpec( "c", "3.0", Artifact.SCOPE_PROVIDED );
501 
502         a.addDependency( "c", "2.0", Artifact.SCOPE_RUNTIME );
503 
504         Artifact modifiedC = createArtifactSpec( "c", "3.0", Artifact.SCOPE_RUNTIME ).artifact;
505 
506         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, c.artifact } ) );
507         assertEquals( createSet( new Object[] { a.artifact, modifiedC } ), res.getArtifacts(), "Check artifact list" );
508         Artifact artifact = getArtifact( "c", res.getArtifacts() );
509         // local wins now, and irrelevant if not local as test/provided aren't transitive
510         // assertEquals( Artifact.SCOPE_RUNTIME, artifact.getArtifactScope(), "Check artifactScope" );
511         assertEquals( Artifact.SCOPE_PROVIDED, artifact.getScope(), "Check artifactScope" );
512     }
513 
514     @Test
515     public void testProvidedScopeNotTransitive()
516         throws ArtifactResolutionException, InvalidVersionSpecificationException
517     {
518         ArtifactSpec a = createArtifactSpec( "a", "1.0", Artifact.SCOPE_PROVIDED );
519         ArtifactSpec b = createArtifactSpec( "b", "1.0" );
520         b.addDependency( "c", "3.0", Artifact.SCOPE_PROVIDED );
521 
522         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
523         assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
524     }
525 
526     @Test
527     public void testOptionalNotTransitive()
528         throws ArtifactResolutionException, InvalidVersionSpecificationException
529     {
530         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
531         ArtifactSpec b = createArtifactSpec( "b", "1.0" );
532         b.addDependency( "c", "3.0", true );
533 
534         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
535         assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
536     }
537 
538     @Test
539     public void testOptionalIncludedAtRoot()
540         throws ArtifactResolutionException, InvalidVersionSpecificationException
541     {
542         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
543 
544         ArtifactSpec b = createArtifactSpec( "b", "1.0", true );
545 
546         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
547         assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
548     }
549 
550     @Test
551     public void testScopeUpdate()
552         throws InvalidVersionSpecificationException, ArtifactResolutionException
553     {
554         /* farthest = compile */
555         checkScopeUpdate( Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE );
556         checkScopeUpdate( Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_COMPILE );
557         checkScopeUpdate( Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_COMPILE );
558         checkScopeUpdate( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_COMPILE );
559         checkScopeUpdate( Artifact.SCOPE_COMPILE, Artifact.SCOPE_TEST, Artifact.SCOPE_COMPILE );
560 
561         /* farthest = provided */
562         checkScopeUpdate( Artifact.SCOPE_PROVIDED, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE );
563         checkScopeUpdate( Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED );
564         checkScopeUpdate( Artifact.SCOPE_PROVIDED, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME );
565         checkScopeUpdate( Artifact.SCOPE_PROVIDED, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM );
566         checkScopeUpdate( Artifact.SCOPE_PROVIDED, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST );
567 
568         /* farthest = runtime */
569         checkScopeUpdate( Artifact.SCOPE_RUNTIME, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE );
570         checkScopeUpdate( Artifact.SCOPE_RUNTIME, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_RUNTIME );
571         checkScopeUpdate( Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME );
572         checkScopeUpdate( Artifact.SCOPE_RUNTIME, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM );
573         checkScopeUpdate( Artifact.SCOPE_RUNTIME, Artifact.SCOPE_TEST, Artifact.SCOPE_RUNTIME );
574 
575         /* farthest = system */
576         checkScopeUpdate( Artifact.SCOPE_SYSTEM, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE );
577         checkScopeUpdate( Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED );
578         checkScopeUpdate( Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME );
579         checkScopeUpdate( Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM );
580         checkScopeUpdate( Artifact.SCOPE_SYSTEM, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST );
581 
582         /* farthest = test */
583         checkScopeUpdate( Artifact.SCOPE_TEST, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE );
584         checkScopeUpdate( Artifact.SCOPE_TEST, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED );
585         checkScopeUpdate( Artifact.SCOPE_TEST, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME );
586         checkScopeUpdate( Artifact.SCOPE_TEST, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM );
587         checkScopeUpdate( Artifact.SCOPE_TEST, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST );
588     }
589 
590     private void checkScopeUpdate( String farthestScope, String nearestScope, String expectedScope )
591         throws ArtifactResolutionException, InvalidVersionSpecificationException
592     {
593         checkScopeUpdateDirect( farthestScope, nearestScope, expectedScope );
594         checkScopeUpdateTransitively( farthestScope, nearestScope, expectedScope );
595     }
596 
597     private void checkScopeUpdateTransitively( String farthestScope, String nearestScope, String expectedScope )
598         throws ArtifactResolutionException, InvalidVersionSpecificationException
599     {
600         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
601         ArtifactSpec b = createArtifactSpec( "b", "1.0", nearestScope );
602         ArtifactSpec c = createArtifactSpec( "c", "1.0" );
603         a.addDependency( c );
604         ArtifactSpec dNearest = createArtifactSpec( "d", "2.0" );
605         b.addDependency( dNearest );
606         ArtifactSpec dFarthest = createArtifactSpec( "d", "3.0", farthestScope );
607         c.addDependency( dFarthest );
608 
609         /* system and provided dependencies are not transitive */
610         if ( !Artifact.SCOPE_SYSTEM.equals( nearestScope ) && !Artifact.SCOPE_PROVIDED.equals( nearestScope ) )
611         {
612             checkScopeUpdate( a, b, expectedScope, "2.0" );
613         }
614     }
615 
616     private void checkScopeUpdateDirect( String farthestScope, String nearestScope, String expectedScope )
617         throws ArtifactResolutionException, InvalidVersionSpecificationException
618     {
619         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
620         ArtifactSpec b = createArtifactSpec( "b", "1.0" );
621         ArtifactSpec c = createArtifactSpec( "c", "1.0" );
622         a.addDependency( c );
623         ArtifactSpec dNearest = createArtifactSpec( "d", "2.0", nearestScope );
624         b.addDependency( dNearest );
625         ArtifactSpec dFarthest = createArtifactSpec( "d", "3.0", farthestScope );
626         c.addDependency( dFarthest );
627 
628         checkScopeUpdate( a, b, expectedScope, "2.0" );
629     }
630 
631     private void checkScopeUpdate( ArtifactSpec a, ArtifactSpec b, String expectedScope, String expectedVersion )
632         throws ArtifactResolutionException, InvalidVersionSpecificationException
633     {
634         ScopeArtifactFilter filter;
635         if ( Artifact.SCOPE_PROVIDED.equals( expectedScope ) )
636         {
637             filter = new ScopeArtifactFilter( Artifact.SCOPE_COMPILE );
638         }
639         else if ( Artifact.SCOPE_SYSTEM.equals( expectedScope ) )
640         {
641             filter = new ScopeArtifactFilter( Artifact.SCOPE_COMPILE );
642         }
643         else
644         {
645             filter = new ScopeArtifactFilter( expectedScope );
646         }
647 
648         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ), filter );
649         Artifact artifact = getArtifact( "d", res.getArtifacts() );
650         assertNotNull( artifact, "MNG-1895 Dependency was not added to resolution" );
651         assertEquals( expectedScope, artifact.getScope(), "Check artifactScope" );
652         assertEquals( expectedVersion, artifact.getVersion(), "Check version" );
653 
654         ArtifactSpec d = createArtifactSpec( "d", "1.0" );
655         res = collect( createSet( new Object[] { a.artifact, b.artifact, d.artifact } ), filter );
656         artifact = getArtifact( "d", res.getArtifacts() );
657         assertNotNull( artifact, "MNG-1895 Dependency was not added to resolution" );
658         assertEquals( d.artifact.getScope(), artifact.getScope(), "Check artifactScope" );
659         assertEquals( "1.0", artifact.getVersion(), "Check version" );
660     }
661 
662     @Test
663     @Disabled
664     public void testOptionalNotTransitiveButVersionIsInfluential()
665         throws ArtifactResolutionException, InvalidVersionSpecificationException
666     {
667         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
668         ArtifactSpec b = createArtifactSpec( "b", "1.0" );
669         b.addDependency( "c", "3.0", true );
670         ArtifactSpec d = a.addDependency( "d", "1.0" );
671         ArtifactSpec e = d.addDependency( "e", "1.0" );
672         e.addDependency( "c", "2.0" );
673 
674         ArtifactSpec c = createArtifactSpec( "c", "3.0" );
675 
676         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
677         assertEquals( createSet( new Object[] { a.artifact, b.artifact, c.artifact, d.artifact, e.artifact } ), res.getArtifacts(), "Check artifact list" );
678         Artifact artifact = getArtifact( "c", res.getArtifacts() );
679         assertEquals( "3.0", artifact.getVersion(), "Check version" );
680     }
681 
682     @Test
683     public void testTestScopeNotTransitive()
684         throws ArtifactResolutionException, InvalidVersionSpecificationException
685     {
686         ArtifactSpec a = createArtifactSpec( "a", "1.0", Artifact.SCOPE_TEST );
687         ArtifactSpec b = createArtifactSpec( "b", "1.0" );
688         b.addDependency( "c", "3.0", Artifact.SCOPE_TEST );
689 
690         ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
691         assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
692     }
693 
694     @Test
695     public void testSnapshotNotIncluded()
696         throws ArtifactResolutionException, InvalidVersionSpecificationException
697     {
698         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
699         a.addDependency( "b", "[1.0,)" );
700         createArtifactSpec( "b", "1.0-SNAPSHOT" );
701 
702         ArtifactResolutionResult res = collect( a );
703 
704         assertTrue( res.hasVersionRangeViolations() );
705 
706         /*
707          * try { ArtifactResolutionResult res = collect( a ); fail( "Expected b not to resolve: " + res ); } catch (
708          * OverConstrainedVersionException e ) { assertTrue( e.getMessage().indexOf( "[1.0-SNAPSHOT]" ) <
709          * e.getMessage().indexOf( "[1.0,)" ) ); }
710          */
711     }
712 
713     @Test
714     @Disabled("that one does not work")
715     public void testOverConstrainedVersionException()
716         throws ArtifactResolutionException, InvalidVersionSpecificationException
717     {
718         ArtifactSpec a = createArtifactSpec( "a", "1.0" );
719         a.addDependency( "b", "[1.0, 2.0)" );
720         a.addDependency( "c", "[3.3.0,4.0.0)" );
721 
722         ArtifactSpec b = createArtifactSpec( "b", "1.0.0" );
723         b.addDependency( "c", "3.3.0-v3346" );
724 
725         ArtifactSpec c = createArtifactSpec( "c", "3.2.1-v3235e" );
726 
727         OverConstrainedVersionException e = assertThrows(
728                 OverConstrainedVersionException.class,
729                 () -> collect( createSet( new Object[] { a.artifact } ) ) );
730         assertTrue( e.getMessage().contains( "[3.2.1-v3235e, 3.3.0-v3346]" ), "Versions unordered" );
731         assertTrue( e.getMessage().contains( "Path to dependency:" ), "DependencyTrail unresolved" );
732     }
733 
734     private Artifact getArtifact( String id, Set artifacts )
735     {
736         for ( Object artifact : artifacts )
737         {
738             Artifact a = (Artifact) artifact;
739             if ( a.getArtifactId().equals( id ) && a.getGroupId().equals( GROUP_ID ) )
740             {
741                 return a;
742             }
743         }
744         return null;
745     }
746 
747     private ArtifactResolutionResult collect( Set<Artifact> artifacts )
748         throws ArtifactResolutionException
749     {
750         return collect( artifacts, null );
751     }
752 
753     private ArtifactResolutionResult collect( Set<Artifact> artifacts, ArtifactFilter filter )
754         throws ArtifactResolutionException
755     {
756         return artifactCollector.collect( artifacts, projectArtifact.artifact, null, null, null, source, filter,
757                                           Collections.emptyList(), null );
758     }
759 
760     private ArtifactResolutionResult collect( ArtifactSpec a )
761         throws ArtifactResolutionException
762     {
763         return artifactCollector.collect( Collections.singleton( a.artifact ), projectArtifact.artifact, null, null,
764                                           null, source, null, Collections.emptyList(), null );
765     }
766 
767     private ArtifactResolutionResult collect( ArtifactSpec a, ArtifactFilter filter )
768         throws ArtifactResolutionException
769     {
770         return artifactCollector.collect( Collections.singleton( a.artifact ), projectArtifact.artifact, null, null,
771                                           null, source, filter, Collections.emptyList(), null );
772     }
773 
774     private ArtifactResolutionResult collect( ArtifactSpec a, Artifact managedVersion )
775         throws ArtifactResolutionException
776     {
777         Map<String, Artifact> managedVersions = Collections.singletonMap( managedVersion.getDependencyConflictId(), managedVersion );
778         return artifactCollector.collect( Collections.singleton( a.artifact ), projectArtifact.artifact,
779                                           managedVersions, null, null, source, null, Collections.emptyList(), null );
780     }
781 
782     private ArtifactSpec createArtifactSpec( String id, String version )
783         throws InvalidVersionSpecificationException
784     {
785         return createArtifactSpec( id, version, Artifact.SCOPE_COMPILE );
786     }
787 
788     private ArtifactSpec createArtifactSpec( String id, String version, boolean optional )
789         throws InvalidVersionSpecificationException
790     {
791         return createArtifactSpec( id, version, Artifact.SCOPE_COMPILE, null, optional );
792     }
793 
794     private ArtifactSpec createArtifactSpec( String id, String version, String scope )
795         throws InvalidVersionSpecificationException
796     {
797         return createArtifactSpec( id, version, scope, null, false );
798     }
799 
800     private ArtifactSpec createArtifactSpec( String id, String version, String scope, String inheritedScope,
801                                              boolean optional )
802         throws InvalidVersionSpecificationException
803     {
804         VersionRange versionRange = VersionRange.createFromVersionSpec( version );
805         Artifact artifact =
806             artifactFactory.createDependencyArtifact( GROUP_ID, id, versionRange, "jar", null, scope, inheritedScope,
807                                                       optional );
808         ArtifactSpec spec = null;
809         if ( artifact != null )
810         {
811             spec = new ArtifactSpec();
812             spec.artifact = artifact;
813             source.addArtifact( spec );
814         }
815         return spec;
816     }
817 
818     @SuppressWarnings( "unchecked" )
819     private static Set<Artifact> createSet( Object[] x )
820     {
821         return new LinkedHashSet( Arrays.asList( x ) );
822     }
823 
824     private class ArtifactSpec
825     {
826         private Artifact artifact;
827 
828         private Set<Artifact> dependencies = new HashSet<>();
829 
830         public ArtifactSpec addDependency( String id, String version )
831             throws InvalidVersionSpecificationException
832         {
833             return addDependency( id, version, Artifact.SCOPE_COMPILE );
834         }
835 
836         public ArtifactSpec addDependency( String id, String version, String scope )
837             throws InvalidVersionSpecificationException
838         {
839             return addDependency( id, version, scope, false );
840         }
841 
842         private ArtifactSpec addDependency( ArtifactSpec dep )
843             throws InvalidVersionSpecificationException
844         {
845             if ( dep != null )
846             {
847                 dependencies.add( dep.artifact );
848             }
849             return dep;
850         }
851 
852         private ArtifactSpec addDependency( String id, String version, String scope, boolean optional )
853             throws InvalidVersionSpecificationException
854         {
855             ArtifactSpec dep = createArtifactSpec( id, version, scope, artifact.getScope(), optional );
856             return addDependency( dep );
857         }
858 
859         public ArtifactSpec addDependency( String id, String version, boolean optional )
860             throws InvalidVersionSpecificationException
861         {
862             return addDependency( id, version, Artifact.SCOPE_COMPILE, optional );
863         }
864     }
865 
866     private class Source
867         implements ArtifactMetadataSource
868     {
869         private Map<String, ArtifactSpec> artifacts = new HashMap<>();
870 
871         private Map<String, List<ArtifactVersion>> versions = new HashMap<>();
872 
873         public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
874                                          List<ArtifactRepository> remoteRepositories )
875             throws ArtifactMetadataRetrievalException
876         {
877             String key = getKey( artifact );
878 
879             ArtifactSpec a = (ArtifactSpec) artifacts.get( key );
880             try
881             {
882                 return new ResolutionGroup( artifact, createArtifacts( artifactFactory, a.dependencies,
883                                                                        artifact.getScope(),
884                                                                        artifact.getDependencyFilter() ),
885                                             Collections.emptyList() );
886             }
887             catch ( InvalidVersionSpecificationException e )
888             {
889                 throw new ArtifactMetadataRetrievalException( "Invalid version creating artifacts", e, artifact );
890             }
891         }
892 
893         private String getKey( Artifact artifact )
894         {
895             return artifact.getDependencyConflictId();
896         }
897 
898         private Set<Artifact> createArtifacts( ArtifactFactory artifactFactory, Set<Artifact> dependencies, String inheritedScope,
899                                      ArtifactFilter dependencyFilter )
900             throws InvalidVersionSpecificationException
901         {
902             Set<Artifact> projectArtifacts = new HashSet<>();
903 
904             for ( Artifact d : dependencies )
905             {
906                 VersionRange versionRange;
907                 if ( d.getVersionRange() != null )
908                 {
909                     versionRange = d.getVersionRange();
910                 }
911                 else
912                 {
913                     versionRange = VersionRange.createFromVersionSpec( d.getVersion() );
914                 }
915                 Artifact artifact;
916                 if ( d.getScope().equals( Artifact.SCOPE_TEST ) || d.getScope().equals( Artifact.SCOPE_PROVIDED ) )
917                 {
918                     /* don't call createDependencyArtifact as it'll ignore test and provided scopes */
919                     artifact =
920                         artifactFactory.createArtifact( d.getGroupId(), d.getArtifactId(), d.getVersion(), d.getScope(),
921                                                         d.getType() );
922                 }
923                 else
924                 {
925                     artifact =
926                         artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(), versionRange,
927                                                                   d.getType(), d.getClassifier(), d.getScope(),
928                                                                   inheritedScope, d.isOptional() );
929                 }
930 
931                 if ( artifact != null && ( dependencyFilter == null || dependencyFilter.include( artifact ) ) )
932                 {
933                     artifact.setDependencyFilter( dependencyFilter );
934 
935                     projectArtifacts.add( artifact );
936                 }
937             }
938 
939             return projectArtifacts;
940         }
941 
942         public void addArtifact( ArtifactSpec spec )
943         {
944             artifacts.put( getKey( spec.artifact ), spec );
945 
946             String key = spec.artifact.getDependencyConflictId();
947             List<ArtifactVersion> artifactVersions = versions.computeIfAbsent( key, k -> new ArrayList<>() );
948             if ( spec.artifact.getVersion() != null )
949             {
950                 artifactVersions.add( new DefaultArtifactVersion( spec.artifact.getVersion() ) );
951             }
952         }
953 
954         public List<ArtifactVersion> retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository,
955                                                                 List<ArtifactRepository> remoteRepositories )
956             throws ArtifactMetadataRetrievalException
957         {
958             return retrieveAvailableVersions( artifact );
959         }
960 
961         public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository(
962                                                                                         Artifact artifact,
963                                                                                         ArtifactRepository localRepository,
964                                                                                         ArtifactRepository remoteRepository )
965             throws ArtifactMetadataRetrievalException
966         {
967             return retrieveAvailableVersions( artifact );
968         }
969 
970         private List<ArtifactVersion> retrieveAvailableVersions( Artifact artifact )
971         {
972             List<ArtifactVersion> artifactVersions = versions.get( artifact.getDependencyConflictId() );
973             if ( artifactVersions == null )
974             {
975                 artifactVersions = Collections.emptyList();
976             }
977             return artifactVersions;
978         }
979 
980         public ResolutionGroup retrieve( MetadataResolutionRequest request )
981             throws ArtifactMetadataRetrievalException
982         {
983             return retrieve( request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories() );
984         }
985 
986         public List<ArtifactVersion> retrieveAvailableVersions( MetadataResolutionRequest request )
987             throws ArtifactMetadataRetrievalException
988         {
989             return retrieveAvailableVersions( request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories() );
990         }
991     }
992 }