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