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