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