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");

Reply via email to