Support optional trailing separator on path pattern matching
This commit adds the ability for path patterns to automatically match a trailing separator (so there is no need to add two variants of a pattern, one with and one without). This behaviour is currently turned off but a simple tweak in PathPatternParser can make it the default. If made default other parts of Spring may need altering (simplifying hopefully) to cope with this. Issue: SPR-15260
This commit is contained in:
@@ -38,6 +38,198 @@ import static org.junit.Assert.*;
|
||||
*/
|
||||
public class PathPatternMatcherTests {
|
||||
|
||||
@Test
|
||||
public void basicMatching() {
|
||||
checkMatches(null, null);
|
||||
checkMatches("", "");
|
||||
checkMatches("", null);
|
||||
checkNoMatch("/abc", null);
|
||||
checkMatches(null, "");
|
||||
checkNoMatch(null, "/abc");
|
||||
checkMatches("/", "/");
|
||||
checkNoMatch("/", "/a");
|
||||
checkMatches("f", "f");
|
||||
checkMatches("/foo", "/foo");
|
||||
checkMatches("/foo/", "/foo/");
|
||||
checkMatches("/foo/bar", "/foo/bar");
|
||||
checkMatches("foo/bar", "foo/bar");
|
||||
checkMatches("/foo/bar/", "/foo/bar/");
|
||||
checkMatches("foo/bar/", "foo/bar/");
|
||||
checkMatches("/foo/bar/woo", "/foo/bar/woo");
|
||||
checkNoMatch("foo", "foobar");
|
||||
checkMatches("/foo/bar", "/foo/bar");
|
||||
checkNoMatch("/foo/bar", "/foo/baz");
|
||||
// TODO Need more tests for escaped separators in path patterns and paths?
|
||||
checkMatches("/foo\\/bar", "/foo\\/bar"); // chain string is Separator(/) Literal(foo\) Separator(/) Literal(bar)
|
||||
}
|
||||
|
||||
@Test
|
||||
public void optionalTrailingSeparators() {
|
||||
// LiteralPathElement
|
||||
PathPattern pp = parse("/resource");
|
||||
assertTrue(pp.matches("/resource"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
pp = parse("/resource/");
|
||||
assertFalse(pp.matches("/resource"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
|
||||
// SingleCharWildcardPathElement
|
||||
pp = parse("/res?urce");
|
||||
assertTrue(pp.matches("/resource"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
pp = parse("/res?urce/");
|
||||
assertFalse(pp.matches("/resource"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
|
||||
// CaptureVariablePathElement
|
||||
pp = parse("/{var}");
|
||||
assertTrue(pp.matches("/resource"));
|
||||
assertEquals("resource",pp.matchAndExtract("/resource").get("var"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertEquals("resource",pp.matchAndExtract("/resource/").get("var"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
pp = parse("/{var}/");
|
||||
assertFalse(pp.matches("/resource"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertEquals("resource",pp.matchAndExtract("/resource/").get("var"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
|
||||
// CaptureTheRestPathElement
|
||||
pp = parse("/{*var}");
|
||||
assertTrue(pp.matches("/resource"));
|
||||
assertEquals("/resource",pp.matchAndExtract("/resource").get("var"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertEquals("/resource/",pp.matchAndExtract("/resource/").get("var"));
|
||||
assertTrue(pp.matches("/resource//"));
|
||||
assertEquals("/resource//",pp.matchAndExtract("/resource//").get("var"));
|
||||
assertTrue(pp.matches("//resource//"));
|
||||
assertEquals("//resource//",pp.matchAndExtract("//resource//").get("var"));
|
||||
|
||||
// WildcardTheRestPathElement
|
||||
pp = parse("/**");
|
||||
assertTrue(pp.matches("/resource"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertTrue(pp.matches("/resource//"));
|
||||
assertTrue(pp.matches("//resource//"));
|
||||
|
||||
// WildcardPathElement
|
||||
pp = parse("/*");
|
||||
assertTrue(pp.matches("/resource"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
pp = parse("/*/");
|
||||
assertFalse(pp.matches("/resource"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
|
||||
// RegexPathElement
|
||||
pp = parse("/{var1}_{var2}");
|
||||
assertTrue(pp.matches("/res1_res2"));
|
||||
assertEquals("res1",pp.matchAndExtract("/res1_res2").get("var1"));
|
||||
assertEquals("res2",pp.matchAndExtract("/res1_res2").get("var2"));
|
||||
assertTrue(pp.matches("/res1_res2/"));
|
||||
assertEquals("res1",pp.matchAndExtract("/res1_res2/").get("var1"));
|
||||
assertEquals("res2",pp.matchAndExtract("/res1_res2/").get("var2"));
|
||||
assertFalse(pp.matches("/res1_res2//"));
|
||||
pp = parse("/{var1}_{var2}/");
|
||||
assertFalse(pp.matches("/res1_res2"));
|
||||
assertTrue(pp.matches("/res1_res2/"));
|
||||
assertEquals("res1",pp.matchAndExtract("/res1_res2/").get("var1"));
|
||||
assertEquals("res2",pp.matchAndExtract("/res1_res2/").get("var2"));
|
||||
assertFalse(pp.matches("/res1_res2//"));
|
||||
pp = parse("/{var1}*");
|
||||
assertTrue(pp.matches("/a"));
|
||||
assertTrue(pp.matches("/a/"));
|
||||
assertFalse(pp.matches("/")); // no characters for var1
|
||||
assertFalse(pp.matches("//")); // no characters for var1
|
||||
|
||||
// Now with trailing matching turned OFF
|
||||
PathPatternParser parser = new PathPatternParser();
|
||||
parser.setMatchOptionalTrailingSlash(false);
|
||||
// LiteralPathElement
|
||||
pp = parser.parse("/resource");
|
||||
assertTrue(pp.matches("/resource"));
|
||||
assertFalse(pp.matches("/resource/"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
pp = parser.parse("/resource/");
|
||||
assertFalse(pp.matches("/resource"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
|
||||
// SingleCharWildcardPathElement
|
||||
pp = parser.parse("/res?urce");
|
||||
assertTrue(pp.matches("/resource"));
|
||||
assertFalse(pp.matches("/resource/"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
pp = parser.parse("/res?urce/");
|
||||
assertFalse(pp.matches("/resource"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
|
||||
// CaptureVariablePathElement
|
||||
pp = parser.parse("/{var}");
|
||||
assertTrue(pp.matches("/resource"));
|
||||
assertEquals("resource",pp.matchAndExtract("/resource").get("var"));
|
||||
assertFalse(pp.matches("/resource/"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
pp = parser.parse("/{var}/");
|
||||
assertFalse(pp.matches("/resource"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertEquals("resource",pp.matchAndExtract("/resource/").get("var"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
|
||||
// CaptureTheRestPathElement
|
||||
pp = parser.parse("/{*var}");
|
||||
assertTrue(pp.matches("/resource"));
|
||||
assertEquals("/resource",pp.matchAndExtract("/resource").get("var"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertEquals("/resource/",pp.matchAndExtract("/resource/").get("var"));
|
||||
assertTrue(pp.matches("/resource//"));
|
||||
assertEquals("/resource//",pp.matchAndExtract("/resource//").get("var"));
|
||||
assertTrue(pp.matches("//resource//"));
|
||||
assertEquals("//resource//",pp.matchAndExtract("//resource//").get("var"));
|
||||
|
||||
// WildcardTheRestPathElement
|
||||
pp = parser.parse("/**");
|
||||
assertTrue(pp.matches("/resource"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertTrue(pp.matches("/resource//"));
|
||||
assertTrue(pp.matches("//resource//"));
|
||||
|
||||
// WildcardPathElement
|
||||
pp = parser.parse("/*");
|
||||
assertTrue(pp.matches("/resource"));
|
||||
assertFalse(pp.matches("/resource/"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
pp = parser.parse("/*/");
|
||||
assertFalse(pp.matches("/resource"));
|
||||
assertTrue(pp.matches("/resource/"));
|
||||
assertFalse(pp.matches("/resource//"));
|
||||
|
||||
// RegexPathElement
|
||||
pp = parser.parse("/{var1}_{var2}");
|
||||
assertTrue(pp.matches("/res1_res2"));
|
||||
assertEquals("res1",pp.matchAndExtract("/res1_res2").get("var1"));
|
||||
assertEquals("res2",pp.matchAndExtract("/res1_res2").get("var2"));
|
||||
assertFalse(pp.matches("/res1_res2/"));
|
||||
assertFalse(pp.matches("/res1_res2//"));
|
||||
pp = parser.parse("/{var1}_{var2}/");
|
||||
assertFalse(pp.matches("/res1_res2"));
|
||||
assertTrue(pp.matches("/res1_res2/"));
|
||||
assertEquals("res1",pp.matchAndExtract("/res1_res2/").get("var1"));
|
||||
assertEquals("res2",pp.matchAndExtract("/res1_res2/").get("var2"));
|
||||
assertFalse(pp.matches("/res1_res2//"));
|
||||
pp = parser.parse("/{var1}*");
|
||||
assertTrue(pp.matches("/a"));
|
||||
assertFalse(pp.matches("/a/"));
|
||||
assertFalse(pp.matches("/")); // no characters for var1
|
||||
assertFalse(pp.matches("//")); // no characters for var1
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pathRemainderBasicCases_spr15336() {
|
||||
// Cover all PathElement kinds
|
||||
@@ -92,31 +284,6 @@ public class PathPatternMatcherTests {
|
||||
assertNull(parse("").getPathRemaining(null).getPathRemaining());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicMatching() {
|
||||
checkMatches(null, null);
|
||||
checkMatches("", "");
|
||||
checkMatches("", null);
|
||||
checkNoMatch("/abc", null);
|
||||
checkMatches(null, "");
|
||||
checkNoMatch(null, "/abc");
|
||||
checkMatches("/", "/");
|
||||
checkNoMatch("/", "/a");
|
||||
checkMatches("f", "f");
|
||||
checkMatches("/foo", "/foo");
|
||||
checkMatches("/foo/", "/foo/");
|
||||
checkMatches("/foo/bar", "/foo/bar");
|
||||
checkMatches("foo/bar", "foo/bar");
|
||||
checkMatches("/foo/bar/", "/foo/bar/");
|
||||
checkMatches("foo/bar/", "foo/bar/");
|
||||
checkMatches("/foo/bar/woo", "/foo/bar/woo");
|
||||
checkNoMatch("foo", "foobar");
|
||||
checkMatches("/foo/bar", "/foo/bar");
|
||||
checkNoMatch("/foo/bar", "/foo/baz");
|
||||
// TODO Need more tests for escaped separators in path patterns and paths?
|
||||
checkMatches("/foo\\/bar", "/foo\\/bar"); // chain string is Separator(/) Literal(foo\) Separator(/) Literal(bar)
|
||||
}
|
||||
|
||||
@Test
|
||||
public void questionMarks() {
|
||||
checkNoMatch("a", "ab");
|
||||
@@ -144,38 +311,62 @@ public class PathPatternMatcherTests {
|
||||
checkCapture("/customer/{*something}", "/customer/aa/bb/cc", "something",
|
||||
"/aa/bb/cc");
|
||||
checkCapture("/customer/{*something}", "/customer/", "something", "/");
|
||||
checkCapture("/customer/////{*something}", "/customer/", "something", "/");
|
||||
checkCapture("/customer/{*something}", "/customer//////99", "something", "/99");
|
||||
checkCapture("/customer///{*something}", "/customer//////99", "something", "/99");
|
||||
checkCapture("/customer/////{*something}", "/customer/////", "something", "/");
|
||||
checkCapture("/customer/////{*something}", "/customer//////", "something", "//");
|
||||
checkCapture("/customer//////{*something}", "/customer//////99", "something", "/99");
|
||||
checkCapture("/customer//////{*something}", "/customer//////99", "something", "/99");
|
||||
checkCapture("/customer/{*something}", "/customer", "something", "");
|
||||
checkCapture("/{*something}", "", "something", "");
|
||||
checkCapture("/customer/{*something}", "/customer//////99", "something", "//////99");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleSelectorsInPattern() {
|
||||
checkMatches("///abc", "/abc");
|
||||
checkMatches("//", "/");
|
||||
checkMatches("abc", "abc");
|
||||
checkMatches("///abc//d/e", "/abc/d/e");
|
||||
checkMatches("///abc//{def}//////xyz", "/abc/foo/xyz");
|
||||
public void multipleSeparatorsInPattern() {
|
||||
PathPattern pp = parse("a//b//c");
|
||||
assertEquals("Literal(a) Separator(/) Separator(/) Literal(b) Separator(/) Separator(/) Literal(c)",pp.toChainString());
|
||||
assertTrue(pp.matches("a//b//c"));
|
||||
assertEquals("Literal(a) Separator(/) WildcardTheRest(/**)",parse("a//**").toChainString());
|
||||
checkMatches("///abc", "///abc");
|
||||
checkNoMatch("///abc", "/abc");
|
||||
checkNoMatch("//", "/");
|
||||
checkMatches("//", "//");
|
||||
checkNoMatch("///abc//d/e", "/abc/d/e");
|
||||
checkMatches("///abc//d/e", "///abc//d/e");
|
||||
checkNoMatch("///abc//{def}//////xyz", "/abc/foo/xyz");
|
||||
checkMatches("///abc//{def}//////xyz", "///abc//p//////xyz");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleSelectorsInPath() {
|
||||
checkMatches("/abc", "////abc");
|
||||
checkMatches("/", "//");
|
||||
checkMatches("/abc//def///ghi", "/abc/def/ghi");
|
||||
checkNoMatch("/abc", "////abc");
|
||||
checkNoMatch("/", "//");
|
||||
checkNoMatch("/abc/def/ghi", "/abc//def///ghi");
|
||||
checkNoMatch("/abc", "////abc");
|
||||
checkMatches("////abc", "////abc");
|
||||
checkNoMatch("/", "//");
|
||||
checkNoMatch("/abc//def///ghi", "/abc/def/ghi");
|
||||
checkMatches("/abc//def///ghi", "/abc//def///ghi");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleSelectorsInPatternAndPath() {
|
||||
checkMatches("///one///two///three", "//one/////two///////three");
|
||||
checkMatches("//one//two//three", "/one/////two/three");
|
||||
checkCapture("///{foo}///bar", "/one/bar", "foo", "one");
|
||||
public void multipleSeparatorsInPatternAndPath() {
|
||||
checkNoMatch("///one///two///three", "//one/////two///////three");
|
||||
checkMatches("//one/////two///////three", "//one/////two///////three");
|
||||
checkNoMatch("//one//two//three", "/one/////two/three");
|
||||
checkMatches("/one/////two/three", "/one/////two/three");
|
||||
checkCapture("///{foo}///bar", "///one///bar", "foo", "one");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void wildcards() {
|
||||
checkMatches("/*/bar", "/foo/bar");
|
||||
checkNoMatch("/*/bar", "/foo/baz");
|
||||
checkNoMatch("/*/bar", "//bar");
|
||||
checkMatches("/f*/bar", "/foo/bar");
|
||||
checkMatches("/*/bar", "/foo/bar");
|
||||
checkMatches("a/*","a/");
|
||||
|
||||
checkMatches("/*","/");
|
||||
checkMatches("/*/bar", "/foo/bar");
|
||||
checkNoMatch("/*/bar", "/foo/baz");
|
||||
checkMatches("/f*/bar", "/foo/bar");
|
||||
@@ -183,20 +374,19 @@ public class PathPatternMatcherTests {
|
||||
checkMatches("/a*b*c*d/bar", "/abcd/bar");
|
||||
checkMatches("*a*", "testa");
|
||||
checkMatches("a/*", "a/");
|
||||
checkNoMatch("a/*", "a//"); // trailing slash, so is allowed
|
||||
checkMatches("a/*", "a/a/"); // trailing slash, so is allowed
|
||||
PathPatternParser ppp = new PathPatternParser();
|
||||
ppp.setMatchOptionalTrailingSlash(false);
|
||||
assertFalse(ppp.parse("a/*").matches("a//"));
|
||||
checkMatches("a/*", "a/a");
|
||||
checkNoMatch("a/*", "a/a/");
|
||||
|
||||
checkMatches("a/*", "a/a/"); // trailing slash is optional
|
||||
checkMatches("/resource/**", "/resource");
|
||||
checkNoMatch("/resource/**", "/resourceX");
|
||||
checkNoMatch("/resource/**", "/resourceX/foobar");
|
||||
checkMatches("/resource/**", "/resource/foobar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trailingSeparators() {
|
||||
checkNoMatch("aaa/", "aaa");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constrainedMatches() {
|
||||
checkCapture("{foo:[0-9]*}", "123", "foo", "123");
|
||||
@@ -246,7 +436,8 @@ public class PathPatternMatcherTests {
|
||||
checkMatches("test*aaa", "testblaaaa");
|
||||
checkNoMatch("test*", "tst");
|
||||
checkNoMatch("test*", "tsttest");
|
||||
checkNoMatch("test*", "test/");
|
||||
checkMatches("test*", "test/"); // trailing slash is optional
|
||||
checkMatches("test*", "test"); // trailing slash is optional
|
||||
checkNoMatch("test*", "test/t");
|
||||
checkNoMatch("test/*", "test");
|
||||
checkNoMatch("*test*", "tsttst");
|
||||
@@ -265,8 +456,6 @@ public class PathPatternMatcherTests {
|
||||
|
||||
checkMatches("/**", "");
|
||||
checkMatches("/books/**", "/books");
|
||||
checkMatches("/books////**", "/books");
|
||||
checkMatches("/books////**", "/books////");
|
||||
checkMatches("/**", "/testing/testing");
|
||||
checkMatches("/*/**", "/testing/testing");
|
||||
checkMatches("/bla*bla/test", "/blaXXXbla/test");
|
||||
@@ -314,6 +503,12 @@ public class PathPatternMatcherTests {
|
||||
|
||||
@Test
|
||||
public void matchStart() {
|
||||
checkStartNoMatch("test/*/","test//");
|
||||
checkStartMatches("test/*","test/abc");
|
||||
checkStartMatches("test/*/def","test/abc/def");
|
||||
checkStartNoMatch("test/*/def","test//");
|
||||
checkStartNoMatch("test/*/def","test//def");
|
||||
|
||||
checkStartMatches("test/{a}_{b}/foo", "test/a_b");
|
||||
checkStartMatches("test/?/abc", "test/a");
|
||||
checkStartMatches("test/{*foobar}", "test/");
|
||||
@@ -357,7 +552,8 @@ public class PathPatternMatcherTests {
|
||||
checkStartMatches("*.*", "test.test.test");
|
||||
checkStartMatches("test*aaa", "testblaaaa");
|
||||
checkStartNoMatch("test*", "tst");
|
||||
checkStartNoMatch("test*", "test/");
|
||||
checkStartMatches("test*", "test/"); // trailing slash is optional
|
||||
checkStartMatches("test*", "test");
|
||||
checkStartNoMatch("test*", "tsttest");
|
||||
checkStartNoMatch("test*", "test/t");
|
||||
checkStartMatches("test/*", "test");
|
||||
@@ -398,7 +594,7 @@ public class PathPatternMatcherTests {
|
||||
"/XXXblaXXXX/testing/bla/testing/testing.jpg");
|
||||
|
||||
checkStartMatches("/abc/{foo}", "/abc/def");
|
||||
checkStartNoMatch("/abc/{foo}", "/abc/def/");
|
||||
checkStartMatches("/abc/{foo}", "/abc/def/"); // trailing slash is optional
|
||||
checkStartMatches("/abc/{foo}/", "/abc/def/");
|
||||
checkStartNoMatch("/abc/{foo}/", "/abc/def/ghi");
|
||||
checkStartMatches("/abc/{foo}/", "/abc/def");
|
||||
@@ -556,8 +752,8 @@ public class PathPatternMatcherTests {
|
||||
|
||||
@Test
|
||||
public void extractPathWithinPattern_spr15259() {
|
||||
checkExtractPathWithinPattern("/**","//","/");
|
||||
checkExtractPathWithinPattern("/**","/","");
|
||||
checkExtractPathWithinPattern("/**","//","");
|
||||
checkExtractPathWithinPattern("/**","","");
|
||||
checkExtractPathWithinPattern("/**","/foobar","foobar");
|
||||
}
|
||||
@@ -579,10 +775,8 @@ public class PathPatternMatcherTests {
|
||||
checkExtractPathWithinPattern("/a/b/c*d*/*.html", "/a/b/cod/foo.html", "cod/foo.html");
|
||||
checkExtractPathWithinPattern("a/{foo}/b/{bar}", "a/c/b/d", "c/b/d");
|
||||
checkExtractPathWithinPattern("a/{foo}_{bar}/d/e", "a/b_c/d/e", "b_c/d/e");
|
||||
checkExtractPathWithinPattern("aaa//*///ccc///ddd", "aaa/bbb/ccc/ddd", "bbb/ccc/ddd");
|
||||
checkExtractPathWithinPattern("aaa/*/ccc/ddd", "aaa//bbb//ccc/ddd", "bbb/ccc/ddd");
|
||||
checkExtractPathWithinPattern("aaa//*///ccc///ddd", "aaa//bbb///ccc///ddd", "bbb/ccc/ddd");
|
||||
checkExtractPathWithinPattern("aaa//*///ccc///ddd", "aaa//bbb//ccc/ddd", "bbb/ccc/ddd");
|
||||
checkExtractPathWithinPattern("aaa//*///ccc///ddd", "aaa/////bbb//ccc/ddd", "bbb/ccc/ddd");
|
||||
checkExtractPathWithinPattern("aaa/c*/ddd/", "aaa/ccc///ddd///", "ccc/ddd");
|
||||
checkExtractPathWithinPattern("", "", "");
|
||||
checkExtractPathWithinPattern("/", "", "");
|
||||
@@ -604,13 +798,18 @@ public class PathPatternMatcherTests {
|
||||
|
||||
pp = new PathPatternParser().parse("/{foo}/{bar}");
|
||||
assertTrue(pp.matches("/abc/def"));
|
||||
assertFalse(pp.matches("/def"));
|
||||
assertFalse(pp.matches("/"));
|
||||
assertFalse(pp.matches("//def"));
|
||||
assertFalse(pp.matches("//"));
|
||||
|
||||
|
||||
pp = parse("/{foo}/boo");
|
||||
assertTrue(pp.matches("/abc/boo"));
|
||||
assertTrue(pp.matches("/a/boo"));
|
||||
assertFalse(pp.matches("/boo"));
|
||||
assertFalse(pp.matches("//boo"));
|
||||
|
||||
|
||||
pp = parse("/{foo}*");
|
||||
assertTrue(pp.matches("/abc"));
|
||||
@@ -630,11 +829,14 @@ public class PathPatternMatcherTests {
|
||||
checkCapture("/{foo:[a-z][a-z]}{bar:[a-z]}", "/abc", "foo", "ab", "bar", "c");
|
||||
|
||||
// Only patterns not capturing variables cannot match against just /
|
||||
pp = new PathPatternParser().parse("/****");
|
||||
PathPatternParser ppp = new PathPatternParser();
|
||||
ppp.setMatchOptionalTrailingSlash(true);
|
||||
pp = ppp.parse("/****");
|
||||
assertTrue(pp.matches("/abcdef"));
|
||||
assertTrue(pp.matches("/"));
|
||||
assertTrue(pp.matches("/"));
|
||||
assertTrue(pp.matches("//"));
|
||||
|
||||
|
||||
// Confirming AntPathMatcher behaviour:
|
||||
assertFalse(new AntPathMatcher().match("/{foo}", "/"));
|
||||
assertTrue(new AntPathMatcher().match("/{foo}", "/a"));
|
||||
@@ -682,6 +884,7 @@ public class PathPatternMatcherTests {
|
||||
checkCapture("/{bla}.*", "/testing.html", "bla", "testing");
|
||||
Map<String, String> extracted = checkCapture("/abc", "/abc");
|
||||
assertEquals(0, extracted.size());
|
||||
checkCapture("/{bla}/foo","/a/foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -990,6 +1193,7 @@ public class PathPatternMatcherTests {
|
||||
|
||||
private PathPattern parse(String path) {
|
||||
PathPatternParser pp = new PathPatternParser();
|
||||
pp.setMatchOptionalTrailingSlash(true);
|
||||
return pp.parse(path);
|
||||
}
|
||||
|
||||
@@ -998,18 +1202,21 @@ public class PathPatternMatcherTests {
|
||||
private void checkMatches(String uriTemplate, String path) {
|
||||
PathPatternParser parser = (separator == PathPatternParser.DEFAULT_SEPARATOR
|
||||
? new PathPatternParser() : new PathPatternParser(separator));
|
||||
parser.setMatchOptionalTrailingSlash(true);
|
||||
PathPattern p = parser.parse(uriTemplate);
|
||||
assertTrue(p.matches(path));
|
||||
}
|
||||
|
||||
private void checkStartNoMatch(String uriTemplate, String path) {
|
||||
PathPatternParser p = new PathPatternParser();
|
||||
p.setMatchOptionalTrailingSlash(true);
|
||||
PathPattern pattern = p.parse(uriTemplate);
|
||||
assertFalse(pattern.matchStart(path));
|
||||
}
|
||||
|
||||
private void checkStartMatches(String uriTemplate, String path) {
|
||||
PathPatternParser p = new PathPatternParser();
|
||||
p.setMatchOptionalTrailingSlash(true);
|
||||
PathPattern pattern = p.parse(uriTemplate);
|
||||
assertTrue(pattern.matchStart(path));
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class PathPatternParserTests {
|
||||
checkStructure("foo");
|
||||
checkStructure("foo/");
|
||||
checkStructure("/foo/");
|
||||
checkStructure("//");
|
||||
checkStructure("");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -49,7 +49,7 @@ public class PathPatternParserTests {
|
||||
p = checkStructure("?");
|
||||
assertPathElements(p, SingleCharWildcardedPathElement.class);
|
||||
checkStructure("/?/");
|
||||
checkStructure("//?abc?/");
|
||||
checkStructure("/?abc?/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -175,7 +175,7 @@ public class PathPatternParserTests {
|
||||
p = checkStructure("{foo}");
|
||||
assertEquals(CaptureVariablePathElement.class.getName(), p.getHeadSection().getClass().getName());
|
||||
checkStructure("/{foo}");
|
||||
checkStructure("//{f}/");
|
||||
checkStructure("/{f}/");
|
||||
checkStructure("/{foo}/{bar}/{wibble}");
|
||||
}
|
||||
|
||||
@@ -208,13 +208,13 @@ public class PathPatternParserTests {
|
||||
checkError("{", 1, PatternMessage.MISSING_CLOSE_CAPTURE);
|
||||
checkError("{abc", 4, PatternMessage.MISSING_CLOSE_CAPTURE);
|
||||
checkError("{/}", 1, PatternMessage.MISSING_CLOSE_CAPTURE);
|
||||
checkError("//{", 3, PatternMessage.MISSING_CLOSE_CAPTURE);
|
||||
checkError("/{", 2, PatternMessage.MISSING_CLOSE_CAPTURE);
|
||||
checkError("}", 0, PatternMessage.MISSING_OPEN_CAPTURE);
|
||||
checkError("/}", 1, PatternMessage.MISSING_OPEN_CAPTURE);
|
||||
checkError("def}", 3, PatternMessage.MISSING_OPEN_CAPTURE);
|
||||
checkError("//{/}", 3, PatternMessage.MISSING_CLOSE_CAPTURE);
|
||||
checkError("//{{/}", 3, PatternMessage.ILLEGAL_NESTED_CAPTURE);
|
||||
checkError("//{abc{/}", 6, PatternMessage.ILLEGAL_NESTED_CAPTURE);
|
||||
checkError("/{/}", 2, PatternMessage.MISSING_CLOSE_CAPTURE);
|
||||
checkError("/{{/}", 2, PatternMessage.ILLEGAL_NESTED_CAPTURE);
|
||||
checkError("/{abc{/}", 5, PatternMessage.ILLEGAL_NESTED_CAPTURE);
|
||||
checkError("/{0abc}/abc", 2, PatternMessage.ILLEGAL_CHARACTER_AT_START_OF_CAPTURE_DESCRIPTOR);
|
||||
checkError("/{a?bc}/abc", 3, PatternMessage.ILLEGAL_CHARACTER_IN_CAPTURE_DESCRIPTOR);
|
||||
checkError("/{abc}_{abc}", 1, PatternMessage.ILLEGAL_DOUBLE_CAPTURE);
|
||||
@@ -294,15 +294,19 @@ public class PathPatternParserTests {
|
||||
@Test
|
||||
public void multipleSeparatorPatterns() {
|
||||
p = checkStructure("///aaa");
|
||||
assertEquals(4, p.getNormalizedLength());
|
||||
assertPathElements(p, SeparatorPathElement.class, LiteralPathElement.class);
|
||||
assertEquals(6, p.getNormalizedLength());
|
||||
assertPathElements(p, SeparatorPathElement.class, SeparatorPathElement.class,
|
||||
SeparatorPathElement.class, LiteralPathElement.class);
|
||||
p = checkStructure("///aaa////aaa/b");
|
||||
assertEquals(10, p.getNormalizedLength());
|
||||
assertPathElements(p, SeparatorPathElement.class, LiteralPathElement.class,
|
||||
SeparatorPathElement.class, LiteralPathElement.class, SeparatorPathElement.class, LiteralPathElement.class);
|
||||
assertEquals(15, p.getNormalizedLength());
|
||||
assertPathElements(p, SeparatorPathElement.class, SeparatorPathElement.class,
|
||||
SeparatorPathElement.class, LiteralPathElement.class, SeparatorPathElement.class,
|
||||
SeparatorPathElement.class, SeparatorPathElement.class, SeparatorPathElement.class,
|
||||
LiteralPathElement.class, SeparatorPathElement.class, LiteralPathElement.class);
|
||||
p = checkStructure("/////**");
|
||||
assertEquals(1, p.getNormalizedLength());
|
||||
assertPathElements(p, WildcardTheRestPathElement.class);
|
||||
assertEquals(5, p.getNormalizedLength());
|
||||
assertPathElements(p, SeparatorPathElement.class, SeparatorPathElement.class,
|
||||
SeparatorPathElement.class, SeparatorPathElement.class, WildcardTheRestPathElement.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user