DefaultPathMatcherFactoryTest.java
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.impl;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.maven.api.services.PathMatcherFactory;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Tests for {@link DefaultPathMatcherFactory}.
*/
public class DefaultPathMatcherFactoryTest {
private final PathMatcherFactory factory = new DefaultPathMatcherFactory();
@Test
public void testCreatePathMatcherWithNullBaseDirectory() {
assertThrows(NullPointerException.class, () -> {
factory.createPathMatcher(null, List.of("**/*.java"), List.of("**/target/**"), false);
});
}
@Test
public void testCreatePathMatcherBasic(@TempDir Path tempDir) throws IOException {
// Create test files
Path srcDir = Files.createDirectories(tempDir.resolve("src/main/java"));
Path testDir = Files.createDirectories(tempDir.resolve("src/test/java"));
Path targetDir = Files.createDirectories(tempDir.resolve("target"));
Files.createFile(srcDir.resolve("Main.java"));
Files.createFile(testDir.resolve("Test.java"));
Files.createFile(targetDir.resolve("compiled.class"));
Files.createFile(tempDir.resolve("README.txt"));
PathMatcher matcher = factory.createPathMatcher(tempDir, List.of("**/*.java"), List.of("**/target/**"), false);
assertNotNull(matcher);
assertTrue(matcher.matches(srcDir.resolve("Main.java")));
assertTrue(matcher.matches(testDir.resolve("Test.java")));
assertFalse(matcher.matches(targetDir.resolve("compiled.class")));
assertFalse(matcher.matches(tempDir.resolve("README.txt")));
}
@Test
public void testCreatePathMatcherWithDefaultExcludes(@TempDir Path tempDir) throws IOException {
// Create test files including SCM files
Path srcDir = Files.createDirectories(tempDir.resolve("src"));
Path gitDir = Files.createDirectories(tempDir.resolve(".git"));
Files.createFile(srcDir.resolve("Main.java"));
Files.createFile(gitDir.resolve("config"));
Files.createFile(tempDir.resolve(".gitignore"));
PathMatcher matcher = factory.createPathMatcher(tempDir, List.of("**/*"), null, true); // Use default excludes
assertNotNull(matcher);
assertTrue(matcher.matches(srcDir.resolve("Main.java")));
assertFalse(matcher.matches(gitDir.resolve("config")));
assertFalse(matcher.matches(tempDir.resolve(".gitignore")));
}
@Test
public void testCreateIncludeOnlyMatcher(@TempDir Path tempDir) throws IOException {
Files.createFile(tempDir.resolve("Main.java"));
Files.createFile(tempDir.resolve("README.txt"));
PathMatcher matcher = factory.createIncludeOnlyMatcher(tempDir, List.of("**/*.java"));
assertNotNull(matcher);
assertTrue(matcher.matches(tempDir.resolve("Main.java")));
assertFalse(matcher.matches(tempDir.resolve("README.txt")));
}
@Test
public void testCreateExcludeOnlyMatcher(@TempDir Path tempDir) throws IOException {
// Create a simple file structure for testing
Files.createFile(tempDir.resolve("included.txt"));
Files.createFile(tempDir.resolve("excluded.txt"));
// Test that the method exists and returns a non-null matcher
PathMatcher matcher = factory.createExcludeOnlyMatcher(tempDir, List.of("excluded.txt"), false);
assertNotNull(matcher);
// Test that files not matching exclude patterns are included
assertTrue(matcher.matches(tempDir.resolve("included.txt")));
// Note: Due to a known issue in PathSelector (fixed in PR #10909),
// exclude-only patterns don't work correctly in the current codebase.
// This test verifies the API exists and basic functionality works.
// Full exclude-only functionality will work once PR #10909 is merged.
}
@Test
public void testCreatePathMatcherDefaultMethod(@TempDir Path tempDir) throws IOException {
Files.createFile(tempDir.resolve("Main.java"));
Files.createFile(tempDir.resolve("Test.java"));
// Test the default method without useDefaultExcludes parameter
PathMatcher matcher = factory.createPathMatcher(tempDir, List.of("**/*.java"), List.of("**/Test.java"));
assertNotNull(matcher);
assertTrue(matcher.matches(tempDir.resolve("Main.java")));
assertFalse(matcher.matches(tempDir.resolve("Test.java")));
}
@Test
public void testIncludesAll(@TempDir Path tempDir) {
PathMatcher matcher = factory.createPathMatcher(tempDir, null, null, false);
// Because no pattern has been specified, simplify to includes all.
// IT must be the same instance, by method contract.
assertSame(factory.includesAll(), matcher);
}
/**
* Test that verifies the factory creates matchers that work correctly with file trees,
* similar to the existing PathSelectorTest.
*/
@Test
public void testFactoryWithFileTree(@TempDir Path directory) throws IOException {
Path foo = Files.createDirectory(directory.resolve("foo"));
Path bar = Files.createDirectory(foo.resolve("bar"));
Path baz = Files.createDirectory(directory.resolve("baz"));
Files.createFile(directory.resolve("root.txt"));
Files.createFile(bar.resolve("leaf.txt"));
Files.createFile(baz.resolve("excluded.txt"));
PathMatcher matcher = factory.createPathMatcher(directory, List.of("**/*.txt"), List.of("baz/**"), false);
Set<Path> filtered =
new HashSet<>(Files.walk(directory).filter(matcher::matches).toList());
String[] expected = {"root.txt", "foo/bar/leaf.txt"};
assertEquals(expected.length, filtered.size());
for (String path : expected) {
assertTrue(filtered.contains(directory.resolve(path)), "Expected path not found: " + path);
}
}
@Test
public void testNullParameterThrowsNPE(@TempDir Path tempDir) {
// Test that null baseDirectory throws NullPointerException
assertThrows(
NullPointerException.class,
() -> factory.createPathMatcher(null, List.of("*.txt"), List.of("*.tmp"), false));
assertThrows(
NullPointerException.class, () -> factory.createPathMatcher(null, List.of("*.txt"), List.of("*.tmp")));
assertThrows(NullPointerException.class, () -> factory.createExcludeOnlyMatcher(null, List.of("*.tmp"), false));
assertThrows(NullPointerException.class, () -> factory.createIncludeOnlyMatcher(null, List.of("*.txt")));
// Test that PathSelector constructor also throws NPE for null directory
assertThrows(
NullPointerException.class, () -> PathSelector.of(null, List.of("*.txt"), List.of("*.tmp"), false));
// Test that deriveDirectoryMatcher throws NPE for null fileMatcher
assertThrows(NullPointerException.class, () -> factory.deriveDirectoryMatcher(null));
}
@Test
public void testDeriveDirectoryMatcher(@TempDir Path tempDir) throws IOException {
// Create directory structure
Path subDir = Files.createDirectory(tempDir.resolve("subdir"));
Path excludedDir = Files.createDirectory(tempDir.resolve("excluded"));
// Test basic functionality - method exists and returns non-null matcher
PathMatcher anyMatcher = factory.createPathMatcher(tempDir, List.of("**/*.txt"), null, false);
PathMatcher dirMatcher = factory.deriveDirectoryMatcher(anyMatcher);
assertNotNull(dirMatcher);
// Basic functionality test - should return a working matcher
assertTrue(dirMatcher.matches(subDir));
assertTrue(dirMatcher.matches(excludedDir));
// Test with matcher that has no directory filtering (null includes/excludes)
PathMatcher allMatcher = factory.createPathMatcher(tempDir, null, null, false);
PathMatcher dirMatcher2 = factory.deriveDirectoryMatcher(allMatcher);
assertNotNull(dirMatcher2);
// Should include all directories when no filtering is possible
assertTrue(dirMatcher2.matches(subDir));
assertTrue(dirMatcher2.matches(excludedDir));
// Test with non-PathSelector matcher (should return INCLUDES_ALL)
PathMatcher customMatcher = path -> true;
PathMatcher dirMatcher3 = factory.deriveDirectoryMatcher(customMatcher);
assertNotNull(dirMatcher3);
// Should include all directories for unknown matcher types
assertTrue(dirMatcher3.matches(subDir));
assertTrue(dirMatcher3.matches(excludedDir));
// Test that the method correctly identifies PathSelector instances
// and calls the appropriate methods (canFilterDirectories, couldHoldSelected)
PathMatcher pathSelectorMatcher = factory.createPathMatcher(tempDir, List.of("*.txt"), List.of("*.tmp"), false);
PathMatcher dirMatcher4 = factory.deriveDirectoryMatcher(pathSelectorMatcher);
assertNotNull(dirMatcher4);
// The exact behavior depends on PathSelector implementation
// We just verify the method works and returns a valid matcher
assertTrue(dirMatcher4.matches(subDir)
|| !dirMatcher4.matches(subDir)); // Always true, just testing it doesn't throw
}
}