Skip to content

Commit d0db7d2

Browse files
committed
Adding DefaultDependencyResolverResultTest
1 parent 9b95526 commit d0db7d2

File tree

1 file changed

+371
-0
lines changed

1 file changed

+371
-0
lines changed
Lines changed: 371 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,371 @@
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.impl;
20+
21+
import java.nio.file.Files;
22+
import java.nio.file.Path;
23+
import java.util.ArrayList;
24+
import java.util.List;
25+
import java.util.Optional;
26+
import java.util.function.Predicate;
27+
import java.util.jar.Attributes;
28+
import java.util.jar.JarOutputStream;
29+
import java.util.jar.Manifest;
30+
31+
import org.apache.maven.api.Dependency;
32+
import org.apache.maven.api.JavaPathType;
33+
import org.apache.maven.api.Node;
34+
import org.apache.maven.api.PathType;
35+
import org.apache.maven.api.services.DependencyResolverRequest;
36+
import org.apache.maven.impl.resolver.type.DefaultType;
37+
import org.junit.jupiter.api.Test;
38+
39+
import static org.junit.jupiter.api.Assertions.assertEquals;
40+
import static org.junit.jupiter.api.Assertions.assertThrows;
41+
import static org.junit.jupiter.api.Assertions.assertTrue;
42+
import static org.mockito.Mockito.mock;
43+
import static org.mockito.Mockito.when;
44+
45+
/** Unit tests for {@link DefaultDependencyResolverResult}. */
46+
public class DefaultDependencyResolverResultTest {
47+
48+
@Test
49+
public void testAddDependencyWithNullDependencyAddsNodeOnly() throws Exception {
50+
DependencyResolverRequest req = mock(DependencyResolverRequest.class);
51+
List<Exception> exceptions = new ArrayList<>();
52+
Node root = mock(Node.class);
53+
PathModularizationCache cache = new PathModularizationCache(Runtime.version());
54+
55+
DefaultDependencyResolverResult result = new DefaultDependencyResolverResult(req, cache, exceptions, root, 4);
56+
57+
Node node = mock(Node.class);
58+
// addDependency with null dependency should only add the node
59+
result.addDependency(node, null, (Predicate<PathType>) (t) -> true, null);
60+
61+
assertEquals(1, result.getNodes().size());
62+
assertEquals(0, result.getDependencies().size());
63+
assertEquals(0, result.getPaths().size());
64+
assertTrue(result.getDispatchedPaths().isEmpty());
65+
}
66+
67+
@Test
68+
public void testAddDependencyDuplicateThrows() throws Exception {
69+
DependencyResolverRequest req = mock(DependencyResolverRequest.class);
70+
List<Exception> exceptions = new ArrayList<>();
71+
Node root = mock(Node.class);
72+
PathModularizationCache cache = new PathModularizationCache(Runtime.version());
73+
74+
DefaultDependencyResolverResult result = new DefaultDependencyResolverResult(req, cache, exceptions, root, 4);
75+
76+
Dependency dep = mock(Dependency.class);
77+
when(dep.getGroupId()).thenReturn("g");
78+
when(dep.getArtifactId()).thenReturn("a");
79+
when(dep.getType())
80+
.thenReturn(new DefaultType(
81+
"jar", org.apache.maven.api.Language.JAVA_FAMILY, "jar", null, false, JavaPathType.MODULES));
82+
83+
Node node = mock(Node.class);
84+
Path p = Files.createTempFile("dup", ".jar");
85+
86+
result.addDependency(node, dep, (Predicate<PathType>) (t) -> true, p);
87+
88+
// adding the same dependency again should throw
89+
IllegalStateException ex = assertThrows(
90+
IllegalStateException.class,
91+
() -> result.addDependency(node, dep, (Predicate<PathType>) (t) -> true, p));
92+
assertTrue(ex.getMessage().contains("Duplicated key"));
93+
}
94+
95+
@Test
96+
public void testAddDependencyWithAutomaticModuleNameAndGetModuleName() throws Exception {
97+
DependencyResolverRequest req = mock(DependencyResolverRequest.class);
98+
List<Exception> exceptions = new ArrayList<>();
99+
Node root = mock(Node.class);
100+
PathModularizationCache cache = new PathModularizationCache(Runtime.version());
101+
102+
DefaultDependencyResolverResult result = new DefaultDependencyResolverResult(req, cache, exceptions, root, 4);
103+
104+
// create a jar with Automatic-Module-Name manifest attribute
105+
Path jar = Files.createTempFile("auto-module", ".jar");
106+
Manifest mf = new Manifest();
107+
mf.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
108+
mf.getMainAttributes().put(new Attributes.Name("Automatic-Module-Name"), "auto.mod");
109+
try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(jar), mf)) {
110+
// empty jar with manifest
111+
}
112+
113+
Dependency dep = mock(Dependency.class);
114+
when(dep.getGroupId()).thenReturn("g");
115+
when(dep.getArtifactId()).thenReturn("a");
116+
when(dep.getType())
117+
.thenReturn(new DefaultType(
118+
"jar", org.apache.maven.api.Language.JAVA_FAMILY, "jar", null, false, JavaPathType.MODULES));
119+
120+
Node node = mock(Node.class);
121+
122+
result.addDependency(node, dep, (Predicate<PathType>) (t) -> true, jar);
123+
124+
assertEquals(1, result.getDependencies().size());
125+
assertEquals(1, result.getPaths().size());
126+
127+
Optional<String> moduleName = result.getModuleName(jar);
128+
assertTrue(moduleName.isPresent());
129+
assertEquals("auto.mod", moduleName.get());
130+
131+
Optional<java.lang.module.ModuleDescriptor> descriptor = result.getModuleDescriptor(jar);
132+
assertTrue(descriptor.isEmpty());
133+
}
134+
135+
@Test
136+
public void testSelectPathTypeUnknownsBecomeUnresolved() throws Exception {
137+
DependencyResolverRequest req = mock(DependencyResolverRequest.class);
138+
List<Exception> exceptions = new ArrayList<>();
139+
Node root = mock(Node.class);
140+
PathModularizationCache cache = new PathModularizationCache(Runtime.version());
141+
142+
DefaultDependencyResolverResult result = new DefaultDependencyResolverResult(req, cache, exceptions, root, 4);
143+
144+
Dependency dep = mock(Dependency.class);
145+
when(dep.getGroupId()).thenReturn("g.u");
146+
when(dep.getArtifactId()).thenReturn("a.u");
147+
Path p = Files.createTempFile("unres", ".jar");
148+
149+
// Type returns a known CLASSES and an unknown custom PathType => selectPathType should return empty
150+
when(dep.getType())
151+
.thenReturn(new DefaultType(
152+
"jar", org.apache.maven.api.Language.JAVA_FAMILY, "jar", null, false, JavaPathType.UNRESOLVED));
153+
154+
Node node = mock(Node.class);
155+
result.addDependency(node, dep, (Predicate<PathType>) (t) -> true, p);
156+
157+
assertTrue(result.getDispatchedPaths().containsKey(org.apache.maven.api.PathType.UNRESOLVED));
158+
assertTrue(result.getDispatchedPaths()
159+
.get(org.apache.maven.api.PathType.UNRESOLVED)
160+
.contains(p));
161+
}
162+
163+
@Test
164+
public void testAddOutputDirectoryWithNullMainPlacesTestOnClasspath() throws Exception {
165+
DependencyResolverRequest req = mock(DependencyResolverRequest.class);
166+
List<Exception> exceptions = new ArrayList<>();
167+
Node root = mock(Node.class);
168+
PathModularizationCache cache = new PathModularizationCache(Runtime.version());
169+
170+
DefaultDependencyResolverResult result = new DefaultDependencyResolverResult(req, cache, exceptions, root, 4);
171+
172+
Path testDir = Files.createTempDirectory("test-out");
173+
result.addOutputDirectory(null, testDir);
174+
175+
assertTrue(result.getDispatchedPaths().containsKey(JavaPathType.CLASSES));
176+
assertEquals(1, result.getDispatchedPaths().get(JavaPathType.CLASSES).size());
177+
assertEquals(
178+
testDir, result.getDispatchedPaths().get(JavaPathType.CLASSES).get(0));
179+
}
180+
181+
@Test
182+
public void testAddOutputDirectoryCalledTwiceThrows() throws Exception {
183+
DependencyResolverRequest req = mock(DependencyResolverRequest.class);
184+
List<Exception> exceptions = new ArrayList<>();
185+
Node root = mock(Node.class);
186+
PathModularizationCache cache = new PathModularizationCache(Runtime.version());
187+
188+
DefaultDependencyResolverResult result = new DefaultDependencyResolverResult(req, cache, exceptions, root, 4);
189+
190+
Path testDir = Files.createTempDirectory("test-out2");
191+
result.addOutputDirectory(null, testDir);
192+
193+
assertThrows(IllegalStateException.class, () -> result.addOutputDirectory(null, testDir));
194+
}
195+
196+
@Test
197+
public void testReturnedCollectionsAreUnmodifiable() throws Exception {
198+
DependencyResolverRequest req = mock(DependencyResolverRequest.class);
199+
List<Exception> exceptions = new ArrayList<>();
200+
Node root = mock(Node.class);
201+
PathModularizationCache cache = new PathModularizationCache(Runtime.version());
202+
203+
DefaultDependencyResolverResult result = new DefaultDependencyResolverResult(req, cache, exceptions, root, 4);
204+
205+
Node n1 = mock(Node.class);
206+
Node n2 = mock(Node.class);
207+
result.addNode(n1);
208+
result.addNode(n2);
209+
210+
// nodes list should be unmodifiable
211+
assertThrows(
212+
UnsupportedOperationException.class, () -> result.getNodes().add(mock(Node.class)));
213+
214+
// add a dependency to populate paths
215+
Dependency dep = mock(Dependency.class);
216+
when(dep.getGroupId()).thenReturn("g3");
217+
when(dep.getArtifactId()).thenReturn("a3");
218+
when(dep.getType())
219+
.thenReturn(new DefaultType(
220+
"jar", org.apache.maven.api.Language.JAVA_FAMILY, "jar", null, false, JavaPathType.CLASSES));
221+
222+
Path p = Files.createTempFile("path", ".jar");
223+
result.addDependency(n1, dep, (Predicate<PathType>) (t) -> true, p);
224+
225+
assertThrows(
226+
UnsupportedOperationException.class, () -> result.getPaths().add(Path.of("x")));
227+
}
228+
229+
@Test
230+
public void testAddOutputDirectoryWithMainPlacesMainOnModulePath() throws Exception {
231+
DependencyResolverRequest req = mock(DependencyResolverRequest.class);
232+
List<Exception> exceptions = new ArrayList<>();
233+
Node root = mock(Node.class);
234+
PathModularizationCache cache = new PathModularizationCache(Runtime.version());
235+
236+
DefaultDependencyResolverResult result = new DefaultDependencyResolverResult(req, cache, exceptions, root, 4);
237+
238+
// create a jar with Automatic-Module-Name manifest attribute to simulate a modular main output
239+
Path mainJar = Files.createTempFile("main-module", ".jar");
240+
Manifest mf = new Manifest();
241+
mf.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
242+
mf.getMainAttributes().put(new Attributes.Name("Automatic-Module-Name"), "main.mod");
243+
try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(mainJar), mf)) {
244+
// empty jar with manifest
245+
}
246+
247+
result.addOutputDirectory(mainJar, null);
248+
249+
// main output should have been placed on the module path
250+
assertTrue(result.getDispatchedPaths().containsKey(JavaPathType.MODULES));
251+
assertEquals(1, result.getDispatchedPaths().get(JavaPathType.MODULES).size());
252+
assertEquals(
253+
mainJar, result.getDispatchedPaths().get(JavaPathType.MODULES).get(0));
254+
}
255+
256+
@Test
257+
public void testAddDependencyPatchingExistingModuleUsesPatchModule() throws Exception {
258+
DependencyResolverRequest req = mock(DependencyResolverRequest.class);
259+
List<Exception> exceptions = new ArrayList<>();
260+
Node root = mock(Node.class);
261+
PathModularizationCache cache = new PathModularizationCache(Runtime.version());
262+
263+
DefaultDependencyResolverResult result = new DefaultDependencyResolverResult(req, cache, exceptions, root, 8);
264+
265+
// first dependency: modular artifact that will be placed on module path
266+
Path moduleJar1 = Files.createTempFile("mod1", ".jar");
267+
Manifest mf1 = new Manifest();
268+
mf1.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
269+
mf1.getMainAttributes().put(new Attributes.Name("Automatic-Module-Name"), "modA");
270+
try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(moduleJar1), mf1)) {
271+
// empty jar with manifest
272+
}
273+
274+
Dependency dep1 = mock(Dependency.class);
275+
when(dep1.getGroupId()).thenReturn("g1");
276+
when(dep1.getArtifactId()).thenReturn("a1");
277+
when(dep1.getType())
278+
.thenReturn(new DefaultType(
279+
"jar", org.apache.maven.api.Language.JAVA_FAMILY, "jar", null, false, JavaPathType.MODULES));
280+
281+
Node node = mock(Node.class);
282+
// add first dependency -> should be on MODULES
283+
result.addDependency(node, dep1, (Predicate<PathType>) (t) -> true, moduleJar1);
284+
285+
// second dependency: a patch-module for the same module name "modA"
286+
Path moduleJar2 = Files.createTempFile("mod2", ".jar");
287+
Manifest mf2 = new Manifest();
288+
mf2.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
289+
mf2.getMainAttributes().put(new Attributes.Name("Automatic-Module-Name"), "modA");
290+
try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(moduleJar2), mf2)) {
291+
// empty jar with manifest
292+
}
293+
294+
Dependency dep2 = mock(Dependency.class);
295+
when(dep2.getGroupId()).thenReturn("g2");
296+
when(dep2.getArtifactId()).thenReturn("a2");
297+
when(dep2.getType())
298+
.thenReturn(new DefaultType(
299+
"jar",
300+
org.apache.maven.api.Language.JAVA_FAMILY,
301+
"jar",
302+
null,
303+
false,
304+
JavaPathType.PATCH_MODULE));
305+
306+
// add second dependency -> should detect existing module and dispatch as patch-module(modA)
307+
result.addDependency(node, dep2, (Predicate<PathType>) (t) -> true, moduleJar2);
308+
309+
JavaPathType.Modular patchForModA = JavaPathType.patchModule("modA");
310+
assertTrue(result.getDispatchedPaths().containsKey(patchForModA));
311+
assertTrue(result.getDispatchedPaths().get(patchForModA).contains(moduleJar2));
312+
}
313+
314+
@Test
315+
public void testAddDependencyPatchingByArtifactWhenNoModuleInfoButMatchingArtifactExists() throws Exception {
316+
DependencyResolverRequest req = mock(DependencyResolverRequest.class);
317+
List<Exception> exceptions = new ArrayList<>();
318+
Node root = mock(Node.class);
319+
PathModularizationCache cache = new PathModularizationCache(Runtime.version());
320+
321+
DefaultDependencyResolverResult result = new DefaultDependencyResolverResult(req, cache, exceptions, root, 8);
322+
323+
// main artifact (provides module info)
324+
Path mainJar = Files.createTempFile("main-artifact", ".jar");
325+
Manifest mfMain = new Manifest();
326+
mfMain.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
327+
mfMain.getMainAttributes().put(new Attributes.Name("Automatic-Module-Name"), "modB");
328+
try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(mainJar), mfMain)) {
329+
// empty jar with manifest
330+
}
331+
332+
Dependency mainDep = mock(Dependency.class);
333+
when(mainDep.getGroupId()).thenReturn("gX");
334+
when(mainDep.getArtifactId()).thenReturn("aX");
335+
when(mainDep.getType())
336+
.thenReturn(new DefaultType(
337+
"jar", org.apache.maven.api.Language.JAVA_FAMILY, "jar", null, false, JavaPathType.MODULES));
338+
339+
Node node = mock(Node.class);
340+
// add main artifact
341+
result.addDependency(node, mainDep, (Predicate<PathType>) (t) -> true, mainJar);
342+
343+
// patch artifact which has no module info itself
344+
Path patchJar = Files.createTempFile("patch-no-modinfo", ".jar");
345+
// create an empty jar without Automatic-Module-Name
346+
try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(patchJar), new Manifest())) {
347+
// empty jar
348+
}
349+
350+
Dependency patchDep = mock(Dependency.class);
351+
when(patchDep.getGroupId()).thenReturn("gX");
352+
when(patchDep.getArtifactId()).thenReturn("aX"); // same identifiers -> findArtifactPath should find mainDep
353+
when(patchDep.getType())
354+
.thenReturn(new DefaultType(
355+
"jar",
356+
org.apache.maven.api.Language.JAVA_FAMILY,
357+
"jar",
358+
null,
359+
false,
360+
JavaPathType.PATCH_MODULE));
361+
362+
// add the patch dependency; since it has no module info, findArtifactPath should pick up mainJar and add a
363+
// patch for modB
364+
result.addDependency(node, patchDep, (Predicate<PathType>) (t) -> true, patchJar);
365+
366+
JavaPathType.Modular patchForModB = JavaPathType.patchModule("modB");
367+
assertTrue(result.getDispatchedPaths().containsKey(patchForModB));
368+
// The code will add the main artifact's descriptor path for patching (info.getKey()), assert mainJar present
369+
assertTrue(result.getDispatchedPaths().get(patchForModB).contains(mainJar));
370+
}
371+
}

0 commit comments

Comments
 (0)