View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.maven;
6   
7   import com.google.common.collect.ImmutableList;
8   import java.io.File;
9   import java.nio.charset.StandardCharsets;
10  import java.nio.file.Files;
11  import java.nio.file.Path;
12  import java.util.Collections;
13  import org.apache.maven.model.Build;
14  import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
15  import org.hamcrest.MatcherAssert;
16  import org.hamcrest.Matchers;
17  import org.junit.jupiter.api.Test;
18  import org.junit.jupiter.api.io.TempDir;
19  
20  /**
21   * Test case for {@link DefaultMavenEnvironment} class.
22   * @since 0.8
23   */
24  @SuppressWarnings("PMD.TooManyMethods")
25  final class DefaultMavenEnvironmentTest {
26  
27      /**
28       * DefaultMavenEnvironment can produce list of excludes.
29       */
30      @Test
31      void excludeAllFiles() {
32          final DefaultMavenEnvironment env = new DefaultMavenEnvironment();
33          env.setExcludes(Collections.singletonList("codenarc:**/*.groovy"));
34          MatcherAssert.assertThat(
35              "Excludes should be returned",
36              env.excludes("codenarc"),
37              Matchers.contains("**/*.groovy")
38          );
39      }
40  
41      /**
42       * DefaultMavenEnvironment can produce list of excludes from empty source.
43       */
44      @Test
45      void emptyExclude() {
46          final DefaultMavenEnvironment env = new DefaultMavenEnvironment();
47          env.setExcludes(Collections.<String>emptyList());
48          MatcherAssert.assertThat(
49              "Empty list should be returned",
50              env.excludes("codenarc").iterator().hasNext(),
51              Matchers.is(false)
52          );
53      }
54  
55      /**
56       * DefaultMavenEnvironment can produce list of excludes without excludes.
57       */
58      @Test
59      void noExclude() {
60          MatcherAssert.assertThat(
61              "Excludes should be empty list by default",
62              new DefaultMavenEnvironment().excludes("codenarc")
63                  .iterator().hasNext(),
64              Matchers.is(false)
65          );
66      }
67  
68      /**
69       * DefaultMavenEnvironment can produce list of excludes.
70       */
71      @Test
72      void excludeSomeFiles() {
73          final DefaultMavenEnvironment env = new DefaultMavenEnvironment();
74          env.setExcludes(
75              ImmutableList.<String>builder()
76                  .add("codenarc:**/src/ex1/Main.groovy")
77                  .add("codenarc:**/src/ex2/Main2.groovy")
78                  .build()
79          );
80          MatcherAssert.assertThat(
81              "Excludes should be returned as list",
82              env.excludes("codenarc"),
83              Matchers.containsInAnyOrder(
84                  "**/src/ex1/Main.groovy",
85                  "**/src/ex2/Main2.groovy"
86              )
87          );
88      }
89  
90      /**
91       * DefaultMavenEnvironment can work with whitespaces in classpath.
92       * @throws Exception If something wrong happens inside
93       */
94      @Test
95      void passPathsWithWhitespaces() throws Exception {
96          final DefaultMavenEnvironment env = new DefaultMavenEnvironment();
97          final MavenProjectStub project = new MavenProjectStub();
98          project.setRuntimeClasspathElements(
99              Collections.singletonList("/Users/Carlos Miranda/git")
100         );
101         project.setDependencyArtifacts(Collections.emptySet());
102         env.setProject(project);
103         MatcherAssert.assertThat(
104             "ClassPath should be returned",
105             env.classloader(),
106             Matchers.notNullValue()
107         );
108     }
109 
110     /**
111      * DefaultMavenEnvironment can produce empty collection when no matches
112      * with checker.
113      */
114     @Test
115     void producesEmptyExcludesWhenNoMatches() {
116         final DefaultMavenEnvironment env = new DefaultMavenEnvironment();
117         env.setExcludes(
118             ImmutableList.of(
119                 "checkstyle:**/src/ex1/Main.groovy",
120                 "pmd:**/src/ex2/Main2.groovy"
121             )
122         );
123         MatcherAssert.assertThat(
124             "Exclude dependencies should be empty",
125             env.excludes("dependencies"),
126             Matchers.empty()
127         );
128     }
129 
130     /**
131      * DefaultMavenEnvironment.files() should silently drop binary files so
132      * that validators never try to read them as text
133      * (see <a href="https://github.com/yegor256/qulice/issues/1264">
134      * issue #1264</a>).
135      * @param basedir Temporary base directory
136      * @throws Exception If something wrong happens inside
137      */
138     @Test
139     void skipsBinaryFilesWhenListing(@TempDir final Path basedir)
140         throws Exception {
141         final Path src = basedir.resolve("src/main/java");
142         Files.createDirectories(src);
143         final Path source = src.resolve("Foo.java");
144         Files.writeString(
145             source,
146             "class Foo {}".concat(String.valueOf('\n')),
147             StandardCharsets.UTF_8
148         );
149         final Path image = basedir.resolve("src/main/resources/pixel.png");
150         Files.createDirectories(image.getParent());
151         Files.write(
152             image,
153             new byte[] {
154                 (byte) 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
155                 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
156             }
157         );
158         final DefaultMavenEnvironment env = new DefaultMavenEnvironment();
159         env.setProject(
160             new MavenProjectStub() {
161                 @Override
162                 public File getBasedir() {
163                     return basedir.toFile();
164                 }
165             }
166         );
167         MatcherAssert.assertThat(
168             "Binary files cannot leak into the list of files to validate",
169             env.files("*.*"),
170             Matchers.allOf(
171                 Matchers.hasItem(source.toFile()),
172                 Matchers.not(Matchers.hasItem(image.toFile()))
173             )
174         );
175     }
176 
177     /**
178      * DefaultMavenEnvironment.files() should honor a non-default
179      * {@code <sourceDirectory>} declared in the POM
180      * (see <a href="https://github.com/yegor256/qulice/issues/382">
181      * issue #382</a>).
182      * @param basedir Temporary base directory
183      * @throws Exception If something wrong happens inside
184      */
185     @Test
186     void respectsCustomSourceDirectory(@TempDir final Path basedir)
187         throws Exception {
188         final Path sources = basedir.resolve("sources");
189         Files.createDirectories(sources);
190         final Path source = sources.resolve("Foo.java");
191         Files.writeString(
192             source,
193             "class Foo {}".concat(String.valueOf('\n')),
194             StandardCharsets.UTF_8
195         );
196         final DefaultMavenEnvironment env = new DefaultMavenEnvironment();
197         final MavenProjectStub project = new MavenProjectStub() {
198             @Override
199             public File getBasedir() {
200                 return basedir.toFile();
201             }
202         };
203         project.addCompileSourceRoot(sources.toAbsolutePath().toString());
204         env.setProject(project);
205         MatcherAssert.assertThat(
206             "Files under custom sourceDirectory should be found",
207             env.files("*.*"),
208             Matchers.hasItem(source.toFile())
209         );
210     }
211 
212     /**
213      * DefaultMavenEnvironment.files() should honor a non-default
214      * {@code <testSourceDirectory>} declared in the POM
215      * (see <a href="https://github.com/yegor256/qulice/issues/382">
216      * issue #382</a>).
217      * @param basedir Temporary base directory
218      * @throws Exception If something wrong happens inside
219      */
220     @Test
221     void respectsCustomTestSourceDirectory(@TempDir final Path basedir)
222         throws Exception {
223         final Path tests = basedir.resolve("tests");
224         Files.createDirectories(tests);
225         final Path test = tests.resolve("FooTest.java");
226         Files.writeString(
227             test,
228             "class FooTest {}".concat(String.valueOf('\n')),
229             StandardCharsets.UTF_8
230         );
231         final DefaultMavenEnvironment env = new DefaultMavenEnvironment();
232         final MavenProjectStub project = new MavenProjectStub() {
233             @Override
234             public File getBasedir() {
235                 return basedir.toFile();
236             }
237         };
238         project.addTestCompileSourceRoot(tests.toAbsolutePath().toString());
239         env.setProject(project);
240         MatcherAssert.assertThat(
241             "Files under custom testSourceDirectory should be found",
242             env.files("*.*"),
243             Matchers.hasItem(test.toFile())
244         );
245     }
246 
247     /**
248      * DefaultMavenEnvironment.files() should honor directories declared in
249      * {@code <resources>} blocks of the POM
250      * (see <a href="https://github.com/yegor256/qulice/issues/382">
251      * issue #382</a>).
252      * @param basedir Temporary base directory
253      * @throws Exception If something wrong happens inside
254      */
255     @Test
256     void respectsCustomResourcesDirectory(@TempDir final Path basedir)
257         throws Exception {
258         final Path assets = basedir.resolve("assets");
259         Files.createDirectories(assets);
260         final Path asset = assets.resolve("config.xml");
261         Files.writeString(
262             asset,
263             "<config/>".concat(String.valueOf('\n')),
264             StandardCharsets.UTF_8
265         );
266         final Build build = new Build();
267         final org.apache.maven.model.Resource resource =
268             new org.apache.maven.model.Resource();
269         resource.setDirectory(assets.toAbsolutePath().toString());
270         build.addResource(resource);
271         final DefaultMavenEnvironment env = new DefaultMavenEnvironment();
272         env.setProject(
273             new MavenProjectStub() {
274                 @Override
275                 public File getBasedir() {
276                     return basedir.toFile();
277                 }
278 
279                 @Override
280                 public Build getBuild() {
281                     return build;
282                 }
283             }
284         );
285         MatcherAssert.assertThat(
286             "Files under declared resources directory should be found",
287             env.files("*.*"),
288             Matchers.hasItem(asset.toFile())
289         );
290     }
291 
292     /**
293      * Default source files encoding should be UFT-8.
294      */
295     @Test
296     void defaultEncodingIsUtf() {
297         MatcherAssert.assertThat(
298             "Default encoding should be UTF-8",
299             new DefaultMavenEnvironment().encoding(),
300             Matchers.is(StandardCharsets.UTF_8)
301         );
302     }
303 
304     /**
305      * DefaultMavenEnvironment.files() should ignore source roots that live
306      * under the project's build directory, since those are generated build
307      * outputs (e.g. target/generated-sources/...) and not user-authored code
308      * (see <a href="https://github.com/yegor256/qulice/issues/1560">
309      * issue #1560</a>).
310      * @param basedir Temporary base directory
311      * @throws Exception If something wrong happens inside
312      */
313     @Test
314     void skipsSourcesUnderBuildDirectory(@TempDir final Path basedir)
315         throws Exception {
316         final Path src = basedir.resolve("src/main/java");
317         Files.createDirectories(src);
318         final Path source = src.resolve("Foo.java");
319         Files.writeString(
320             source,
321             "class Foo {}".concat(String.valueOf('\n')),
322             StandardCharsets.UTF_8
323         );
324         final Path generated = basedir.resolve(
325             "target/generated-sources/plugin/com/example"
326         );
327         Files.createDirectories(generated);
328         final Path help = generated.resolve("HelpMojo.java");
329         Files.writeString(
330             help,
331             "class HelpMojo {}".concat(String.valueOf('\n')),
332             StandardCharsets.UTF_8
333         );
334         final Build build = new Build();
335         build.setDirectory(
336             basedir.resolve("target").toAbsolutePath().toString()
337         );
338         final DefaultMavenEnvironment env = new DefaultMavenEnvironment();
339         final MavenProjectStub project = new MavenProjectStub() {
340             @Override
341             public File getBasedir() {
342                 return basedir.toFile();
343             }
344 
345             @Override
346             public Build getBuild() {
347                 return build;
348             }
349         };
350         project.addCompileSourceRoot(src.toAbsolutePath().toString());
351         project.addCompileSourceRoot(
352             generated.toAbsolutePath().toString()
353         );
354         env.setProject(project);
355         MatcherAssert.assertThat(
356             "Generated sources under target/ must not be returned",
357             env.files("*.java"),
358             Matchers.allOf(
359                 Matchers.hasItem(source.toFile()),
360                 Matchers.not(Matchers.hasItem(help.toFile()))
361             )
362         );
363     }
364 }