This is an automated email from the ASF dual-hosted git repository. joerghoh pushed a commit to branch SLING-13379 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-api.git
commit 1a8db762b2ef5b70b5c4bedbe65178e275d51cbf Author: Joerg Hoh <[email protected]> AuthorDate: Wed Oct 7 19:16:30 2026 +0200 SLING-13379 PathSet.optimize can loose coverage --- .../apache/sling/api/resource/path/PathSet.java | 11 ++++-- .../sling/api/resource/path/package-info.java | 2 +- .../sling/api/resource/path/PathSetTest.java | 43 ++++++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/apache/sling/api/resource/path/PathSet.java b/src/main/java/org/apache/sling/api/resource/path/PathSet.java index 3bb6324..3027fb0 100644 --- a/src/main/java/org/apache/sling/api/resource/path/PathSet.java +++ b/src/main/java/org/apache/sling/api/resource/path/PathSet.java @@ -91,17 +91,22 @@ public class PathSet implements Iterable<Path> { } /** - * Optimize the set by filtering out paths which are a sub path - * of another path in the set. + * Optimize the set by filtering out concrete paths which are a sub path + * of another concrete path in the set. Entries involving glob patterns + * are retained: matching a subtree root does not imply covering its + * descendants, and matching a pattern argument only establishes overlap. * @param set The path set */ private static void optimize(final Set<Path> set) { final Iterator<Path> i = set.iterator(); while (i.hasNext()) { final Path next = i.next(); + if (next.isPattern()) { + continue; + } boolean found = false; for (final Path p : set) { - if (p != next && p.matches(next.getPath())) { + if (p != next && !p.isPattern() && p.matches(next.getPath())) { found = true; break; } diff --git a/src/main/java/org/apache/sling/api/resource/path/package-info.java b/src/main/java/org/apache/sling/api/resource/path/package-info.java index 6097af1..5de1514 100644 --- a/src/main/java/org/apache/sling/api/resource/path/package-info.java +++ b/src/main/java/org/apache/sling/api/resource/path/package-info.java @@ -17,7 +17,7 @@ * under the License. */ -@Version("1.2.2") +@Version("1.2.3") package org.apache.sling.api.resource.path; import org.osgi.annotation.versioning.Version; diff --git a/src/test/java/org/apache/sling/api/resource/path/PathSetTest.java b/src/test/java/org/apache/sling/api/resource/path/PathSetTest.java index 734eadd..3950567 100644 --- a/src/test/java/org/apache/sling/api/resource/path/PathSetTest.java +++ b/src/test/java/org/apache/sling/api/resource/path/PathSetTest.java @@ -18,6 +18,7 @@ */ package org.apache.sling.api.resource.path; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -91,6 +92,48 @@ public class PathSetTest { assertEqualSets(set2, "/a", "/z", "/a2", "/x/y"); } + private PathSet[] createPathSets(final String first, final String second) { + final Path firstPath = new Path(first); + final Path secondPath = new Path(second); + return new PathSet[] { + PathSet.fromStrings(first, second), + PathSet.fromStrings(second, first), + PathSet.fromStringCollection(Arrays.asList(first, second)), + PathSet.fromPaths(firstPath, secondPath), + PathSet.fromPathCollection(Arrays.asList(firstPath, secondPath)) + }; + } + + @Test + public void testOptimizeDoesNotDropPathOverlappingWithGlob() { + for (final PathSet set : createPathSets("glob:/apps/*", "/apps/foo")) { + assertEqualSets(set, "glob:/apps/*", "/apps/foo"); + assertNotNull(set.matches("/apps/foo/bar")); + assertNotNull(set.matches("/apps/foo/bar/baz")); + assertNotNull(set.matches("/apps/other")); + assertNull(set.matches("/apps/other/bar")); + } + } + + @Test + public void testOptimizeDoesNotDropGlobOverlappingWithPath() { + for (final PathSet set : createPathSets("/apps/foo", "glob:/apps/**/hello.html")) { + assertEqualSets(set, "/apps/foo", "glob:/apps/**/hello.html"); + assertNotNull(set.matches("/apps/foo/bar")); + assertNotNull(set.matches("/apps/bar/hello.html")); + assertNull(set.matches("/apps/bar/other.html")); + } + } + + @Test + public void testOptimizeStillRemovesPlainSubPaths() { + for (final PathSet set : createPathSets("/a", "/a/b")) { + assertEqualSets(set, "/a"); + assertNotNull(set.matches("/a/b/c")); + assertNull(set.matches("/a2")); + } + } + @Test public void testMatching() { final PathSet set = PathSet.fromStrings("/a", "/x/y");
