use matchit::{MatchError, Router};
#[test]
fn partial_overlap() {
let mut x = Router::new();
x.insert("/foo_bar", "Welcome!").unwrap();
x.insert("/foo/bar", "Welcome!").unwrap();
assert_eq!(x.at("/foo/").unwrap_err(), MatchError::NotFound);
let mut x = Router::new();
x.insert("/foo", "Welcome!").unwrap();
x.insert("/foo/bar", "Welcome!").unwrap();
assert_eq!(x.at("/foo/").unwrap_err(), MatchError::NotFound);
}
#[test]
fn wildcard_overlap() {
let mut router = Router::new();
router.insert("/path/foo", "foo").unwrap();
router.insert("/path/{*rest}", "wildcard").unwrap();
assert_eq!(router.at("/path/foo").map(|m| *m.value), Ok("foo"));
assert_eq!(router.at("/path/bar").map(|m| *m.value), Ok("wildcard"));
assert_eq!(router.at("/path/foo/").map(|m| *m.value), Ok("wildcard"));
let mut router = Router::new();
router.insert("/path/foo/{arg}", "foo").unwrap();
router.insert("/path/{*rest}", "wildcard").unwrap();
assert_eq!(router.at("/path/foo/myarg").map(|m| *m.value), Ok("foo"));
assert_eq!(
router.at("/path/foo/myarg/").map(|m| *m.value),
Ok("wildcard")
);
assert_eq!(
router.at("/path/foo/myarg/bar/baz").map(|m| *m.value),
Ok("wildcard")
);
}
#[test]
fn overlapping_param_backtracking() {
let mut matcher = Router::new();
matcher.insert("/{object}/{id}", "object with id").unwrap();
matcher
.insert("/secret/{id}/path", "secret with id and path")
.unwrap();
let matched = matcher.at("/secret/978/path").unwrap();
assert_eq!(matched.params.get("id"), Some("978"));
let matched = matcher.at("/something/978").unwrap();
assert_eq!(matched.params.get("id"), Some("978"));
assert_eq!(matched.params.get("object"), Some("something"));
let matched = matcher.at("/secret/978").unwrap();
assert_eq!(matched.params.get("id"), Some("978"));
}
struct MatchTest {
routes: Vec<&'static str>,
matches: Vec<(
&'static str,
&'static str,
Result<Vec<(&'static str, &'static str)>, ()>,
)>,
}
impl MatchTest {
fn run(self) {
let mut router = Router::new();
for route in self.routes {
assert_eq!(router.insert(route, route.to_owned()), Ok(()), "{route}");
}
router.check_priorities().unwrap();
for (path, route, params) in self.matches {
match router.at(path) {
Ok(x) => {
assert_eq!(x.value, route);
let got = x.params.iter().collect::<Vec<_>>();
assert_eq!(params.unwrap(), got);
router.at_mut(path).unwrap().value.push_str("Z");
assert!(router.at(path).unwrap().value.contains("Z"));
router.at_mut(path).unwrap().value.pop();
}
Err(_) => params.unwrap_err(),
}
}
}
}
macro_rules! p {
($($k:expr => $v:expr),* $(,)?) => {
Ok(vec![$(($k, $v)),*])
};
}
#[test]
fn bare_catchall() {
MatchTest {
routes: vec!["{*foo}", "foo/{*bar}"],
matches: vec![
("x/y", "{*foo}", p! { "foo" => "x/y" }),
("/x/y", "{*foo}", p! { "foo" => "/x/y" }),
("/foo/x/y", "{*foo}", p! { "foo" => "/foo/x/y" }),
("foo/x/y", "foo/{*bar}", p! { "bar" => "x/y" }),
],
}
.run()
}
#[test]
fn normalized() {
MatchTest {
routes: vec![
"/x/{foo}/bar",
"/x/{bar}/baz",
"/{foo}/{baz}/bax",
"/{foo}/{bar}/baz",
"/{fod}/{baz}/{bax}/foo",
"/{fod}/baz/bax/foo",
"/{foo}/baz/bax",
"/{bar}/{bay}/bay",
"/s",
"/s/s",
"/s/s/s",
"/s/s/s/s",
"/s/s/{s}/x",
"/s/s/{y}/d",
],
matches: vec![
("/x/foo/bar", "/x/{foo}/bar", p! { "foo" => "foo" }),
("/x/foo/baz", "/x/{bar}/baz", p! { "bar" => "foo" }),
(
"/y/foo/baz",
"/{foo}/{bar}/baz",
p! { "foo" => "y", "bar" => "foo" },
),
(
"/y/foo/bax",
"/{foo}/{baz}/bax",
p! { "foo" => "y", "baz" => "foo" },
),
(
"/y/baz/baz",
"/{foo}/{bar}/baz",
p! { "foo" => "y", "bar" => "baz" },
),
("/y/baz/bax/foo", "/{fod}/baz/bax/foo", p! { "fod" => "y" }),
(
"/y/baz/b/foo",
"/{fod}/{baz}/{bax}/foo",
p! { "fod" => "y", "baz" => "baz", "bax" => "b" },
),
("/y/baz/bax", "/{foo}/baz/bax", p! { "foo" => "y" }),
(
"/z/bar/bay",
"/{bar}/{bay}/bay",
p! { "bar" => "z", "bay" => "bar" },
),
("/s", "/s", p! {}),
("/s/s", "/s/s", p! {}),
("/s/s/s", "/s/s/s", p! {}),
("/s/s/s/s", "/s/s/s/s", p! {}),
("/s/s/s/x", "/s/s/{s}/x", p! { "s" => "s" }),
("/s/s/s/d", "/s/s/{y}/d", p! { "y" => "s" }),
],
}
.run()
}
#[test]
fn blog() {
MatchTest {
routes: vec![
"/{page}",
"/posts/{year}/{month}/{post}",
"/posts/{year}/{month}/index",
"/posts/{year}/top",
"/static/{*path}",
"/favicon.ico",
],
matches: vec![
("/about", "/{page}", p! { "page" => "about" }),
(
"/posts/2021/01/rust",
"/posts/{year}/{month}/{post}",
p! { "year" => "2021", "month" => "01", "post" => "rust" },
),
(
"/posts/2021/01/index",
"/posts/{year}/{month}/index",
p! { "year" => "2021", "month" => "01" },
),
(
"/posts/2021/top",
"/posts/{year}/top",
p! { "year" => "2021" },
),
(
"/static/foo.png",
"/static/{*path}",
p! { "path" => "foo.png" },
),
("/favicon.ico", "/favicon.ico", p! {}),
],
}
.run()
}
#[test]
fn double_overlap() {
MatchTest {
routes: vec![
"/{object}/{id}",
"/secret/{id}/path",
"/secret/978",
"/other/{object}/{id}/",
"/other/an_object/{id}",
"/other/static/path",
"/other/long/static/path/",
],
matches: vec![
(
"/secret/978/path",
"/secret/{id}/path",
p! { "id" => "978" },
),
(
"/some_object/978",
"/{object}/{id}",
p! { "object" => "some_object", "id" => "978" },
),
("/secret/978", "/secret/978", p! {}),
("/super_secret/978/", "/{object}/{id}", Err(())),
(
"/other/object/1/",
"/other/{object}/{id}/",
p! { "object" => "object", "id" => "1" },
),
("/other/object/1/2", "/other/{object}/{id}", Err(())),
(
"/other/an_object/1",
"/other/an_object/{id}",
p! { "id" => "1" },
),
("/other/static/path", "/other/static/path", p! {}),
(
"/other/long/static/path/",
"/other/long/static/path/",
p! {},
),
],
}
.run()
}
#[test]
fn catchall_off_by_one() {
MatchTest {
routes: vec!["/foo/{*catchall}", "/bar", "/bar/", "/bar/{*catchall}"],
matches: vec![
("/foo", "", Err(())),
("/foo/", "", Err(())),
("/foo/x", "/foo/{*catchall}", p! { "catchall" => "x" }),
("/bar", "/bar", p! {}),
("/bar/", "/bar/", p! {}),
("/bar/x", "/bar/{*catchall}", p! { "catchall" => "x" }),
],
}
.run()
}
#[test]
fn overlap() {
MatchTest {
routes: vec![
"/foo",
"/bar",
"/{*bar}",
"/baz",
"/baz/",
"/baz/x",
"/baz/{xxx}",
"/",
"/xxx/{*x}",
"/xxx/",
],
matches: vec![
("/foo", "/foo", p! {}),
("/bar", "/bar", p! {}),
("/baz", "/baz", p! {}),
("/baz/", "/baz/", p! {}),
("/baz/x", "/baz/x", p! {}),
("/???", "/{*bar}", p! { "bar" => "???" }),
("/", "/", p! {}),
("", "", Err(())),
("/xxx/y", "/xxx/{*x}", p! { "x" => "y" }),
("/xxx/", "/xxx/", p! {}),
("/xxx", "/{*bar}", p! { "bar" => "xxx" }),
],
}
.run()
}
#[test]
fn missing_trailing_slash_param() {
MatchTest {
routes: vec!["/foo/{object}/{id}", "/foo/bar/baz", "/foo/secret/978/"],
matches: vec![
("/foo/secret/978/", "/foo/secret/978/", p! {}),
(
"/foo/secret/978",
"/foo/{object}/{id}",
p! { "object" => "secret", "id" => "978" },
),
],
}
.run()
}
#[test]
fn extra_trailing_slash_param() {
MatchTest {
routes: vec!["/foo/{object}/{id}", "/foo/bar/baz", "/foo/secret/978"],
matches: vec![
("/foo/secret/978/", "", Err(())),
("/foo/secret/978", "/foo/secret/978", p! {}),
],
}
.run()
}
#[test]
fn missing_trailing_slash_catch_all() {
MatchTest {
routes: vec!["/foo/{*bar}", "/foo/bar/baz", "/foo/secret/978/"],
matches: vec![
(
"/foo/secret/978",
"/foo/{*bar}",
p! { "bar" => "secret/978" },
),
("/foo/secret/978/", "/foo/secret/978/", p! {}),
],
}
.run()
}
#[test]
fn extra_trailing_slash_catch_all() {
MatchTest {
routes: vec!["/foo/{*bar}", "/foo/bar/baz", "/foo/secret/978"],
matches: vec![
(
"/foo/secret/978/",
"/foo/{*bar}",
p! { "bar" => "secret/978/" },
),
("/foo/secret/978", "/foo/secret/978", p! {}),
],
}
.run()
}
#[test]
fn double_overlap_trailing_slash() {
MatchTest {
routes: vec![
"/{object}/{id}",
"/secret/{id}/path",
"/secret/978/",
"/other/{object}/{id}/",
"/other/an_object/{id}",
"/other/static/path",
"/other/long/static/path/",
],
matches: vec![
("/secret/978/path/", "", Err(())),
("/object/id/", "", Err(())),
("/object/id/path", "", Err(())),
("/other/object/1", "", Err(())),
("/other/object/1/2", "", Err(())),
(
"/other/an_object/1/",
"/other/{object}/{id}/",
p! { "object" => "an_object", "id" => "1" },
),
(
"/other/static/path/",
"/other/{object}/{id}/",
p! { "object" => "static", "id" => "path" },
),
("/other/long/static/path", "", Err(())),
("/other/object/static/path", "", Err(())),
],
}
.run()
}
#[test]
fn trailing_slash_overlap() {
MatchTest {
routes: vec!["/foo/{x}/baz/", "/foo/{x}/baz", "/foo/bar/bar"],
matches: vec![
("/foo/x/baz/", "/foo/{x}/baz/", p! { "x" => "x" }),
("/foo/x/baz", "/foo/{x}/baz", p! { "x" => "x" }),
("/foo/bar/bar", "/foo/bar/bar", p! {}),
],
}
.run()
}
#[test]
fn trailing_slash() {
MatchTest {
routes: vec![
"/hi",
"/b/",
"/search/{query}",
"/cmd/{tool}/",
"/src/{*filepath}",
"/x",
"/x/y",
"/y/",
"/y/z",
"/0/{id}",
"/0/{id}/1",
"/1/{id}/",
"/1/{id}/2",
"/aa",
"/a/",
"/admin",
"/admin/static",
"/admin/{category}",
"/admin/{category}/{page}",
"/doc",
"/doc/rust_faq.html",
"/doc/rust1.26.html",
"/no/a",
"/no/b",
"/no/a/b/{*other}",
"/api/{page}/{name}",
"/api/hello/{name}/bar/",
"/api/bar/{name}",
"/api/baz/foo",
"/api/baz/foo/bar",
"/foo/{p}",
],
matches: vec![
("/hi/", "", Err(())),
("/b", "", Err(())),
("/search/rustacean/", "", Err(())),
("/cmd/vet", "", Err(())),
("/src", "", Err(())),
("/src/", "", Err(())),
("/x/", "", Err(())),
("/y", "", Err(())),
("/0/rust/", "", Err(())),
("/1/rust", "", Err(())),
("/a", "", Err(())),
("/admin/", "", Err(())),
("/doc/", "", Err(())),
("/admin/static/", "", Err(())),
("/admin/cfg/", "", Err(())),
("/admin/cfg/users/", "", Err(())),
("/api/hello/x/bar", "", Err(())),
("/api/baz/foo/", "", Err(())),
("/api/baz/bax/", "", Err(())),
("/api/bar/huh/", "", Err(())),
("/api/baz/foo/bar/", "", Err(())),
("/api/world/abc/", "", Err(())),
("/foo/pp/", "", Err(())),
("/", "", Err(())),
("/no", "", Err(())),
("/no/", "", Err(())),
("/no/a/b", "", Err(())),
("/no/a/b/", "", Err(())),
("/_", "", Err(())),
("/_/", "", Err(())),
("/api", "", Err(())),
("/api/", "", Err(())),
("/api/hello/x/foo", "", Err(())),
("/api/baz/foo/bad", "", Err(())),
("/foo/p/p", "", Err(())),
],
}
.run()
}
#[test]
fn backtracking_trailing_slash() {
MatchTest {
routes: vec!["/a/{b}/{c}", "/a/b/{c}/d/"],
matches: vec![("/a/b/c/d", "", Err(()))],
}
.run()
}
#[test]
fn root_trailing_slash() {
MatchTest {
routes: vec!["/foo", "/bar", "/{baz}"],
matches: vec![("/", "", Err(()))],
}
.run()
}
#[test]
fn catchall_overlap() {
MatchTest {
routes: vec!["/yyy/{*x}", "/yyy{*x}"],
matches: vec![
("/yyy/y", "/yyy/{*x}", p! { "x" => "y" }),
("/yyy/", "/yyy{*x}", p! { "x" => "/" }),
],
}
.run();
}
#[test]
fn escaped() {
MatchTest {
routes: vec![
"/",
"/{{",
"/}}",
"/{{x",
"/}}y{{",
"/xy{{",
"/{{/xyz",
"/{ba{{r}",
"/{ba{{r}/",
"/{ba{{r}/x",
"/baz/{xxx}",
"/baz/{xxx}/xy{{",
"/baz/{xxx}/}}xy{{{{",
"/{{/{x}",
"/xxx/",
"/xxx/{x}}{{}}}}{{}}{{{{}}y}",
],
matches: vec![
("/", "/", p! {}),
("/{", "/{{", p! {}),
("/}", "/}}", p! {}),
("/{x", "/{{x", p! {}),
("/}y{", "/}}y{{", p! {}),
("/xy{", "/xy{{", p! {}),
("/{/xyz", "/{{/xyz", p! {}),
("/foo", "/{ba{{r}", p! { "ba{r" => "foo" }),
("/{{", "/{ba{{r}", p! { "ba{r" => "{{" }),
("/{{}}/", "/{ba{{r}/", p! { "ba{r" => "{{}}" }),
("/{{}}{{/x", "/{ba{{r}/x", p! { "ba{r" => "{{}}{{" }),
("/baz/x", "/baz/{xxx}", p! { "xxx" => "x" }),
("/baz/x/xy{", "/baz/{xxx}/xy{{", p! { "xxx" => "x" }),
("/baz/x/xy{{", "", Err(())),
("/baz/x/}xy{{", "/baz/{xxx}/}}xy{{{{", p! { "xxx" => "x" }),
("/{/{{", "/{{/{x}", p! { "x" => "{{" }),
("/xxx", "/{ba{{r}", p! { "ba{r" => "xxx" }),
("/xxx/", "/xxx/", p!()),
(
"/xxx/foo",
"/xxx/{x}}{{}}}}{{}}{{{{}}y}",
p! { "x}{}}{}{{}y" => "foo" },
),
],
}
.run()
}
#[test]
fn basic() {
MatchTest {
routes: vec![
"/hi",
"/contact",
"/co",
"/c",
"/a",
"/ab",
"/doc/",
"/doc/rust_faq.html",
"/doc/rust1.26.html",
"/ʯ",
"/β",
"/sd!here",
"/sd$here",
"/sd&here",
"/sd'here",
"/sd(here",
"/sd)here",
"/sd+here",
"/sd,here",
"/sd;here",
"/sd=here",
],
matches: vec![
("/a", "/a", p! {}),
("", "/", Err(())),
("/hi", "/hi", p! {}),
("/contact", "/contact", p! {}),
("/co", "/co", p! {}),
("", "/con", Err(())),
("", "/cona", Err(())),
("", "/no", Err(())),
("/ab", "/ab", p! {}),
("/ʯ", "/ʯ", p! {}),
("/β", "/β", p! {}),
("/sd!here", "/sd!here", p! {}),
("/sd$here", "/sd$here", p! {}),
("/sd&here", "/sd&here", p! {}),
("/sd'here", "/sd'here", p! {}),
("/sd(here", "/sd(here", p! {}),
("/sd)here", "/sd)here", p! {}),
("/sd+here", "/sd+here", p! {}),
("/sd,here", "/sd,here", p! {}),
("/sd;here", "/sd;here", p! {}),
("/sd=here", "/sd=here", p! {}),
],
}
.run()
}
#[test]
fn wildcard() {
MatchTest {
routes: vec![
"/",
"/cmd/{tool}/",
"/cmd/{tool2}/{sub}",
"/cmd/whoami",
"/cmd/whoami/root",
"/cmd/whoami/root/",
"/src",
"/src/",
"/src/{*filepath}",
"/search/",
"/search/{query}",
"/search/actix-web",
"/search/google",
"/user_{name}",
"/user_{name}/about",
"/files/{dir}/{*filepath}",
"/doc/",
"/doc/rust_faq.html",
"/doc/rust1.26.html",
"/info/{user}/public",
"/info/{user}/project/{project}",
"/info/{user}/project/rustlang",
"/aa/{*xx}",
"/ab/{*xx}",
"/ab/hello{*xx}",
"/{cc}",
"/c1/{dd}/e",
"/c1/{dd}/e1",
"/{cc}/cc",
"/{cc}/{dd}/ee",
"/{cc}/{dd}/{ee}/ff",
"/{cc}/{dd}/{ee}/{ff}/gg",
"/{cc}/{dd}/{ee}/{ff}/{gg}/hh",
"/get/test/abc/",
"/get/{param}/abc/",
"/something/{paramname}/thirdthing",
"/something/secondthing/test",
"/get/abc",
"/get/{param}",
"/get/abc/123abc",
"/get/abc/{param}",
"/get/abc/123abc/xxx8",
"/get/abc/123abc/{param}",
"/get/abc/123abc/xxx8/1234",
"/get/abc/123abc/xxx8/{param}",
"/get/abc/123abc/xxx8/1234/ffas",
"/get/abc/123abc/xxx8/1234/{param}",
"/get/abc/123abc/xxx8/1234/kkdd/12c",
"/get/abc/123abc/xxx8/1234/kkdd/{param}",
"/get/abc/{param}/test",
"/get/abc/123abd/{param}",
"/get/abc/123abddd/{param}",
"/get/abc/123/{param}",
"/get/abc/123abg/{param}",
"/get/abc/123abf/{param}",
"/get/abc/123abfff/{param}",
],
matches: vec![
("/", "/", p! {}),
("/cmd/test", "/cmd/{tool}/", Err(())),
("/cmd/test/", "/cmd/{tool}/", p! { "tool" => "test" }),
(
"/cmd/test/3",
"/cmd/{tool2}/{sub}",
p! { "tool2" => "test", "sub" => "3" },
),
("/cmd/who", "/cmd/{tool}/", Err(())),
("/cmd/who/", "/cmd/{tool}/", p! { "tool" => "who" }),
("/cmd/whoami", "/cmd/whoami", p! {}),
("/cmd/whoami/", "/cmd/{tool}/", p! { "tool" => "whoami" }),
(
"/cmd/whoami/r",
"/cmd/{tool2}/{sub}",
p! { "tool2" => "whoami", "sub" => "r" },
),
("/cmd/whoami/r/", "/cmd/{tool}/{sub}", Err(())),
("/cmd/whoami/root", "/cmd/whoami/root", p! {}),
("/cmd/whoami/root/", "/cmd/whoami/root/", p! {}),
("/src", "/src", p! {}),
("/src/", "/src/", p! {}),
(
"/src/some/file.png",
"/src/{*filepath}",
p! { "filepath" => "some/file.png" },
),
("/search/", "/search/", p! {}),
(
"/search/actix",
"/search/{query}",
p! { "query" => "actix" },
),
("/search/actix-web", "/search/actix-web", p! {}),
(
"/search/someth!ng+in+ünìcodé",
"/search/{query}",
p! { "query" => "someth!ng+in+ünìcodé" },
),
("/search/someth!ng+in+ünìcodé/", "", Err(())),
(
"/user_rustacean",
"/user_{name}",
p! { "name" => "rustacean" },
),
(
"/user_rustacean/about",
"/user_{name}/about",
p! { "name" => "rustacean" },
),
(
"/files/js/inc/framework.js",
"/files/{dir}/{*filepath}",
p! { "dir" => "js", "filepath" => "inc/framework.js" },
),
(
"/info/gordon/public",
"/info/{user}/public",
p! { "user" => "gordon" },
),
(
"/info/gordon/project/rust",
"/info/{user}/project/{project}",
p! { "user" => "gordon", "project" => "rust" },
),
(
"/info/gordon/project/rustlang",
"/info/{user}/project/rustlang",
p! { "user" => "gordon" },
),
("/aa/", "/", Err(())),
("/aa/aa", "/aa/{*xx}", p! { "xx" => "aa" }),
("/ab/ab", "/ab/{*xx}", p! { "xx" => "ab" }),
("/ab/hello-world", "/ab/hello{*xx}", p! { "xx" => "-world" }),
("/a", "/{cc}", p! { "cc" => "a" }),
("/all", "/{cc}", p! { "cc" => "all" }),
("/d", "/{cc}", p! { "cc" => "d" }),
("/ad", "/{cc}", p! { "cc" => "ad" }),
("/dd", "/{cc}", p! { "cc" => "dd" }),
("/dddaa", "/{cc}", p! { "cc" => "dddaa" }),
("/aa", "/{cc}", p! { "cc" => "aa" }),
("/aaa", "/{cc}", p! { "cc" => "aaa" }),
("/aaa/cc", "/{cc}/cc", p! { "cc" => "aaa" }),
("/ab", "/{cc}", p! { "cc" => "ab" }),
("/abb", "/{cc}", p! { "cc" => "abb" }),
("/abb/cc", "/{cc}/cc", p! { "cc" => "abb" }),
("/allxxxx", "/{cc}", p! { "cc" => "allxxxx" }),
("/alldd", "/{cc}", p! { "cc" => "alldd" }),
("/all/cc", "/{cc}/cc", p! { "cc" => "all" }),
("/a/cc", "/{cc}/cc", p! { "cc" => "a" }),
("/c1/d/e", "/c1/{dd}/e", p! { "dd" => "d" }),
("/c1/d/e1", "/c1/{dd}/e1", p! { "dd" => "d" }),
(
"/c1/d/ee",
"/{cc}/{dd}/ee",
p! { "cc" => "c1", "dd" => "d" },
),
("/cc/cc", "/{cc}/cc", p! { "cc" => "cc" }),
("/ccc/cc", "/{cc}/cc", p! { "cc" => "ccc" }),
("/deedwjfs/cc", "/{cc}/cc", p! { "cc" => "deedwjfs" }),
("/acllcc/cc", "/{cc}/cc", p! { "cc" => "acllcc" }),
("/get/test/abc/", "/get/test/abc/", p! {}),
("/get/te/abc/", "/get/{param}/abc/", p! { "param" => "te" }),
(
"/get/testaa/abc/",
"/get/{param}/abc/",
p! { "param" => "testaa" },
),
("/get/xx/abc/", "/get/{param}/abc/", p! { "param" => "xx" }),
("/get/tt/abc/", "/get/{param}/abc/", p! { "param" => "tt" }),
("/get/a/abc/", "/get/{param}/abc/", p! { "param" => "a" }),
("/get/t/abc/", "/get/{param}/abc/", p! { "param" => "t" }),
("/get/aa/abc/", "/get/{param}/abc/", p! { "param" => "aa" }),
(
"/get/abas/abc/",
"/get/{param}/abc/",
p! { "param" => "abas" },
),
(
"/something/secondthing/test",
"/something/secondthing/test",
p! {},
),
(
"/something/abcdad/thirdthing",
"/something/{paramname}/thirdthing",
p! { "paramname" => "abcdad" },
),
(
"/something/secondthingaaaa/thirdthing",
"/something/{paramname}/thirdthing",
p! { "paramname" => "secondthingaaaa" },
),
(
"/something/se/thirdthing",
"/something/{paramname}/thirdthing",
p! { "paramname" => "se" },
),
(
"/something/s/thirdthing",
"/something/{paramname}/thirdthing",
p! { "paramname" => "s" },
),
("/c/d/ee", "/{cc}/{dd}/ee", p! { "cc" => "c", "dd" => "d" }),
(
"/c/d/e/ff",
"/{cc}/{dd}/{ee}/ff",
p! { "cc" => "c", "dd" => "d", "ee" => "e" },
),
(
"/c/d/e/f/gg",
"/{cc}/{dd}/{ee}/{ff}/gg",
p! { "cc" => "c", "dd" => "d", "ee" => "e", "ff" => "f" },
),
(
"/c/d/e/f/g/hh",
"/{cc}/{dd}/{ee}/{ff}/{gg}/hh",
p! { "cc" => "c", "dd" => "d", "ee" => "e", "ff" => "f", "gg" => "g" },
),
(
"/cc/dd/ee/ff/gg/hh",
"/{cc}/{dd}/{ee}/{ff}/{gg}/hh",
p! { "cc" => "cc", "dd" => "dd", "ee" => "ee", "ff" => "ff", "gg" => "gg" },
),
("/get/abc", "/get/abc", p! {}),
("/get/a", "/get/{param}", p! { "param" => "a" }),
("/get/abz", "/get/{param}", p! { "param" => "abz" }),
("/get/12a", "/get/{param}", p! { "param" => "12a" }),
("/get/abcd", "/get/{param}", p! { "param" => "abcd" }),
("/get/abc/123abc", "/get/abc/123abc", p! {}),
("/get/abc/12", "/get/abc/{param}", p! { "param" => "12" }),
(
"/get/abc/123ab",
"/get/abc/{param}",
p! { "param" => "123ab" },
),
("/get/abc/xyz", "/get/abc/{param}", p! { "param" => "xyz" }),
(
"/get/abc/123abcddxx",
"/get/abc/{param}",
p! { "param" => "123abcddxx" },
),
("/get/abc/123abc/xxx8", "/get/abc/123abc/xxx8", p! {}),
(
"/get/abc/123abc/x",
"/get/abc/123abc/{param}",
p! { "param" => "x" },
),
(
"/get/abc/123abc/xxx",
"/get/abc/123abc/{param}",
p! { "param" => "xxx" },
),
(
"/get/abc/123abc/abc",
"/get/abc/123abc/{param}",
p! { "param" => "abc" },
),
(
"/get/abc/123abc/xxx8xxas",
"/get/abc/123abc/{param}",
p! { "param" => "xxx8xxas" },
),
(
"/get/abc/123abc/xxx8/1234",
"/get/abc/123abc/xxx8/1234",
p! {},
),
(
"/get/abc/123abc/xxx8/1",
"/get/abc/123abc/xxx8/{param}",
p! { "param" => "1" },
),
(
"/get/abc/123abc/xxx8/123",
"/get/abc/123abc/xxx8/{param}",
p! { "param" => "123" },
),
(
"/get/abc/123abc/xxx8/78k",
"/get/abc/123abc/xxx8/{param}",
p! { "param" => "78k" },
),
(
"/get/abc/123abc/xxx8/1234xxxd",
"/get/abc/123abc/xxx8/{param}",
p! { "param" => "1234xxxd" },
),
(
"/get/abc/123abc/xxx8/1234/ffas",
"/get/abc/123abc/xxx8/1234/ffas",
p! {},
),
(
"/get/abc/123abc/xxx8/1234/f",
"/get/abc/123abc/xxx8/1234/{param}",
p! { "param" => "f" },
),
(
"/get/abc/123abc/xxx8/1234/ffa",
"/get/abc/123abc/xxx8/1234/{param}",
p! { "param" => "ffa" },
),
(
"/get/abc/123abc/xxx8/1234/kka",
"/get/abc/123abc/xxx8/1234/{param}",
p! { "param" => "kka" },
),
(
"/get/abc/123abc/xxx8/1234/ffas321",
"/get/abc/123abc/xxx8/1234/{param}",
p! { "param" => "ffas321" },
),
(
"/get/abc/123abc/xxx8/1234/kkdd/12c",
"/get/abc/123abc/xxx8/1234/kkdd/12c",
p! {},
),
(
"/get/abc/123abc/xxx8/1234/kkdd/1",
"/get/abc/123abc/xxx8/1234/kkdd/{param}",
p! { "param" => "1" },
),
(
"/get/abc/123abc/xxx8/1234/kkdd/12",
"/get/abc/123abc/xxx8/1234/kkdd/{param}",
p! { "param" => "12" },
),
(
"/get/abc/123abc/xxx8/1234/kkdd/12b",
"/get/abc/123abc/xxx8/1234/kkdd/{param}",
p! { "param" => "12b" },
),
(
"/get/abc/123abc/xxx8/1234/kkdd/34",
"/get/abc/123abc/xxx8/1234/kkdd/{param}",
p! { "param" => "34" },
),
(
"/get/abc/123abc/xxx8/1234/kkdd/12c2e3",
"/get/abc/123abc/xxx8/1234/kkdd/{param}",
p! { "param" => "12c2e3" },
),
(
"/get/abc/12/test",
"/get/abc/{param}/test",
p! { "param" => "12" },
),
(
"/get/abc/123abdd/test",
"/get/abc/{param}/test",
p! { "param" => "123abdd" },
),
(
"/get/abc/123abdddf/test",
"/get/abc/{param}/test",
p! { "param" => "123abdddf" },
),
(
"/get/abc/123ab/test",
"/get/abc/{param}/test",
p! { "param" => "123ab" },
),
(
"/get/abc/123abgg/test",
"/get/abc/{param}/test",
p! { "param" => "123abgg" },
),
(
"/get/abc/123abff/test",
"/get/abc/{param}/test",
p! { "param" => "123abff" },
),
(
"/get/abc/123abffff/test",
"/get/abc/{param}/test",
p! { "param" => "123abffff" },
),
(
"/get/abc/123abd/test",
"/get/abc/123abd/{param}",
p! { "param" => "test" },
),
(
"/get/abc/123abddd/test",
"/get/abc/123abddd/{param}",
p! { "param" => "test" },
),
(
"/get/abc/123/test22",
"/get/abc/123/{param}",
p! { "param" => "test22" },
),
(
"/get/abc/123abg/test",
"/get/abc/123abg/{param}",
p! { "param" => "test" },
),
(
"/get/abc/123abf/testss",
"/get/abc/123abf/{param}",
p! { "param" => "testss" },
),
(
"/get/abc/123abfff/te",
"/get/abc/123abfff/{param}",
p! { "param" => "te" },
),
],
}
.run()
}