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