Skip to content

Commit dafad48

Browse files
committed
Adding DefaultDependencyResolverResultTest
1 parent 9b95526 commit dafad48

File tree

1 file changed

+376
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)