View Javadoc
1   package org.codehaus.plexus.languages.java.jpms;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.nio.file.Path;
24  import java.nio.file.Paths;
25  import java.util.Arrays;
26  import java.util.Collections;
27  import java.util.HashSet;
28  
29  import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor.JavaRequires.JavaModifier;
30  import org.junit.jupiter.api.BeforeEach;
31  import org.junit.jupiter.api.Test;
32  
33  import static org.assertj.core.api.Assertions.assertThat;
34  import static org.mockito.ArgumentMatchers.any;
35  import static org.mockito.Mockito.mock;
36  import static org.mockito.Mockito.when;
37  
38  class LocationManagerTest {
39      private BinaryModuleInfoParser asmParser;
40  
41      private SourceModuleInfoParser qdoxParser;
42  
43      private LocationManager locationManager;
44  
45      final Path mockModuleInfoJava = Paths.get("src/test/resources/mock/module-info.java");
46  
47      @BeforeEach
48      void onSetup() {
49          asmParser = mock(BinaryModuleInfoParser.class);
50          qdoxParser = mock(SourceModuleInfoParser.class);
51          locationManager = new LocationManager(qdoxParser) {
52              @Override
53              ModuleInfoParser getBinaryModuleInfoParser(Path jdkHome) {
54                  return asmParser;
55              }
56          };
57      }
58  
59      @Test
60      void testNoPaths() throws Exception {
61          ResolvePathsResult<File> result =
62                  locationManager.resolvePaths(ResolvePathsRequest.ofFiles(Collections.emptyList()));
63          assertThat(result.getMainModuleDescriptor()).isNull();
64          assertThat(result.getPathElements()).hasSize(0);
65          assertThat(result.getModulepathElements()).hasSize(0);
66          assertThat(result.getClasspathElements()).hasSize(0);
67          assertThat(result.getPathExceptions()).hasSize(0);
68      }
69  
70      @Test
71      void testWithUnknownRequires() throws Exception {
72          JavaModuleDescriptor descriptor = JavaModuleDescriptor.newModule("base")
73                  .requires("java.base")
74                  .requires("jdk.net")
75                  .build();
76          when(qdoxParser.fromSourcePath(any(Path.class))).thenReturn(descriptor);
77          ResolvePathsRequest<File> request = ResolvePathsRequest.ofFiles(Collections.emptyList())
78                  .setMainModuleDescriptor(mockModuleInfoJava.toFile());
79  
80          ResolvePathsResult<File> result = locationManager.resolvePaths(request);
81  
82          assertThat(result.getMainModuleDescriptor()).isEqualTo(descriptor);
83          assertThat(result.getPathElements()).hasSize(0);
84          assertThat(result.getModulepathElements()).hasSize(0);
85          assertThat(result.getClasspathElements()).hasSize(0);
86          assertThat(result.getPathExceptions()).hasSize(0);
87      }
88  
89      @Test
90      void testManifestWithReflectRequires() throws Exception {
91          Path abc = Paths.get("src/test/resources/dir.manifest.with/out");
92          JavaModuleDescriptor descriptor = JavaModuleDescriptor.newModule("base")
93                  .requires("auto.by.manifest")
94                  .build();
95          when(qdoxParser.fromSourcePath(any(Path.class))).thenReturn(descriptor);
96          ResolvePathsRequest<Path> request =
97                  ResolvePathsRequest.ofPaths(Collections.singletonList(abc)).setMainModuleDescriptor(mockModuleInfoJava);
98  
99          ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
100 
101         assertThat(result.getMainModuleDescriptor()).isEqualTo(descriptor);
102         assertThat(result.getPathElements()).hasSize(1);
103         assertThat(result.getModulepathElements()).hasSize(1);
104         assertThat(result.getModulepathElements().get(abc)).isEqualTo(ModuleNameSource.MANIFEST);
105         assertThat(result.getClasspathElements()).hasSize(0);
106         assertThat(result.getPathExceptions()).hasSize(0);
107     }
108 
109     @Test
110     void testDirDescriptorWithReflectRequires() throws Exception {
111         Path abc = Paths.get("src/test/resources/dir.descriptor/out");
112         JavaModuleDescriptor descriptor = JavaModuleDescriptor.newModule("base")
113                 .requires("dir.descriptor")
114                 .build();
115         when(qdoxParser.fromSourcePath(any(Path.class))).thenReturn(descriptor);
116         ResolvePathsRequest<Path> request =
117                 ResolvePathsRequest.ofPaths(Collections.singletonList(abc)).setMainModuleDescriptor(mockModuleInfoJava);
118 
119         when(asmParser.getModuleDescriptor(abc))
120                 .thenReturn(JavaModuleDescriptor.newModule("dir.descriptor").build());
121 
122         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
123 
124         assertThat(result.getMainModuleDescriptor()).isEqualTo(descriptor);
125         assertThat(result.getPathElements()).hasSize(1);
126         assertThat(result.getModulepathElements()).hasSize(1);
127         assertThat(result.getModulepathElements().get(abc)).isEqualTo(ModuleNameSource.MODULEDESCRIPTOR);
128         assertThat(result.getClasspathElements()).hasSize(0);
129         assertThat(result.getPathExceptions()).hasSize(0);
130     }
131 
132     @Test
133     void testJarWithAsmRequires() throws Exception {
134         Path abc = Paths.get("src/test/resources/jar.descriptor/asm-6.0_BETA.jar");
135         JavaModuleDescriptor descriptor = JavaModuleDescriptor.newModule("base")
136                 .requires("org.objectweb.asm")
137                 .build();
138         when(qdoxParser.fromSourcePath(any(Path.class))).thenReturn(descriptor);
139         ResolvePathsRequest<Path> request =
140                 ResolvePathsRequest.ofPaths(Collections.singletonList(abc)).setMainModuleDescriptor(mockModuleInfoJava);
141 
142         when(asmParser.getModuleDescriptor(abc))
143                 .thenReturn(JavaModuleDescriptor.newModule("org.objectweb.asm").build());
144 
145         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
146         assertThat(result.getMainModuleDescriptor()).isEqualTo(descriptor);
147         assertThat(result.getPathElements()).hasSize(1);
148         assertThat(result.getModulepathElements()).hasSize(1);
149         assertThat(result.getModulepathElements().get(abc)).isEqualTo(ModuleNameSource.MODULEDESCRIPTOR);
150         assertThat(result.getClasspathElements()).hasSize(0);
151         assertThat(result.getPathExceptions()).hasSize(0);
152     }
153 
154     @Test
155     void testIdenticalModuleNames() throws Exception {
156         Path pj1 = Paths.get("src/test/resources/jar.empty/plexus-java-1.0.0-SNAPSHOT.jar");
157         Path pj2 = Paths.get("src/test/resources/jar.empty.2/plexus-java-2.0.0-SNAPSHOT.jar");
158         JavaModuleDescriptor descriptor =
159                 JavaModuleDescriptor.newModule("base").requires("plexus.java").build();
160         when(qdoxParser.fromSourcePath(any(Path.class))).thenReturn(descriptor);
161         ResolvePathsRequest<Path> request =
162                 ResolvePathsRequest.ofPaths(Arrays.asList(pj1, pj2)).setMainModuleDescriptor(mockModuleInfoJava);
163 
164         when(asmParser.getModuleDescriptor(pj1))
165                 .thenReturn(JavaModuleDescriptor.newModule("plexus.java").build());
166         when(asmParser.getModuleDescriptor(pj2))
167                 .thenReturn(JavaModuleDescriptor.newModule("plexus.java").build());
168 
169         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
170 
171         assertThat(result.getMainModuleDescriptor()).isEqualTo(descriptor);
172         assertThat(result.getPathElements()).hasSize(2);
173         assertThat(result.getModulepathElements()).hasSize(1);
174         assertThat(result.getModulepathElements()).containsKey(pj1);
175         assertThat(result.getModulepathElements()).doesNotContainKey(pj2);
176         assertThat(result.getClasspathElements()).isEmpty();
177         // duplicate is flagged as an error
178         assertThat(result.getPathExceptions()).containsOnlyKeys(pj2);
179         assertThat(result.getPathExceptions().get(pj2))
180                 .isInstanceOf(IllegalStateException.class)
181                 .hasMessageContaining("Module 'plexus.java' is already on the module path!");
182     }
183 
184     @Test
185     public void testIdenticalAutomaticModuleNames() throws Exception {
186         Path pj1 = Paths.get("src/test/resources/jar.empty/plexus-java-1.0.0-SNAPSHOT.jar");
187         Path pj2 = Paths.get("src/test/resources/jar.empty.2/plexus-java-2.0.0-SNAPSHOT.jar");
188         JavaModuleDescriptor descriptor =
189                 JavaModuleDescriptor.newModule("base").requires("plexus.java").build();
190         when(qdoxParser.fromSourcePath(any(Path.class))).thenReturn(descriptor);
191         ResolvePathsRequest<Path> request =
192                 ResolvePathsRequest.ofPaths(Arrays.asList(pj1, pj2)).setMainModuleDescriptor(mockModuleInfoJava);
193 
194         when(asmParser.getModuleDescriptor(pj1))
195                 .thenReturn(
196                         JavaModuleDescriptor.newAutomaticModule("plexus.java").build());
197         when(asmParser.getModuleDescriptor(pj2))
198                 .thenReturn(
199                         JavaModuleDescriptor.newAutomaticModule("plexus.java").build());
200 
201         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
202         assertThat(result.getMainModuleDescriptor()).isEqualTo(descriptor);
203         assertThat(result.getPathElements()).hasSize(2);
204         assertThat(result.getModulepathElements()).containsOnlyKeys(pj1);
205         assertThat(result.getModulepathElements()).doesNotContainKey(pj2);
206         assertThat(result.getClasspathElements()).isEmpty();
207         // duplicate is flagged as an error
208         assertThat(result.getPathExceptions()).containsOnlyKeys(pj2);
209         assertThat(result.getPathExceptions().get(pj2))
210                 .isInstanceOf(IllegalStateException.class)
211                 .hasMessageContaining("Module 'plexus.java' is already on the module path!");
212     }
213 
214     @Test
215     public void testMainJarModuleAndTestJarAutomatic() throws Exception {
216         Path pj1 = Paths.get("src/test/resources/jar.tests/plexus-java-1.0.0-SNAPSHOT.jar");
217         Path pj2 = Paths.get("src/test/resources/jar.tests/plexus-java-1.0.0-SNAPSHOT-tests.jar");
218         JavaModuleDescriptor descriptor =
219                 JavaModuleDescriptor.newModule("base").requires("plexus.java").build();
220         when(qdoxParser.fromSourcePath(any(Path.class))).thenReturn(descriptor);
221         ResolvePathsRequest<Path> request =
222                 ResolvePathsRequest.ofPaths(Arrays.asList(pj1, pj2)).setMainModuleDescriptor(mockModuleInfoJava);
223 
224         when(asmParser.getModuleDescriptor(pj1))
225                 .thenReturn(JavaModuleDescriptor.newModule("plexus.java").build());
226         when(asmParser.getModuleDescriptor(pj2)).thenReturn(null);
227 
228         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
229 
230         assertThat(result.getMainModuleDescriptor()).isEqualTo(descriptor);
231         assertThat(result.getPathElements()).hasSize(2);
232         assertThat(result.getModulepathElements()).hasSize(1);
233         assertThat(result.getModulepathElements()).containsKey(pj1);
234         assertThat(result.getModulepathElements()).doesNotContainKey(pj2);
235         assertThat(result.getClasspathElements()).isEmpty();
236 
237         // duplicate is flagged as an error
238         assertThat(result.getPathExceptions()).containsOnlyKeys(pj2);
239         assertThat(result.getPathExceptions().get(pj2))
240                 .isInstanceOf(IllegalStateException.class)
241                 .hasMessageContaining("Module 'plexus.java' is already on the module path!");
242     }
243 
244     @Test
245     void testNonJar() throws Exception {
246         Path p = Paths.get("src/test/resources/nonjar/pom.xml");
247 
248         ResolvePathsRequest<Path> request =
249                 ResolvePathsRequest.ofPaths(Collections.singletonList(p)).setMainModuleDescriptor(mockModuleInfoJava);
250 
251         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
252 
253         assertThat(result.getPathExceptions()).hasSize(1);
254     }
255 
256     @Test
257     void testAdditionalModules() throws Exception {
258         Path p = Paths.get("src/test/resources/mock/jar0.jar");
259 
260         JavaModuleDescriptor descriptor = JavaModuleDescriptor.newModule("base").build();
261         when(qdoxParser.fromSourcePath(any(Path.class))).thenReturn(descriptor);
262         ResolvePathsRequest<Path> request = ResolvePathsRequest.ofPaths(Collections.singletonList(p))
263                 .setMainModuleDescriptor(mockModuleInfoJava)
264                 .setAdditionalModules(Collections.singletonList("plexus.java"));
265 
266         when(asmParser.getModuleDescriptor(p))
267                 .thenReturn(
268                         JavaModuleDescriptor.newAutomaticModule("plexus.java").build());
269 
270         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
271         assertThat(result.getMainModuleDescriptor()).isEqualTo(descriptor);
272         assertThat(result.getPathElements()).hasSize(1);
273         assertThat(result.getModulepathElements()).hasSize(1);
274         assertThat(result.getClasspathElements()).hasSize(0);
275         assertThat(result.getPathExceptions()).hasSize(0);
276     }
277 
278     @Test
279     void testResolvePath() throws Exception {
280         Path abc = Paths.get("src/test/resources/mock/jar0.jar");
281         ResolvePathRequest<Path> request = ResolvePathRequest.ofPath(abc);
282 
283         when(asmParser.getModuleDescriptor(abc))
284                 .thenReturn(JavaModuleDescriptor.newModule("org.objectweb.asm").build());
285 
286         ResolvePathResult result = locationManager.resolvePath(request);
287 
288         assertThat(result.getModuleDescriptor())
289                 .isEqualTo(JavaModuleDescriptor.newModule("org.objectweb.asm").build());
290         assertThat(result.getModuleNameSource()).isEqualTo(ModuleNameSource.MODULEDESCRIPTOR);
291     }
292 
293     @Test
294     void testNoMatchingProviders() throws Exception {
295         Path abc = Paths.get("src/test/resources/mock/module-info.java"); // some file called module-info.java
296         Path def = Paths.get("src/test/resources/mock/jar0.jar"); // any existing file
297         ResolvePathsRequest<Path> request =
298                 ResolvePathsRequest.ofPaths(def).setMainModuleDescriptor(abc).setIncludeAllProviders(true);
299 
300         when(qdoxParser.fromSourcePath(abc))
301                 .thenReturn(JavaModuleDescriptor.newModule("abc").uses("device").build());
302         when(asmParser.getModuleDescriptor(def))
303                 .thenReturn(JavaModuleDescriptor.newModule("def")
304                         .provides("tool", Arrays.asList("java", "javac"))
305                         .build());
306 
307         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
308         assertThat(result.getPathElements()).hasSize(1);
309         assertThat(result.getModulepathElements()).hasSize(0);
310         assertThat(result.getClasspathElements()).hasSize(1);
311         assertThat(result.getPathExceptions()).hasSize(0);
312     }
313 
314     @Test
315     void testMainModuleDescriptorWithProviders() throws Exception {
316         Path abc = Paths.get("src/test/resources/mock/module-info.java"); // some file called module-info.java
317         Path def = Paths.get("src/test/resources/mock/jar0.jar"); // any existing file
318         ResolvePathsRequest<Path> request =
319                 ResolvePathsRequest.ofPaths(def).setMainModuleDescriptor(abc).setIncludeAllProviders(true);
320 
321         when(qdoxParser.fromSourcePath(abc))
322                 .thenReturn(JavaModuleDescriptor.newModule("abc").uses("tool").build());
323         when(asmParser.getModuleDescriptor(def))
324                 .thenReturn(JavaModuleDescriptor.newModule("def")
325                         .provides("tool", Arrays.asList("java", "javac"))
326                         .build());
327 
328         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
329         assertThat(result.getPathElements()).hasSize(1);
330         assertThat(result.getModulepathElements()).hasSize(1);
331         assertThat(result.getClasspathElements()).hasSize(0);
332         assertThat(result.getPathExceptions()).hasSize(0);
333     }
334 
335     @Test
336     void testMainModuleDescriptorWithProvidersDontIncludeProviders() throws Exception {
337         Path abc = Paths.get("src/test/resources/mock/module-info.java"); // some file called module-info.java
338         Path def = Paths.get("src/test/resources/mock/jar0.jar"); // any existing file
339         ResolvePathsRequest<Path> request = ResolvePathsRequest.ofPaths(def).setMainModuleDescriptor(abc);
340 
341         when(qdoxParser.fromSourcePath(abc))
342                 .thenReturn(JavaModuleDescriptor.newModule("abc").uses("tool").build());
343         when(asmParser.getModuleDescriptor(def))
344                 .thenReturn(JavaModuleDescriptor.newModule("def")
345                         .provides("tool", Arrays.asList("java", "javac"))
346                         .build());
347 
348         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
349         assertThat(result.getPathElements()).hasSize(1);
350         assertThat(result.getModulepathElements()).hasSize(0);
351         assertThat(result.getClasspathElements()).hasSize(1);
352         assertThat(result.getPathExceptions()).hasSize(0);
353     }
354 
355     @Test
356     void testTransitiveProviders() throws Exception {
357         Path abc = Paths.get("src/test/resources/mock/module-info.java"); // some file called module-info.java
358         Path def = Paths.get("src/test/resources/mock/jar0.jar"); // any existing file
359         Path ghi = Paths.get("src/test/resources/mock/jar1.jar"); // any existing file
360         ResolvePathsRequest<Path> request = ResolvePathsRequest.ofPaths(def, ghi)
361                 .setMainModuleDescriptor(abc)
362                 .setIncludeAllProviders(true);
363 
364         when(qdoxParser.fromSourcePath(abc))
365                 .thenReturn(
366                         JavaModuleDescriptor.newModule("abc").requires("ghi").build());
367         when(asmParser.getModuleDescriptor(def))
368                 .thenReturn(JavaModuleDescriptor.newModule("def")
369                         .provides("tool", Arrays.asList("java", "javac"))
370                         .build());
371         when(asmParser.getModuleDescriptor(ghi))
372                 .thenReturn(JavaModuleDescriptor.newModule("ghi").uses("tool").build());
373 
374         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
375         assertThat(result.getPathElements()).hasSize(2);
376         assertThat(result.getModulepathElements()).hasSize(2);
377         assertThat(result.getClasspathElements()).hasSize(0);
378         assertThat(result.getPathExceptions()).hasSize(0);
379     }
380 
381     @Test
382     void testDontIncludeProviders() throws Exception {
383         Path abc = Paths.get("src/test/resources/mock/module-info.java"); // some file called module-info.java
384         Path def = Paths.get("src/test/resources/mock/jar0.jar"); // any existing file
385         Path ghi = Paths.get("src/test/resources/mock/jar1.jar"); // any existing file
386         ResolvePathsRequest<Path> request =
387                 ResolvePathsRequest.ofPaths(def, ghi).setMainModuleDescriptor(abc);
388 
389         when(qdoxParser.fromSourcePath(abc))
390                 .thenReturn(
391                         JavaModuleDescriptor.newModule("abc").requires("ghi").build());
392         when(asmParser.getModuleDescriptor(def))
393                 .thenReturn(JavaModuleDescriptor.newModule("def")
394                         .provides("tool", Arrays.asList("java", "javac"))
395                         .build());
396         when(asmParser.getModuleDescriptor(ghi))
397                 .thenReturn(JavaModuleDescriptor.newModule("ghi").uses("tool").build());
398 
399         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
400         assertThat(result.getPathElements()).hasSize(2);
401         assertThat(result.getModulepathElements()).hasSize(1);
402         assertThat(result.getClasspathElements()).hasSize(1);
403         assertThat(result.getPathExceptions()).hasSize(0);
404     }
405 
406     @Test
407     void testAllowAdditionalModulesWithoutMainDescriptor() throws Exception {
408         Path def = Paths.get("src/test/resources/mock/jar0.jar"); // any existing file
409         Path ghi = Paths.get("src/test/resources/mock/jar1.jar"); // any existing file
410         ResolvePathsRequest<Path> request =
411                 ResolvePathsRequest.ofPaths(def, ghi).setAdditionalModules(Collections.singleton("def"));
412 
413         when(asmParser.getModuleDescriptor(def))
414                 .thenReturn(JavaModuleDescriptor.newModule("def").build());
415         when(asmParser.getModuleDescriptor(ghi))
416                 .thenReturn(JavaModuleDescriptor.newModule("ghi").build());
417 
418         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
419         assertThat(result.getPathElements()).hasSize(2);
420         assertThat(result.getModulepathElements()).hasSize(1);
421         assertThat(result.getClasspathElements()).hasSize(1);
422         assertThat(result.getPathExceptions()).hasSize(0);
423     }
424 
425     @Test
426     void testReuseModuleDescriptor() throws Exception {
427         Path def = Paths.get("src/test/resources/mock/jar0.jar");
428 
429         ResolvePathRequest<Path> request1 = ResolvePathRequest.ofPath(def);
430         when(asmParser.getModuleDescriptor(def))
431                 .thenReturn(JavaModuleDescriptor.newModule("def").build());
432 
433         ResolvePathResult result1 = locationManager.resolvePath(request1);
434 
435         ResolvePathsRequest<Path> request2 = ResolvePathsRequest.ofPaths(def);
436         request2.setModuleDescriptor(result1.getModuleDescriptor());
437 
438         ResolvePathsResult<Path> result2 = locationManager.resolvePaths(request2);
439 
440         assertThat(result1.getModuleDescriptor()).isEqualTo(result2.getMainModuleDescriptor());
441     }
442 
443     @Test
444     void testParseModuleDescriptor() throws Exception {
445         Path descriptorPath = Paths.get("src/test/resources/src.dir/module-info.java");
446         when(qdoxParser.fromSourcePath(descriptorPath))
447                 .thenReturn(JavaModuleDescriptor.newModule("a.b.c").build());
448 
449         ResolvePathResult result = locationManager.parseModuleDescriptor(descriptorPath);
450         assertThat(result.getModuleNameSource()).isEqualTo(ModuleNameSource.MODULEDESCRIPTOR);
451         assertThat(result.getModuleDescriptor().name()).isEqualTo("a.b.c");
452 
453         locationManager.parseModuleDescriptor(descriptorPath.toFile());
454         assertThat(result.getModuleNameSource()).isEqualTo(ModuleNameSource.MODULEDESCRIPTOR);
455         assertThat(result.getModuleDescriptor().name()).isEqualTo("a.b.c");
456 
457         locationManager.parseModuleDescriptor(descriptorPath.toString());
458         assertThat(result.getModuleNameSource()).isEqualTo(ModuleNameSource.MODULEDESCRIPTOR);
459         assertThat(result.getModuleDescriptor().name()).isEqualTo("a.b.c");
460     }
461 
462     @Test
463     void testTransitiveStatic() throws Exception {
464         Path moduleA = Paths.get("src/test/resources/mock/module-info.java"); // some file called module-info.java
465         Path moduleB = Paths.get("src/test/resources/mock/jar0.jar"); // any existing file
466         Path moduleC = Paths.get("src/test/resources/mock/jar1.jar"); // any existing file
467         ResolvePathsRequest<Path> request =
468                 ResolvePathsRequest.ofPaths(moduleB, moduleC).setMainModuleDescriptor(moduleA);
469 
470         when(qdoxParser.fromSourcePath(moduleA))
471                 .thenReturn(JavaModuleDescriptor.newModule("moduleA")
472                         .requires("moduleB")
473                         .build());
474         when(asmParser.getModuleDescriptor(moduleB))
475                 .thenReturn(JavaModuleDescriptor.newModule("moduleB")
476                         .requires(Collections.singleton(JavaModifier.STATIC), "moduleC")
477                         .build());
478         when(asmParser.getModuleDescriptor(moduleC))
479                 .thenReturn(JavaModuleDescriptor.newModule("moduleC").build());
480 
481         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
482         assertThat(result.getPathElements()).hasSize(2);
483         assertThat(result.getModulepathElements()).hasSize(1);
484         assertThat(result.getClasspathElements()).hasSize(1);
485         assertThat(result.getPathExceptions()).hasSize(0);
486     }
487 
488     @Test
489     void testDirectStatic() throws Exception {
490         Path moduleA = Paths.get("src/test/resources/mock/module-info.java"); // some file called module-info.java
491         Path moduleB = Paths.get("src/test/resources/mock/jar0.jar"); // any existing file
492         Path moduleC = Paths.get("src/test/resources/mock/jar1.jar"); // any existing file
493         Path moduleD = Paths.get("src/test/resources/mock/jar2.jar"); // any existing file
494         ResolvePathsRequest<Path> request =
495                 ResolvePathsRequest.ofPaths(moduleB, moduleC, moduleD).setMainModuleDescriptor(moduleA);
496         // .setIncludeStatic( true );
497 
498         when(qdoxParser.fromSourcePath(moduleA))
499                 .thenReturn(JavaModuleDescriptor.newModule("moduleA")
500                         .requires("moduleB")
501                         .requires(Collections.singleton(JavaModifier.STATIC), "moduleD")
502                         .build());
503         when(asmParser.getModuleDescriptor(moduleB))
504                 .thenReturn(JavaModuleDescriptor.newModule("moduleB")
505                         .requires(Collections.singleton(JavaModifier.STATIC), "moduleC")
506                         .build());
507         when(asmParser.getModuleDescriptor(moduleC))
508                 .thenReturn(JavaModuleDescriptor.newModule("moduleC").build());
509         when(asmParser.getModuleDescriptor(moduleD))
510                 .thenReturn(JavaModuleDescriptor.newModule("moduleD").build());
511 
512         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
513         assertThat(result.getPathElements()).hasSize(3);
514         assertThat(result.getModulepathElements()).containsOnlyKeys(moduleB, moduleD);
515         assertThat(result.getClasspathElements()).containsOnly(moduleC);
516         assertThat(result.getPathExceptions()).hasSize(0);
517     }
518 
519     @Test
520     void testDuplicateModule() throws Exception {
521         Path moduleA = Paths.get("src/test/resources/mock/module-info.java"); // some file called module-info.java
522         Path moduleB = Paths.get("src/test/resources/mock/jar0.jar"); // any existing file
523         Path moduleC = Paths.get("src/test/resources/mock/jar1.jar"); // any existing file
524 
525         ResolvePathsRequest<Path> request =
526                 ResolvePathsRequest.ofPaths(moduleB, moduleC).setMainModuleDescriptor(moduleA);
527 
528         when(qdoxParser.fromSourcePath(moduleA))
529                 .thenReturn(JavaModuleDescriptor.newModule("moduleA")
530                         .requires("anonymous")
531                         .build());
532         when(asmParser.getModuleDescriptor(moduleB))
533                 .thenReturn(JavaModuleDescriptor.newModule("anonymous").build());
534         when(asmParser.getModuleDescriptor(moduleC))
535                 .thenReturn(JavaModuleDescriptor.newModule("anonymous").build());
536 
537         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
538         assertThat(result.getPathElements()).hasSize(2);
539         assertThat(result.getModulepathElements()).containsOnlyKeys(moduleB);
540         assertThat(result.getClasspathElements()).hasSize(0);
541         assertThat(result.getPathExceptions()).hasSize(1);
542         // duplicate (module B / module C) is flagged as an error
543         assertThat(result.getPathExceptions()).containsOnlyKeys(moduleC);
544         assertThat(result.getPathExceptions().get(moduleC))
545                 .isInstanceOf(IllegalStateException.class)
546                 .hasMessageContaining("Module 'anonymous' is already on the module path!");
547     }
548 
549     @Test
550     void testStaticTransitive() throws Exception {
551         Path moduleA = Paths.get("src/test/resources/mock/module-info.java"); // some file called module-info.java
552         Path moduleB = Paths.get("src/test/resources/mock/jar0.jar"); // any existing file
553         Path moduleC = Paths.get("src/test/resources/mock/jar1.jar"); // any existing file
554         Path moduleD = Paths.get("src/test/resources/mock/jar2.jar"); // any existing file
555         ResolvePathsRequest<Path> request =
556                 ResolvePathsRequest.ofPaths(moduleB, moduleC, moduleD).setMainModuleDescriptor(moduleA);
557 
558         when(qdoxParser.fromSourcePath(moduleA))
559                 .thenReturn(JavaModuleDescriptor.newModule("moduleA")
560                         .requires("moduleB")
561                         .build());
562         when(asmParser.getModuleDescriptor(moduleB))
563                 .thenReturn(JavaModuleDescriptor.newModule("moduleB")
564                         .requires(new HashSet<>(Arrays.asList(JavaModifier.STATIC, JavaModifier.TRANSITIVE)), "moduleC")
565                         .build());
566         when(asmParser.getModuleDescriptor(moduleC))
567                 .thenReturn(JavaModuleDescriptor.newModule("moduleC")
568                         .requires(new HashSet<>(Arrays.asList(JavaModifier.STATIC)), "moduleD")
569                         .build());
570         when(asmParser.getModuleDescriptor(moduleD))
571                 .thenReturn(JavaModuleDescriptor.newModule("moduleD").build());
572 
573         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
574         assertThat(result.getPathElements()).hasSize(3);
575         assertThat(result.getModulepathElements()).containsOnlyKeys(moduleB, moduleC);
576         assertThat(result.getClasspathElements()).containsOnly(moduleD);
577         assertThat(result.getPathExceptions()).hasSize(0);
578     }
579 
580     /**
581      * test case for <a href="https://issues.apache.org/jira/browse/MCOMPILER-481">MCOMPILER-481</a>
582      */
583     @Test
584     void includeDeeperRequiresStatic() throws Exception {
585         Path moduleA = Paths.get("src/test/resources/mock/module-info.java"); // some file called module-info.java
586         Path moduleB = Paths.get("src/test/resources/mock/jar0.jar"); // any existing file
587         Path moduleC = Paths.get("src/test/resources/mock/jar1.jar"); // any existing file
588         ResolvePathsRequest<Path> request = ResolvePathsRequest.ofPaths(moduleA, moduleB, moduleC)
589                 .setMainModuleDescriptor(moduleA)
590                 .setIncludeStatic(true);
591         when(qdoxParser.fromSourcePath(moduleA))
592                 .thenReturn(JavaModuleDescriptor.newModule("moduleA")
593                         .requires("moduleB")
594                         .build());
595         when(asmParser.getModuleDescriptor(moduleB))
596                 .thenReturn(JavaModuleDescriptor.newModule("moduleB")
597                         .requires(Collections.singleton(JavaModifier.STATIC), "moduleC")
598                         .build());
599         when(asmParser.getModuleDescriptor(moduleC))
600                 .thenReturn(JavaModuleDescriptor.newModule("moduleC").build());
601 
602         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
603         assertThat(result.getModulepathElements()).containsOnlyKeys(moduleB, moduleC);
604     }
605 
606     /**
607      * test case for <a href="https://issues.apache.org/jira/browse/MCOMPILER-482">MCOMPILER-482</a>
608      */
609     @Test
610     void includeDeeperRequiresStaticTransitive() throws Exception {
611         Path moduleA = Paths.get("src/test/resources/mock/module-info.java"); // some file called module-info.java core
612         Path moduleB = Paths.get("src/test/resources/mock/jar0.jar"); // any existing file
613         Path moduleC = Paths.get("src/test/resources/mock/jar1.jar"); // any existing file
614         Path moduleD = Paths.get("src/test/resources/mock/jar2.jar"); // any existing file
615         ResolvePathsRequest<Path> request = ResolvePathsRequest.ofPaths(moduleA, moduleB, moduleC, moduleD)
616                 .setMainModuleDescriptor(moduleA)
617                 .setIncludeStatic(true);
618         when(qdoxParser.fromSourcePath(moduleA))
619                 .thenReturn(JavaModuleDescriptor.newModule("moduleA")
620                         .requires("moduleB")
621                         .build());
622         when(asmParser.getModuleDescriptor(moduleB))
623                 .thenReturn(JavaModuleDescriptor.newModule("moduleB")
624                         .requires("moduleC")
625                         .requires(new HashSet<>(Arrays.asList(JavaModifier.STATIC, JavaModifier.TRANSITIVE)), "moduleD")
626                         .build());
627         when(asmParser.getModuleDescriptor(moduleC))
628                 .thenReturn(JavaModuleDescriptor.newModule("moduleC")
629                         .requires(new HashSet<>(Arrays.asList(JavaModifier.STATIC, JavaModifier.TRANSITIVE)), "moduleD")
630                         .build());
631         when(asmParser.getModuleDescriptor(moduleD))
632                 .thenReturn(JavaModuleDescriptor.newModule("moduleD").build());
633 
634         ResolvePathsResult<Path> result = locationManager.resolvePaths(request);
635         assertThat(result.getModulepathElements()).containsOnlyKeys(moduleB, moduleC, moduleD);
636     }
637 }