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.eclipse.aether.internal.impl.collect;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.LinkedList;
29  import java.util.List;
30  import java.util.Map;
31  
32  import org.eclipse.aether.DefaultRepositorySystemSession;
33  import org.eclipse.aether.RepositorySystemSession;
34  import org.eclipse.aether.artifact.Artifact;
35  import org.eclipse.aether.artifact.ArtifactProperties;
36  import org.eclipse.aether.artifact.DefaultArtifact;
37  import org.eclipse.aether.collection.CollectRequest;
38  import org.eclipse.aether.collection.CollectResult;
39  import org.eclipse.aether.collection.DependencyCollectionContext;
40  import org.eclipse.aether.collection.DependencyCollectionException;
41  import org.eclipse.aether.collection.DependencyManagement;
42  import org.eclipse.aether.collection.DependencyManager;
43  import org.eclipse.aether.graph.DefaultDependencyNode;
44  import org.eclipse.aether.graph.Dependency;
45  import org.eclipse.aether.graph.DependencyCycle;
46  import org.eclipse.aether.graph.DependencyNode;
47  import org.eclipse.aether.graph.Exclusion;
48  import org.eclipse.aether.impl.ArtifactDescriptorReader;
49  import org.eclipse.aether.internal.impl.IniArtifactDescriptorReader;
50  import org.eclipse.aether.internal.test.util.DependencyGraphParser;
51  import org.eclipse.aether.internal.test.util.TestUtils;
52  import org.eclipse.aether.repository.RemoteRepository;
53  import org.eclipse.aether.resolution.ArtifactDescriptorException;
54  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
55  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
56  import org.eclipse.aether.util.artifact.ArtifactIdUtils;
57  import org.eclipse.aether.util.graph.manager.ClassicDependencyManager;
58  import org.eclipse.aether.util.graph.manager.DefaultDependencyManager;
59  import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
60  import org.eclipse.aether.util.graph.manager.TransitiveDependencyManager;
61  import org.eclipse.aether.util.graph.transformer.ConflictResolver;
62  import org.eclipse.aether.util.graph.transformer.JavaScopeDeriver;
63  import org.eclipse.aether.util.graph.transformer.JavaScopeSelector;
64  import org.eclipse.aether.util.graph.transformer.NearestVersionSelector;
65  import org.eclipse.aether.util.graph.transformer.SimpleOptionalitySelector;
66  import org.eclipse.aether.util.graph.version.HighestVersionFilter;
67  import org.junit.jupiter.api.BeforeEach;
68  import org.junit.jupiter.api.Test;
69  
70  import static java.util.Collections.singletonList;
71  import static java.util.Objects.requireNonNull;
72  import static org.junit.jupiter.api.Assertions.*;
73  
74  /**
75   * Common tests for various {@link DependencyCollectorDelegate} implementations.
76   */
77  public abstract class DependencyCollectorDelegateTestSupport {
78  
79      protected DefaultRepositorySystemSession session;
80  
81      protected DependencyGraphParser parser;
82  
83      protected RemoteRepository repository;
84  
85      protected DependencyCollectorDelegate collector;
86  
87      protected IniArtifactDescriptorReader newReader(String prefix) {
88          return new IniArtifactDescriptorReader("artifact-descriptions/" + prefix);
89      }
90  
91      protected Dependency newDep(String coords) {
92          return newDep(coords, "");
93      }
94  
95      protected Dependency newDep(String coords, String scope) {
96          return new Dependency(new DefaultArtifact(coords), scope);
97      }
98  
99      @BeforeEach
100     void setup() {
101         session = TestUtils.newSession();
102         parser = new DependencyGraphParser("artifact-descriptions/");
103         repository = new RemoteRepository.Builder("id", "default", "file:///").build();
104         collector = setupCollector(newReader(""));
105     }
106 
107     protected abstract DependencyCollectorDelegate setupCollector(ArtifactDescriptorReader artifactDescriptorReader);
108 
109     private static void assertEqualSubtree(DependencyNode expected, DependencyNode actual) {
110         assertEqualSubtree(expected, actual, new LinkedList<>());
111     }
112 
113     private static void assertEqualSubtree(
114             DependencyNode expected, DependencyNode actual, LinkedList<DependencyNode> parents) {
115         assertEquals(expected.getDependency(), actual.getDependency(), "path: " + parents);
116 
117         if (actual.getDependency() != null) {
118             Artifact artifact = actual.getDependency().getArtifact();
119             for (DependencyNode parent : parents) {
120                 if (parent.getDependency() != null
121                         && artifact.equals(parent.getDependency().getArtifact())) {
122                     return;
123                 }
124             }
125         }
126 
127         parents.addLast(expected);
128 
129         assertEquals(
130                 expected.getChildren().size(),
131                 actual.getChildren().size(),
132                 "path: " + parents + ", expected: " + expected.getChildren() + ", actual: " + actual.getChildren());
133 
134         Iterator<DependencyNode> iterator1 = expected.getChildren().iterator();
135         Iterator<DependencyNode> iterator2 = actual.getChildren().iterator();
136 
137         while (iterator1.hasNext()) {
138             assertEqualSubtree(iterator1.next(), iterator2.next(), parents);
139         }
140 
141         parents.removeLast();
142     }
143 
144     protected Dependency dep(DependencyNode root, int... coords) {
145         return path(root, coords).getDependency();
146     }
147 
148     protected DependencyNode path(DependencyNode root, int... coords) {
149         try {
150             DependencyNode node = root;
151             for (int coord : coords) {
152                 node = node.getChildren().get(coord);
153             }
154 
155             return node;
156         } catch (IndexOutOfBoundsException | NullPointerException e) {
157             throw new IllegalArgumentException("illegal coordinates for child", e);
158         }
159     }
160 
161     @Test
162     void testSimpleCollection() throws DependencyCollectionException {
163         Dependency dependency = newDep("gid:aid:ext:ver", "compile");
164         CollectRequest request = new CollectRequest(dependency, singletonList(repository));
165         CollectResult result = collector.collectDependencies(session, request);
166 
167         assertEquals(0, result.getExceptions().size());
168 
169         DependencyNode root = result.getRoot();
170         Dependency newDependency = root.getDependency();
171 
172         assertEquals(dependency, newDependency);
173         assertEquals(dependency.getArtifact(), newDependency.getArtifact());
174 
175         assertEquals(1, root.getChildren().size());
176 
177         Dependency expect = newDep("gid:aid2:ext:ver", "compile");
178         assertEquals(expect, root.getChildren().get(0).getDependency());
179     }
180 
181     @Test
182     void testMissingDependencyDescription() {
183         CollectRequest request = new CollectRequest(newDep("missing:description:ext:ver"), singletonList(repository));
184         try {
185             collector.collectDependencies(session, request);
186             fail("expected exception");
187         } catch (DependencyCollectionException e) {
188             CollectResult result = e.getResult();
189             assertSame(request, result.getRequest());
190             assertNotNull(result.getExceptions());
191             assertEquals(1, result.getExceptions().size());
192 
193             assertTrue(result.getExceptions().get(0) instanceof ArtifactDescriptorException);
194 
195             assertEquals(request.getRoot(), result.getRoot().getDependency());
196         }
197     }
198 
199     @Test
200     void testDuplicates() throws DependencyCollectionException {
201         Dependency dependency = newDep("duplicate:transitive:ext:dependency");
202         CollectRequest request = new CollectRequest(dependency, singletonList(repository));
203 
204         CollectResult result = collector.collectDependencies(session, request);
205 
206         assertEquals(0, result.getExceptions().size());
207 
208         DependencyNode root = result.getRoot();
209         Dependency newDependency = root.getDependency();
210 
211         assertEquals(dependency, newDependency);
212         assertEquals(dependency.getArtifact(), newDependency.getArtifact());
213 
214         assertEquals(2, root.getChildren().size());
215 
216         Dependency dep = newDep("gid:aid:ext:ver", "compile");
217         assertEquals(dep, dep(root, 0));
218 
219         dep = newDep("gid:aid2:ext:ver", "compile");
220         assertEquals(dep, dep(root, 1));
221         assertEquals(dep, dep(root, 0, 0));
222         assertEquals(dep(root, 1), dep(root, 0, 0));
223     }
224 
225     @Test
226     void testEqualSubtree() throws IOException, DependencyCollectionException {
227         DependencyNode root = parser.parseResource("expectedSubtreeComparisonResult.txt");
228         Dependency dependency = root.getDependency();
229         CollectRequest request = new CollectRequest(dependency, singletonList(repository));
230 
231         CollectResult result = collector.collectDependencies(session, request);
232         assertEqualSubtree(root, result.getRoot());
233     }
234 
235     @Test
236     void testCyclicDependencies() throws Exception {
237         DependencyNode root = parser.parseResource("cycle.txt");
238         CollectRequest request = new CollectRequest(root.getDependency(), singletonList(repository));
239         CollectResult result = collector.collectDependencies(session, request);
240         assertEqualSubtree(root, result.getRoot());
241     }
242 
243     @Test
244     void testCyclicDependenciesBig() throws Exception {
245         CollectRequest request = new CollectRequest(newDep("1:2:pom:5.50-SNAPSHOT"), singletonList(repository));
246         collector = setupCollector(newReader("cycle-big/"));
247         CollectResult result = collector.collectDependencies(session, request);
248         assertNotNull(result.getRoot());
249         // we only care about the performance here, this test must not hang or run out of mem
250     }
251 
252     @Test
253     void testCyclicProjects() throws Exception {
254         CollectRequest request = new CollectRequest(newDep("test:a:2"), singletonList(repository));
255         collector = setupCollector(newReader("versionless-cycle/"));
256         CollectResult result = collector.collectDependencies(session, request);
257         DependencyNode root = result.getRoot();
258         DependencyNode a1 = path(root, 0, 0);
259         assertEquals("a", a1.getArtifact().getArtifactId());
260         assertEquals("1", a1.getArtifact().getVersion());
261         for (DependencyNode child : a1.getChildren()) {
262             assertNotEquals("1", child.getArtifact().getVersion());
263         }
264 
265         assertEquals(1, result.getCycles().size());
266         DependencyCycle cycle = result.getCycles().get(0);
267         assertEquals(Collections.emptyList(), cycle.getPrecedingDependencies());
268         assertEquals(
269                 Arrays.asList(root.getDependency(), path(root, 0).getDependency(), a1.getDependency()),
270                 cycle.getCyclicDependencies());
271     }
272 
273     @Test
274     void testCyclicProjects_ConsiderLabelOfRootlessGraph() throws Exception {
275         Dependency dep = newDep("gid:aid:ver", "compile");
276         CollectRequest request = new CollectRequest()
277                 .addDependency(dep)
278                 .addRepository(repository)
279                 .setRootArtifact(dep.getArtifact());
280         CollectResult result = collector.collectDependencies(session, request);
281         DependencyNode root = result.getRoot();
282         DependencyNode a1 = root.getChildren().get(0);
283         assertEquals("aid", a1.getArtifact().getArtifactId());
284         assertEquals("ver", a1.getArtifact().getVersion());
285         DependencyNode a2 = a1.getChildren().get(0);
286         assertEquals("aid2", a2.getArtifact().getArtifactId());
287         assertEquals("ver", a2.getArtifact().getVersion());
288 
289         assertEquals(1, result.getCycles().size());
290         DependencyCycle cycle = result.getCycles().get(0);
291         assertEquals(Collections.emptyList(), cycle.getPrecedingDependencies());
292         assertEquals(
293                 Arrays.asList(new Dependency(dep.getArtifact(), null), a1.getDependency()),
294                 cycle.getCyclicDependencies());
295     }
296 
297     @Test
298     void testPartialResultOnError() throws IOException {
299         DependencyNode root = parser.parseResource("expectedPartialSubtreeOnError.txt");
300 
301         Dependency dependency = root.getDependency();
302         CollectRequest request = new CollectRequest(dependency, singletonList(repository));
303 
304         CollectResult result;
305         try {
306             collector.collectDependencies(session, request);
307             fail("expected exception ");
308         } catch (DependencyCollectionException e) {
309             result = e.getResult();
310 
311             assertSame(request, result.getRequest());
312             assertNotNull(result.getExceptions());
313             assertEquals(1, result.getExceptions().size());
314 
315             assertTrue(result.getExceptions().get(0) instanceof ArtifactDescriptorException);
316 
317             assertEqualSubtree(root, result.getRoot());
318         }
319     }
320 
321     @Test
322     void testCollectMultipleDependencies() throws DependencyCollectionException {
323         Dependency root1 = newDep("gid:aid:ext:ver", "compile");
324         Dependency root2 = newDep("gid:aid2:ext:ver", "compile");
325         List<Dependency> dependencies = Arrays.asList(root1, root2);
326         CollectRequest request = new CollectRequest(dependencies, null, singletonList(repository));
327         CollectResult result = collector.collectDependencies(session, request);
328 
329         assertEquals(0, result.getExceptions().size());
330         assertEquals(2, result.getRoot().getChildren().size());
331         assertEquals(root1, dep(result.getRoot(), 0));
332 
333         assertEquals(1, path(result.getRoot(), 0).getChildren().size());
334         assertEquals(root2, dep(result.getRoot(), 0, 0));
335 
336         assertEquals(0, path(result.getRoot(), 1).getChildren().size());
337         assertEquals(root2, dep(result.getRoot(), 1));
338     }
339 
340     @Test
341     void testArtifactDescriptorResolutionNotRestrictedToRepoHostingSelectedVersion() throws Exception {
342         RemoteRepository repo2 = new RemoteRepository.Builder("test", "default", "file:///").build();
343 
344         final List<RemoteRepository> repos = new ArrayList<>();
345 
346         collector = setupCollector(new ArtifactDescriptorReader() {
347             @Override
348             public ArtifactDescriptorResult readArtifactDescriptor(
349                     RepositorySystemSession session, ArtifactDescriptorRequest request) {
350                 repos.addAll(request.getRepositories());
351                 return new ArtifactDescriptorResult(request);
352             }
353         });
354 
355         List<Dependency> dependencies = singletonList(newDep("verrange:parent:jar:1[1,)", "compile"));
356         CollectRequest request = new CollectRequest(dependencies, null, Arrays.asList(repository, repo2));
357         CollectResult result = collector.collectDependencies(session, request);
358 
359         assertEquals(0, result.getExceptions().size());
360         assertEquals(2, repos.size());
361         assertEquals("id", repos.get(0).getId());
362         assertEquals("test", repos.get(1).getId());
363     }
364 
365     @Test
366     void testManagedVersionScope() throws DependencyCollectionException {
367         Dependency dependency = newDep("managed:aid:ext:ver");
368         CollectRequest request = new CollectRequest(dependency, singletonList(repository));
369 
370         session.setDependencyManager(new ClassicDependencyManager());
371 
372         CollectResult result = collector.collectDependencies(session, request);
373 
374         assertEquals(0, result.getExceptions().size());
375 
376         DependencyNode root = result.getRoot();
377 
378         assertEquals(dependency, dep(root));
379         assertEquals(dependency.getArtifact(), dep(root).getArtifact());
380 
381         assertEquals(1, root.getChildren().size());
382         Dependency expect = newDep("gid:aid:ext:ver", "compile");
383         assertEquals(expect, dep(root, 0));
384 
385         assertEquals(1, path(root, 0).getChildren().size());
386         expect = newDep("gid:aid2:ext:managedVersion", "managedScope");
387         assertEquals(expect, dep(root, 0, 0));
388     }
389 
390     @Test
391     void testDependencyManagement() throws IOException, DependencyCollectionException {
392         collector = setupCollector(newReader("managed/"));
393 
394         DependencyNode root = parser.parseResource("expectedSubtreeComparisonResult.txt");
395         TestDependencyManager depMgmt = new TestDependencyManager();
396         depMgmt.add(dep(root, 0), "managed", null, null);
397         depMgmt.add(dep(root, 0, 1), "managed", "managed", null);
398         depMgmt.add(dep(root, 1), null, null, "managed");
399         session.setDependencyManager(depMgmt);
400 
401         // collect result will differ from expectedSubtreeComparisonResult.txt
402         // set localPath -> no dependency traversal
403         CollectRequest request = new CollectRequest(dep(root), singletonList(repository));
404         CollectResult result = collector.collectDependencies(session, request);
405 
406         DependencyNode node = result.getRoot();
407         assertEquals("managed", dep(node, 0, 1).getArtifact().getVersion());
408         assertEquals("managed", dep(node, 0, 1).getScope());
409 
410         assertEquals("managed", dep(node, 1).getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null));
411         assertEquals("managed", dep(node, 0, 0).getArtifact().getProperty(ArtifactProperties.LOCAL_PATH, null));
412     }
413 
414     @Test
415     void testDependencyManagement_VerboseMode() throws Exception {
416         String depId = "gid:aid2:ext";
417         TestDependencyManager depMgmt = new TestDependencyManager();
418         depMgmt.version(depId, "managedVersion");
419         depMgmt.scope(depId, "managedScope");
420         depMgmt.optional(depId, Boolean.TRUE);
421         depMgmt.path(depId, "managedPath");
422         depMgmt.exclusions(depId, new Exclusion("gid", "aid", "*", "*"));
423         session.setDependencyManager(depMgmt);
424         session.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, Boolean.TRUE);
425 
426         CollectRequest request = new CollectRequest().setRoot(newDep("gid:aid:ver"));
427         CollectResult result = collector.collectDependencies(session, request);
428         DependencyNode node = result.getRoot().getChildren().get(0);
429         assertEquals(
430                 DependencyNode.MANAGED_VERSION
431                         | DependencyNode.MANAGED_SCOPE
432                         | DependencyNode.MANAGED_OPTIONAL
433                         | DependencyNode.MANAGED_PROPERTIES
434                         | DependencyNode.MANAGED_EXCLUSIONS,
435                 node.getManagedBits());
436         assertEquals("ver", DependencyManagerUtils.getPremanagedVersion(node));
437         assertEquals("compile", DependencyManagerUtils.getPremanagedScope(node));
438         assertEquals(Boolean.FALSE, DependencyManagerUtils.getPremanagedOptional(node));
439     }
440 
441     @Test
442     void testDependencyManagement_TransitiveDependencyManager() throws DependencyCollectionException, IOException {
443         collector = setupCollector(newReader("managed/"));
444         parser = new DependencyGraphParser("artifact-descriptions/managed/");
445         session.setDependencyManager(new TransitiveDependencyManager());
446         final Dependency root = newDep("gid:root:ext:ver", "compile");
447         CollectRequest request = new CollectRequest(root, singletonList(repository));
448         request.addManagedDependency(newDep("gid:root:ext:must-retain-core-management"));
449         CollectResult result = collector.collectDependencies(session, request);
450 
451         final DependencyNode expectedTree = parser.parseResource("management-tree.txt");
452         assertEqualSubtree(expectedTree, result.getRoot());
453 
454         // Same test for root artifact (POM) request.
455         final CollectRequest rootArtifactRequest = new CollectRequest();
456         rootArtifactRequest.setRepositories(singletonList(repository));
457         rootArtifactRequest.setRootArtifact(new DefaultArtifact("gid:root:ext:ver"));
458         rootArtifactRequest.addDependency(newDep("gid:direct:ext:ver", "compile"));
459         rootArtifactRequest.addManagedDependency(newDep("gid:root:ext:must-retain-core-management"));
460         rootArtifactRequest.addManagedDependency(newDep("gid:direct:ext:must-retain-core-management"));
461         rootArtifactRequest.addManagedDependency(newDep("gid:transitive-1:ext:managed-by-root"));
462         session.setDependencyManager(new TransitiveDependencyManager());
463         result = collector.collectDependencies(session, rootArtifactRequest);
464         assertEqualSubtree(expectedTree, toDependencyResult(result.getRoot(), "compile", null));
465     }
466 
467     @Test
468     void testDependencyManagement_DefaultDependencyManager() throws DependencyCollectionException, IOException {
469         collector = setupCollector(newReader("managed/"));
470         parser = new DependencyGraphParser("artifact-descriptions/managed/");
471         session.setDependencyManager(new DefaultDependencyManager());
472         final Dependency root = newDep("gid:root:ext:ver", "compile");
473         CollectRequest request = new CollectRequest(root, singletonList(repository));
474         request.addManagedDependency(newDep("gid:root:ext:must-not-manage-root"));
475         request.addManagedDependency(newDep("gid:direct:ext:managed-by-dominant-request"));
476         CollectResult result = collector.collectDependencies(session, request);
477 
478         final DependencyNode expectedTree = parser.parseResource("default-management-tree.txt");
479         assertEqualSubtree(expectedTree, result.getRoot());
480 
481         // Same test for root artifact (POM) request.
482         final CollectRequest rootArtifactRequest = new CollectRequest();
483         rootArtifactRequest.setRepositories(singletonList(repository));
484         rootArtifactRequest.setRootArtifact(new DefaultArtifact("gid:root:ext:ver"));
485         rootArtifactRequest.addDependency(newDep("gid:direct:ext:ver", "compile"));
486         rootArtifactRequest.addManagedDependency(newDep("gid:root:ext:must-not-manage-root"));
487         rootArtifactRequest.addManagedDependency(newDep("gid:direct:ext:managed-by-dominant-request"));
488         rootArtifactRequest.addManagedDependency(newDep("gid:transitive-1:ext:managed-by-root"));
489         session.setDependencyManager(new DefaultDependencyManager());
490         result = collector.collectDependencies(session, rootArtifactRequest);
491         assertEqualSubtree(expectedTree, toDependencyResult(result.getRoot(), "compile", null));
492     }
493 
494     @Test
495     void testTransitiveDepsUseRangesDirtyTree() throws DependencyCollectionException, IOException {
496         // Note: DF depends on version order (ultimately the order of versions as returned by VersionRangeResolver
497         // that in case of Maven, means order as in maven-metadata.xml
498         // BF on the other hand explicitly sorts versions from range in descending order
499         //
500         // Hence, the "dirty tree" of two will not match.
501         DependencyNode root = parser.parseResource(getTransitiveDepsUseRangesDirtyTreeResource());
502         Dependency dependency = root.getDependency();
503         CollectRequest request = new CollectRequest(dependency, singletonList(repository));
504 
505         CollectResult result = collector.collectDependencies(session, request);
506         assertEqualSubtree(root, result.getRoot());
507     }
508 
509     protected abstract String getTransitiveDepsUseRangesDirtyTreeResource();
510 
511     @Test
512     void testTransitiveDepsUseRangesAndRelocationDirtyTree() throws DependencyCollectionException, IOException {
513         // Note: DF depends on version order (ultimately the order of versions as returned by VersionRangeResolver
514         // that in case of Maven, means order as in maven-metadata.xml
515         // BF on the other hand explicitly sorts versions from range in descending order
516         //
517         // Hence, the "dirty tree" of two will not match.
518         DependencyNode root = parser.parseResource(getTransitiveDepsUseRangesAndRelocationDirtyTreeResource());
519         Dependency dependency = root.getDependency();
520         CollectRequest request = new CollectRequest(dependency, singletonList(repository));
521 
522         CollectResult result = collector.collectDependencies(session, request);
523         assertEqualSubtree(root, result.getRoot());
524     }
525 
526     protected abstract String getTransitiveDepsUseRangesAndRelocationDirtyTreeResource();
527 
528     private DependencyNode toDependencyResult(
529             final DependencyNode root, final String rootScope, final Boolean optional) {
530         // Make the root artifact resolution result a dependency resolution result for the subtree check.
531         assertNull(root.getDependency(), "Expected root artifact resolution result.");
532         final DefaultDependencyNode defaultNode =
533                 new DefaultDependencyNode(new Dependency(root.getArtifact(), rootScope));
534 
535         defaultNode.setChildren(root.getChildren());
536 
537         if (optional != null) {
538             defaultNode.setOptional(optional);
539         }
540 
541         return defaultNode;
542     }
543 
544     @Test
545     void testVersionFilter() throws Exception {
546         session.setVersionFilter(new HighestVersionFilter());
547         CollectRequest request = new CollectRequest().setRoot(newDep("gid:aid:1"));
548         CollectResult result = collector.collectDependencies(session, request);
549         assertEquals(1, result.getRoot().getChildren().size());
550     }
551 
552     @Test
553     void testDescriptorDependenciesEmpty() throws Exception {
554         collector = setupCollector(newReader("dependencies-empty/"));
555 
556         session.setDependencyGraphTransformer(new ConflictResolver(
557                 new NearestVersionSelector(),
558                 new JavaScopeSelector(),
559                 new SimpleOptionalitySelector(),
560                 new JavaScopeDeriver()));
561 
562         DependencyNode root = parser.parseResource("expectedSubtreeOnDescriptorDependenciesEmptyLeft.txt");
563         Dependency dependency = root.getDependency();
564         CollectRequest request = new CollectRequest(dependency, singletonList(repository));
565         CollectResult result = collector.collectDependencies(session, request);
566         assertEqualSubtree(root, result.getRoot());
567 
568         root = parser.parseResource("expectedSubtreeOnDescriptorDependenciesEmptyRight.txt");
569         dependency = root.getDependency();
570         request = new CollectRequest(dependency, singletonList(repository));
571         result = collector.collectDependencies(session, request);
572         assertEqualSubtree(root, result.getRoot());
573     }
574 
575     static class TestDependencyManager implements DependencyManager {
576 
577         private final Map<String, String> versions = new HashMap<>();
578 
579         private final Map<String, String> scopes = new HashMap<>();
580 
581         private final Map<String, Boolean> optionals = new HashMap<>();
582 
583         private final Map<String, String> paths = new HashMap<>();
584 
585         private final Map<String, Collection<Exclusion>> exclusions = new HashMap<>();
586 
587         public void add(Dependency d, String version, String scope, String localPath) {
588             String id = toKey(d);
589             version(id, version);
590             scope(id, scope);
591             path(id, localPath);
592         }
593 
594         public void version(String id, String version) {
595             versions.put(id, version);
596         }
597 
598         public void scope(String id, String scope) {
599             scopes.put(id, scope);
600         }
601 
602         public void optional(String id, Boolean optional) {
603             optionals.put(id, optional);
604         }
605 
606         public void path(String id, String path) {
607             paths.put(id, path);
608         }
609 
610         public void exclusions(String id, Exclusion... exclusions) {
611             this.exclusions.put(id, exclusions != null ? Arrays.asList(exclusions) : null);
612         }
613 
614         @Override
615         public DependencyManagement manageDependency(Dependency dependency) {
616             requireNonNull(dependency, "dependency cannot be null");
617             String id = toKey(dependency);
618             DependencyManagement mgmt = new DependencyManagement();
619             mgmt.setVersion(versions.get(id));
620             mgmt.setScope(scopes.get(id));
621             mgmt.setOptional(optionals.get(id));
622             String path = paths.get(id);
623             if (path != null) {
624                 mgmt.setProperties(Collections.singletonMap(ArtifactProperties.LOCAL_PATH, path));
625             }
626             mgmt.setExclusions(exclusions.get(id));
627             return mgmt;
628         }
629 
630         private String toKey(Dependency dependency) {
631             return ArtifactIdUtils.toVersionlessId(dependency.getArtifact());
632         }
633 
634         @Override
635         public DependencyManager deriveChildManager(DependencyCollectionContext context) {
636             requireNonNull(context, "context cannot be null");
637             return this;
638         }
639     }
640 }