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  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      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      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     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     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     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     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     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     void testResolveNearestNewestIsNearest() throws ArtifactResolutionException, InvalidVersionSpecificationException {
199         ArtifactSpec a = createArtifactSpec("a", "1.0");
200         ArtifactSpec b = a.addDependency("b", "1.0");
201         ArtifactSpec c = a.addDependency("c", "3.0");
202 
203         b.addDependency("c", "2.0");
204 
205         ArtifactResolutionResult res = collect(a);
206         assertEquals(
207                 createSet(new Object[] {a.artifact, b.artifact, c.artifact}),
208                 res.getArtifacts(),
209                 "Check artifact list");
210         assertEquals("3.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
211     }
212 
213     @Test
214     void testResolveNearestOldestIsNearest() throws ArtifactResolutionException, InvalidVersionSpecificationException {
215         ArtifactSpec a = createArtifactSpec("a", "1.0");
216         ArtifactSpec b = a.addDependency("b", "1.0");
217         ArtifactSpec c = a.addDependency("c", "2.0");
218 
219         b.addDependency("c", "3.0");
220 
221         ArtifactResolutionResult res = collect(a);
222         assertEquals(
223                 createSet(new Object[] {a.artifact, b.artifact, c.artifact}),
224                 res.getArtifacts(),
225                 "Check artifact list");
226         assertEquals("2.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
227     }
228 
229     @Test
230     void testResolveLocalNewestIsLocal() throws ArtifactResolutionException, InvalidVersionSpecificationException {
231         ArtifactSpec a = createArtifactSpec("a", "1.0");
232         a.addDependency("b", "2.0");
233         ArtifactSpec b = createArtifactSpec("b", "3.0");
234 
235         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
236         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
237         assertEquals("3.0", getArtifact("b", res.getArtifacts()).getVersion(), "Check version");
238     }
239 
240     @Test
241     void testResolveLocalOldestIsLocal() throws ArtifactResolutionException, InvalidVersionSpecificationException {
242         ArtifactSpec a = createArtifactSpec("a", "1.0");
243         a.addDependency("b", "3.0");
244         ArtifactSpec b = createArtifactSpec("b", "2.0");
245 
246         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
247         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
248         assertEquals("2.0", getArtifact("b", res.getArtifacts()).getVersion(), "Check version");
249     }
250 
251     @Test
252     void testResolveLocalWithNewerVersionButLesserScope()
253             throws ArtifactResolutionException, InvalidVersionSpecificationException {
254         ArtifactSpec a = createArtifactSpec("commons-logging", "1.0");
255         a.addDependency("junit", "3.7");
256         ArtifactSpec b = createArtifactSpec("junit", "3.8.1", Artifact.SCOPE_TEST);
257 
258         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
259         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
260         assertEquals("3.8.1", getArtifact("junit", res.getArtifacts()).getVersion(), "Check version");
261         assertEquals(
262                 Artifact.SCOPE_TEST, getArtifact("junit", res.getArtifacts()).getScope(), "Check artifactScope");
263     }
264 
265     @Test
266     void testResolveLocalWithNewerVersionButLesserScopeResolvedFirst()
267             throws ArtifactResolutionException, InvalidVersionSpecificationException {
268         ArtifactSpec b = createArtifactSpec("junit", "3.8.1", Artifact.SCOPE_TEST);
269         ArtifactSpec a = createArtifactSpec("commons-logging", "1.0");
270         a.addDependency("junit", "3.7");
271 
272         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
273         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
274         assertEquals("3.8.1", getArtifact("junit", res.getArtifacts()).getVersion(), "Check version");
275         assertEquals(
276                 Artifact.SCOPE_TEST, getArtifact("junit", res.getArtifacts()).getScope(), "Check artifactScope");
277     }
278 
279     @Test
280     void testResolveNearestWithRanges() throws ArtifactResolutionException, InvalidVersionSpecificationException {
281         ArtifactSpec a = createArtifactSpec("a", "1.0");
282         ArtifactSpec b = a.addDependency("b", "1.0");
283         ArtifactSpec c = a.addDependency("c", "2.0");
284 
285         b.addDependency("c", "[1.0,3.0]");
286 
287         ArtifactResolutionResult res = collect(a);
288         assertEquals(
289                 createSet(new Object[] {a.artifact, b.artifact, c.artifact}),
290                 res.getArtifacts(),
291                 "Check artifact list");
292         assertEquals("2.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
293     }
294 
295     @Test
296     void testResolveRangeWithManagedVersion() throws ArtifactResolutionException, InvalidVersionSpecificationException {
297         ArtifactSpec a = createArtifactSpec("a", "1.0");
298         ArtifactSpec b = a.addDependency("b", "[1.0,3.0]");
299 
300         ArtifactSpec managedB = createArtifactSpec("b", "5.0");
301 
302         ArtifactResolutionResult res = collect(a, managedB.artifact);
303         assertEquals(
304                 createSet(new Object[] {a.artifact, managedB.artifact}), res.getArtifacts(), "Check artifact list");
305         assertEquals("5.0", getArtifact("b", res.getArtifacts()).getVersion(), "Check version");
306     }
307 
308     @Test
309     void testCompatibleRanges() throws ArtifactResolutionException, InvalidVersionSpecificationException {
310         ArtifactSpec a = createArtifactSpec("a", "1.0");
311         ArtifactSpec b = a.addDependency("b", "1.0");
312         a.addDependency("c", "[2.0,2.5]");
313         b.addDependency("c", "[1.0,3.0]");
314         ArtifactSpec c = createArtifactSpec("c", "2.5");
315 
316         ArtifactResolutionResult res = collect(a);
317 
318         assertEquals(
319                 createSet(new Object[] {a.artifact, b.artifact, c.artifact}),
320                 res.getArtifacts(),
321                 "Check artifact list");
322         assertEquals("2.5", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
323     }
324 
325     @Test
326     void testIncompatibleRanges() throws ArtifactResolutionException, InvalidVersionSpecificationException {
327         ArtifactSpec a = createArtifactSpec("a", "1.0");
328         ArtifactSpec b = a.addDependency("b", "1.0");
329         a.addDependency("c", "[2.4,3.0]");
330 
331         b.addDependency("c", "[1.0,2.0]");
332 
333         ArtifactResolutionResult res = collect(a);
334 
335         assertTrue(res.hasVersionRangeViolations());
336     }
337 
338     @Test
339     void testUnboundedRangeWhenVersionUnavailable()
340             throws ArtifactResolutionException, InvalidVersionSpecificationException {
341         ArtifactSpec a = createArtifactSpec("a", "1.0");
342         ArtifactSpec b = a.addDependency("b", "1.0");
343         a.addDependency("c", "[2.0,]");
344         b.addDependency("c", "[1.0,]");
345 
346         ArtifactResolutionResult res = collect(a);
347 
348         assertTrue(res.hasVersionRangeViolations());
349     }
350 
351     @Test
352     void testUnboundedRangeBelowLastRelease() throws ArtifactResolutionException, InvalidVersionSpecificationException {
353         ArtifactSpec a = createArtifactSpec("a", "1.0");
354         createArtifactSpec("c", "1.5");
355         ArtifactSpec c = createArtifactSpec("c", "2.0");
356         createArtifactSpec("c", "1.1");
357         a.addDependency("c", "[1.0,)");
358 
359         ArtifactResolutionResult res = collect(a);
360 
361         assertEquals(createSet(new Object[] {a.artifact, c.artifact}), res.getArtifacts(), "Check artifact list");
362         assertEquals("2.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
363     }
364 
365     @Test
366     void testUnboundedRangeAboveLastRelease() throws ArtifactResolutionException, InvalidVersionSpecificationException {
367         ArtifactSpec a = createArtifactSpec("a", "1.0");
368         createArtifactSpec("c", "2.0");
369         a.addDependency("c", "[10.0,)");
370 
371         ArtifactResolutionResult res = collect(a);
372 
373         assertTrue(res.hasVersionRangeViolations());
374     }
375 
376     @Test
377     void testResolveManagedVersion() throws ArtifactResolutionException, InvalidVersionSpecificationException {
378         ArtifactSpec a = createArtifactSpec("a", "1.0");
379         a.addDependency("b", "3.0", Artifact.SCOPE_RUNTIME);
380 
381         Artifact managedVersion = createArtifactSpec("b", "5.0").artifact;
382         Artifact modifiedB = createArtifactSpec("b", "5.0", Artifact.SCOPE_RUNTIME).artifact;
383 
384         ArtifactResolutionResult res = collect(a, managedVersion);
385         assertEquals(createSet(new Object[] {a.artifact, modifiedB}), res.getArtifacts(), "Check artifact list");
386     }
387 
388     @Test
389     void testCollectChangesVersionOfOriginatingArtifactIfInDependencyManagementHasDifferentVersion()
390             throws ArtifactResolutionException, InvalidVersionSpecificationException {
391         ArtifactSpec a = createArtifactSpec("a", "1.0");
392 
393         Artifact artifact = projectArtifact.artifact;
394         Artifact managedVersion = createArtifactSpec(artifact.getArtifactId(), "2.0").artifact;
395 
396         ArtifactResolutionResult result = collect(a, managedVersion);
397 
398         assertEquals("1.0", artifact.getVersion(), "collect has modified version in originating artifact");
399 
400         Artifact resolvedArtifact = result.getArtifacts().iterator().next();
401 
402         assertEquals("1.0", resolvedArtifact.getVersion(), "Resolved version don't match original artifact version");
403     }
404 
405     @Test
406     void testResolveCompileScopeOverTestScope()
407             throws ArtifactResolutionException, InvalidVersionSpecificationException {
408         ArtifactSpec a = createArtifactSpec("a", "1.0");
409         ArtifactSpec c = createArtifactSpec("c", "3.0", Artifact.SCOPE_TEST);
410 
411         a.addDependency("c", "2.0", Artifact.SCOPE_COMPILE);
412 
413         Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_COMPILE).artifact;
414 
415         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, c.artifact}));
416         assertEquals(createSet(new Object[] {a.artifact, modifiedC}), res.getArtifacts(), "Check artifact list");
417         Artifact artifact = getArtifact("c", res.getArtifacts());
418         // local wins now, and irrelevant if not local as test/provided aren't transitive
419         // assertEquals( Artifact.SCOPE_COMPILE, artifact.getArtifactScope(), "Check artifactScope" );
420         assertEquals(Artifact.SCOPE_TEST, artifact.getScope(), "Check artifactScope");
421     }
422 
423     @Test
424     void testResolveRuntimeScopeOverTestScope()
425             throws ArtifactResolutionException, InvalidVersionSpecificationException {
426         ArtifactSpec a = createArtifactSpec("a", "1.0");
427         ArtifactSpec c = createArtifactSpec("c", "3.0", Artifact.SCOPE_TEST);
428 
429         a.addDependency("c", "2.0", Artifact.SCOPE_RUNTIME);
430 
431         Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_RUNTIME).artifact;
432 
433         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, c.artifact}));
434         assertEquals(createSet(new Object[] {a.artifact, modifiedC}), res.getArtifacts(), "Check artifact list");
435         Artifact artifact = getArtifact("c", res.getArtifacts());
436         // local wins now, and irrelevant if not local as test/provided aren't transitive
437         // assertEquals( Artifact.SCOPE_RUNTIME, artifact.getArtifactScope(), "Check artifactScope" );
438         assertEquals(Artifact.SCOPE_TEST, artifact.getScope(), "Check artifactScope");
439     }
440 
441     @Test
442     void testResolveCompileScopeOverRuntimeScope()
443             throws ArtifactResolutionException, InvalidVersionSpecificationException {
444         ArtifactSpec root = createArtifactSpec("root", "1.0");
445         ArtifactSpec a = root.addDependency("a", "1.0");
446         root.addDependency("c", "3.0", Artifact.SCOPE_RUNTIME);
447 
448         a.addDependency("c", "2.0", Artifact.SCOPE_COMPILE);
449 
450         Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_COMPILE).artifact;
451 
452         ArtifactResolutionResult res = collect(createSet(new Object[] {root.artifact}));
453         assertEquals(
454                 createSet(new Object[] {a.artifact, root.artifact, modifiedC}),
455                 res.getArtifacts(),
456                 "Check artifact list");
457         Artifact artifact = getArtifact("c", res.getArtifacts());
458         assertEquals(Artifact.SCOPE_COMPILE, artifact.getScope(), "Check artifactScope");
459     }
460 
461     @Test
462     void testResolveCompileScopeOverProvidedScope()
463             throws ArtifactResolutionException, InvalidVersionSpecificationException {
464         ArtifactSpec a = createArtifactSpec("a", "1.0");
465         ArtifactSpec c = createArtifactSpec("c", "3.0", Artifact.SCOPE_PROVIDED);
466 
467         a.addDependency("c", "2.0", Artifact.SCOPE_COMPILE);
468 
469         Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_COMPILE).artifact;
470 
471         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, c.artifact}));
472         assertEquals(createSet(new Object[] {a.artifact, modifiedC}), res.getArtifacts(), "Check artifact list");
473         Artifact artifact = getArtifact("c", res.getArtifacts());
474         // local wins now, and irrelevant if not local as test/provided aren't transitive
475         // assertEquals( Artifact.SCOPE_COMPILE, artifact.getArtifactScope(), "Check artifactScope" );
476         assertEquals(Artifact.SCOPE_PROVIDED, artifact.getScope(), "Check artifactScope");
477     }
478 
479     @Test
480     void testResolveRuntimeScopeOverProvidedScope()
481             throws ArtifactResolutionException, InvalidVersionSpecificationException {
482         ArtifactSpec a = createArtifactSpec("a", "1.0");
483         ArtifactSpec c = createArtifactSpec("c", "3.0", Artifact.SCOPE_PROVIDED);
484 
485         a.addDependency("c", "2.0", Artifact.SCOPE_RUNTIME);
486 
487         Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_RUNTIME).artifact;
488 
489         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, c.artifact}));
490         assertEquals(createSet(new Object[] {a.artifact, modifiedC}), res.getArtifacts(), "Check artifact list");
491         Artifact artifact = getArtifact("c", res.getArtifacts());
492         // local wins now, and irrelevant if not local as test/provided aren't transitive
493         // assertEquals( Artifact.SCOPE_RUNTIME, artifact.getArtifactScope(), "Check artifactScope" );
494         assertEquals(Artifact.SCOPE_PROVIDED, artifact.getScope(), "Check artifactScope");
495     }
496 
497     @Test
498     void testProvidedScopeNotTransitive() throws ArtifactResolutionException, InvalidVersionSpecificationException {
499         ArtifactSpec a = createArtifactSpec("a", "1.0", Artifact.SCOPE_PROVIDED);
500         ArtifactSpec b = createArtifactSpec("b", "1.0");
501         b.addDependency("c", "3.0", Artifact.SCOPE_PROVIDED);
502 
503         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
504         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
505     }
506 
507     @Test
508     void testOptionalNotTransitive() throws ArtifactResolutionException, InvalidVersionSpecificationException {
509         ArtifactSpec a = createArtifactSpec("a", "1.0");
510         ArtifactSpec b = createArtifactSpec("b", "1.0");
511         b.addDependency("c", "3.0", true);
512 
513         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
514         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
515     }
516 
517     @Test
518     void testOptionalIncludedAtRoot() throws ArtifactResolutionException, InvalidVersionSpecificationException {
519         ArtifactSpec a = createArtifactSpec("a", "1.0");
520 
521         ArtifactSpec b = createArtifactSpec("b", "1.0", true);
522 
523         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
524         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
525     }
526 
527     @Test
528     void testScopeUpdate() throws InvalidVersionSpecificationException, ArtifactResolutionException {
529         /* farthest = compile */
530         checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
531         checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_COMPILE);
532         checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_COMPILE);
533         checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_COMPILE);
534         checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_TEST, Artifact.SCOPE_COMPILE);
535 
536         /* farthest = provided */
537         checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
538         checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED);
539         checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME);
540         checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM);
541         checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST);
542 
543         /* farthest = runtime */
544         checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
545         checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_RUNTIME);
546         checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME);
547         checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM);
548         checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_TEST, Artifact.SCOPE_RUNTIME);
549 
550         /* farthest = system */
551         checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
552         checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED);
553         checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME);
554         checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM);
555         checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST);
556 
557         /* farthest = test */
558         checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
559         checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED);
560         checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME);
561         checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM);
562         checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST);
563     }
564 
565     private void checkScopeUpdate(String farthestScope, String nearestScope, String expectedScope)
566             throws ArtifactResolutionException, InvalidVersionSpecificationException {
567         checkScopeUpdateDirect(farthestScope, nearestScope, expectedScope);
568         checkScopeUpdateTransitively(farthestScope, nearestScope, expectedScope);
569     }
570 
571     private void checkScopeUpdateTransitively(String farthestScope, String nearestScope, String expectedScope)
572             throws ArtifactResolutionException, InvalidVersionSpecificationException {
573         ArtifactSpec a = createArtifactSpec("a", "1.0");
574         ArtifactSpec b = createArtifactSpec("b", "1.0", nearestScope);
575         ArtifactSpec c = createArtifactSpec("c", "1.0");
576         a.addDependency(c);
577         ArtifactSpec dNearest = createArtifactSpec("d", "2.0");
578         b.addDependency(dNearest);
579         ArtifactSpec dFarthest = createArtifactSpec("d", "3.0", farthestScope);
580         c.addDependency(dFarthest);
581 
582         /* system and provided dependencies are not transitive */
583         if (!Artifact.SCOPE_SYSTEM.equals(nearestScope) && !Artifact.SCOPE_PROVIDED.equals(nearestScope)) {
584             checkScopeUpdate(a, b, expectedScope, "2.0");
585         }
586     }
587 
588     private void checkScopeUpdateDirect(String farthestScope, String nearestScope, String expectedScope)
589             throws ArtifactResolutionException, InvalidVersionSpecificationException {
590         ArtifactSpec a = createArtifactSpec("a", "1.0");
591         ArtifactSpec b = createArtifactSpec("b", "1.0");
592         ArtifactSpec c = createArtifactSpec("c", "1.0");
593         a.addDependency(c);
594         ArtifactSpec dNearest = createArtifactSpec("d", "2.0", nearestScope);
595         b.addDependency(dNearest);
596         ArtifactSpec dFarthest = createArtifactSpec("d", "3.0", farthestScope);
597         c.addDependency(dFarthest);
598 
599         checkScopeUpdate(a, b, expectedScope, "2.0");
600     }
601 
602     private void checkScopeUpdate(ArtifactSpec a, ArtifactSpec b, String expectedScope, String expectedVersion)
603             throws ArtifactResolutionException, InvalidVersionSpecificationException {
604         ScopeArtifactFilter filter;
605         if (Artifact.SCOPE_PROVIDED.equals(expectedScope)) {
606             filter = new ScopeArtifactFilter(Artifact.SCOPE_COMPILE);
607         } else if (Artifact.SCOPE_SYSTEM.equals(expectedScope)) {
608             filter = new ScopeArtifactFilter(Artifact.SCOPE_COMPILE);
609         } else {
610             filter = new ScopeArtifactFilter(expectedScope);
611         }
612 
613         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}), filter);
614         Artifact artifact = getArtifact("d", res.getArtifacts());
615         assertNotNull(artifact, "MNG-1895 Dependency was not added to resolution");
616         assertEquals(expectedScope, artifact.getScope(), "Check artifactScope");
617         assertEquals(expectedVersion, artifact.getVersion(), "Check version");
618 
619         ArtifactSpec d = createArtifactSpec("d", "1.0");
620         res = collect(createSet(new Object[] {a.artifact, b.artifact, d.artifact}), filter);
621         artifact = getArtifact("d", res.getArtifacts());
622         assertNotNull(artifact, "MNG-1895 Dependency was not added to resolution");
623         assertEquals(d.artifact.getScope(), artifact.getScope(), "Check artifactScope");
624         assertEquals("1.0", artifact.getVersion(), "Check version");
625     }
626 
627     @Test
628     @Disabled
629     void testOptionalNotTransitiveButVersionIsInfluential()
630             throws ArtifactResolutionException, InvalidVersionSpecificationException {
631         ArtifactSpec a = createArtifactSpec("a", "1.0");
632         ArtifactSpec b = createArtifactSpec("b", "1.0");
633         b.addDependency("c", "3.0", true);
634         ArtifactSpec d = a.addDependency("d", "1.0");
635         ArtifactSpec e = d.addDependency("e", "1.0");
636         e.addDependency("c", "2.0");
637 
638         ArtifactSpec c = createArtifactSpec("c", "3.0");
639 
640         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
641         assertEquals(
642                 createSet(new Object[] {a.artifact, b.artifact, c.artifact, d.artifact, e.artifact}),
643                 res.getArtifacts(),
644                 "Check artifact list");
645         Artifact artifact = getArtifact("c", res.getArtifacts());
646         assertEquals("3.0", artifact.getVersion(), "Check version");
647     }
648 
649     @Test
650     void testTestScopeNotTransitive() throws ArtifactResolutionException, InvalidVersionSpecificationException {
651         ArtifactSpec a = createArtifactSpec("a", "1.0", Artifact.SCOPE_TEST);
652         ArtifactSpec b = createArtifactSpec("b", "1.0");
653         b.addDependency("c", "3.0", Artifact.SCOPE_TEST);
654 
655         ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
656         assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
657     }
658 
659     @Test
660     void testSnapshotNotIncluded() throws ArtifactResolutionException, InvalidVersionSpecificationException {
661         ArtifactSpec a = createArtifactSpec("a", "1.0");
662         a.addDependency("b", "[1.0,)");
663         createArtifactSpec("b", "1.0-SNAPSHOT");
664 
665         ArtifactResolutionResult res = collect(a);
666 
667         assertTrue(res.hasVersionRangeViolations());
668 
669         /*
670          * try { ArtifactResolutionResult res = collect( a ); fail( "Expected b not to resolve: " + res ); } catch (
671          * OverConstrainedVersionException e ) { assertTrue( e.getMessage().indexOf( "[1.0-SNAPSHOT]" ) <
672          * e.getMessage().indexOf( "[1.0,)" ) ); }
673          */
674     }
675 
676     @Test
677     @Disabled("that one does not work")
678     void testOverConstrainedVersionException()
679             throws ArtifactResolutionException, InvalidVersionSpecificationException {
680         ArtifactSpec a = createArtifactSpec("a", "1.0");
681         a.addDependency("b", "[1.0, 2.0)");
682         a.addDependency("c", "[3.3.0,4.0.0)");
683 
684         ArtifactSpec b = createArtifactSpec("b", "1.0.0");
685         b.addDependency("c", "3.3.0-v3346");
686 
687         ArtifactSpec c = createArtifactSpec("c", "3.2.1-v3235e");
688 
689         OverConstrainedVersionException e = assertThrows(
690                 OverConstrainedVersionException.class, () -> collect(createSet(new Object[] {a.artifact})));
691         assertTrue(e.getMessage().contains("[3.2.1-v3235e, 3.3.0-v3346]"), "Versions unordered");
692         assertTrue(e.getMessage().contains("Path to dependency:"), "DependencyTrail unresolved");
693     }
694 
695     private Artifact getArtifact(String id, Set artifacts) {
696         for (Object artifact : artifacts) {
697             Artifact a = (Artifact) artifact;
698             if (a.getArtifactId().equals(id) && a.getGroupId().equals(GROUP_ID)) {
699                 return a;
700             }
701         }
702         return null;
703     }
704 
705     private ArtifactResolutionResult collect(Set<Artifact> artifacts) throws ArtifactResolutionException {
706         return collect(artifacts, null);
707     }
708 
709     private ArtifactResolutionResult collect(Set<Artifact> artifacts, ArtifactFilter filter)
710             throws ArtifactResolutionException {
711         return artifactCollector.collect(
712                 artifacts, projectArtifact.artifact, null, null, null, source, filter, Collections.emptyList(), null);
713     }
714 
715     private ArtifactResolutionResult collect(ArtifactSpec a) throws ArtifactResolutionException {
716         return artifactCollector.collect(
717                 Collections.singleton(a.artifact),
718                 projectArtifact.artifact,
719                 null,
720                 null,
721                 null,
722                 source,
723                 null,
724                 Collections.emptyList(),
725                 null);
726     }
727 
728     private ArtifactResolutionResult collect(ArtifactSpec a, ArtifactFilter filter) throws ArtifactResolutionException {
729         return artifactCollector.collect(
730                 Collections.singleton(a.artifact),
731                 projectArtifact.artifact,
732                 null,
733                 null,
734                 null,
735                 source,
736                 filter,
737                 Collections.emptyList(),
738                 null);
739     }
740 
741     private ArtifactResolutionResult collect(ArtifactSpec a, Artifact managedVersion)
742             throws ArtifactResolutionException {
743         Map<String, Artifact> managedVersions =
744                 Collections.singletonMap(managedVersion.getDependencyConflictId(), managedVersion);
745         return artifactCollector.collect(
746                 Collections.singleton(a.artifact),
747                 projectArtifact.artifact,
748                 managedVersions,
749                 null,
750                 null,
751                 source,
752                 null,
753                 Collections.emptyList(),
754                 null);
755     }
756 
757     private ArtifactSpec createArtifactSpec(String id, String version) throws InvalidVersionSpecificationException {
758         return createArtifactSpec(id, version, Artifact.SCOPE_COMPILE);
759     }
760 
761     private ArtifactSpec createArtifactSpec(String id, String version, boolean optional)
762             throws InvalidVersionSpecificationException {
763         return createArtifactSpec(id, version, Artifact.SCOPE_COMPILE, null, optional);
764     }
765 
766     private ArtifactSpec createArtifactSpec(String id, String version, String scope)
767             throws InvalidVersionSpecificationException {
768         return createArtifactSpec(id, version, scope, null, false);
769     }
770 
771     private ArtifactSpec createArtifactSpec(
772             String id, String version, String scope, String inheritedScope, boolean optional)
773             throws InvalidVersionSpecificationException {
774         VersionRange versionRange = VersionRange.createFromVersionSpec(version);
775         Artifact artifact = artifactFactory.createDependencyArtifact(
776                 GROUP_ID, id, versionRange, "jar", null, scope, inheritedScope, optional);
777         ArtifactSpec spec = null;
778         if (artifact != null) {
779             spec = new ArtifactSpec();
780             spec.artifact = artifact;
781             source.addArtifact(spec);
782         }
783         return spec;
784     }
785 
786     @SuppressWarnings("unchecked")
787     private static Set<Artifact> createSet(Object[] x) {
788         return new LinkedHashSet(Arrays.asList(x));
789     }
790 
791     private class ArtifactSpec {
792         private Artifact artifact;
793 
794         private Set<Artifact> dependencies = new HashSet<>();
795 
796         public ArtifactSpec addDependency(String id, String version) throws InvalidVersionSpecificationException {
797             return addDependency(id, version, Artifact.SCOPE_COMPILE);
798         }
799 
800         public ArtifactSpec addDependency(String id, String version, String scope)
801                 throws InvalidVersionSpecificationException {
802             return addDependency(id, version, scope, false);
803         }
804 
805         private ArtifactSpec addDependency(ArtifactSpec dep) throws InvalidVersionSpecificationException {
806             if (dep != null) {
807                 dependencies.add(dep.artifact);
808             }
809             return dep;
810         }
811 
812         private ArtifactSpec addDependency(String id, String version, String scope, boolean optional)
813                 throws InvalidVersionSpecificationException {
814             ArtifactSpec dep = createArtifactSpec(id, version, scope, artifact.getScope(), optional);
815             return addDependency(dep);
816         }
817 
818         public ArtifactSpec addDependency(String id, String version, boolean optional)
819                 throws InvalidVersionSpecificationException {
820             return addDependency(id, version, Artifact.SCOPE_COMPILE, optional);
821         }
822     }
823 
824     private class Source implements ArtifactMetadataSource {
825         private Map<String, ArtifactSpec> artifacts = new HashMap<>();
826 
827         private Map<String, List<ArtifactVersion>> versions = new HashMap<>();
828 
829         public ResolutionGroup retrieve(
830                 Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
831                 throws ArtifactMetadataRetrievalException {
832             String key = getKey(artifact);
833 
834             ArtifactSpec a = (ArtifactSpec) artifacts.get(key);
835             try {
836                 return new ResolutionGroup(
837                         artifact,
838                         createArtifacts(
839                                 artifactFactory, a.dependencies, artifact.getScope(), artifact.getDependencyFilter()),
840                         Collections.emptyList());
841             } catch (InvalidVersionSpecificationException e) {
842                 throw new ArtifactMetadataRetrievalException("Invalid version creating artifacts", e, artifact);
843             }
844         }
845 
846         private String getKey(Artifact artifact) {
847             return artifact.getDependencyConflictId();
848         }
849 
850         private Set<Artifact> createArtifacts(
851                 ArtifactFactory artifactFactory,
852                 Set<Artifact> dependencies,
853                 String inheritedScope,
854                 ArtifactFilter dependencyFilter)
855                 throws InvalidVersionSpecificationException {
856             Set<Artifact> projectArtifacts = new HashSet<>();
857 
858             for (Artifact d : dependencies) {
859                 VersionRange versionRange;
860                 if (d.getVersionRange() != null) {
861                     versionRange = d.getVersionRange();
862                 } else {
863                     versionRange = VersionRange.createFromVersionSpec(d.getVersion());
864                 }
865                 Artifact artifact;
866                 if (d.getScope().equals(Artifact.SCOPE_TEST) || d.getScope().equals(Artifact.SCOPE_PROVIDED)) {
867                     /* don't call createDependencyArtifact as it'll ignore test and provided scopes */
868                     artifact = artifactFactory.createArtifact(
869                             d.getGroupId(), d.getArtifactId(), d.getVersion(), d.getScope(), d.getType());
870                 } else {
871                     artifact = artifactFactory.createDependencyArtifact(
872                             d.getGroupId(),
873                             d.getArtifactId(),
874                             versionRange,
875                             d.getType(),
876                             d.getClassifier(),
877                             d.getScope(),
878                             inheritedScope,
879                             d.isOptional());
880                 }
881 
882                 if (artifact != null && (dependencyFilter == null || dependencyFilter.include(artifact))) {
883                     artifact.setDependencyFilter(dependencyFilter);
884 
885                     projectArtifacts.add(artifact);
886                 }
887             }
888 
889             return projectArtifacts;
890         }
891 
892         public void addArtifact(ArtifactSpec spec) {
893             artifacts.put(getKey(spec.artifact), spec);
894 
895             String key = spec.artifact.getDependencyConflictId();
896             List<ArtifactVersion> artifactVersions = versions.computeIfAbsent(key, k -> new ArrayList<>());
897             if (spec.artifact.getVersion() != null) {
898                 artifactVersions.add(new DefaultArtifactVersion(spec.artifact.getVersion()));
899             }
900         }
901 
902         public List<ArtifactVersion> retrieveAvailableVersions(
903                 Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
904                 throws ArtifactMetadataRetrievalException {
905             return retrieveAvailableVersions(artifact);
906         }
907 
908         public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository(
909                 Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository)
910                 throws ArtifactMetadataRetrievalException {
911             return retrieveAvailableVersions(artifact);
912         }
913 
914         private List<ArtifactVersion> retrieveAvailableVersions(Artifact artifact) {
915             List<ArtifactVersion> artifactVersions = versions.get(artifact.getDependencyConflictId());
916             if (artifactVersions == null) {
917                 artifactVersions = Collections.emptyList();
918             }
919             return artifactVersions;
920         }
921 
922         public ResolutionGroup retrieve(MetadataResolutionRequest request) throws ArtifactMetadataRetrievalException {
923             return retrieve(request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories());
924         }
925 
926         public List<ArtifactVersion> retrieveAvailableVersions(MetadataResolutionRequest request)
927                 throws ArtifactMetadataRetrievalException {
928             return retrieveAvailableVersions(
929                     request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories());
930         }
931     }
932 }