244 lines
6.2 KiB
Rust
244 lines
6.2 KiB
Rust
use matchit::{InsertError, Router};
|
|
|
|
struct InsertTest(Vec<(&'static str, Result<(), InsertError>)>);
|
|
|
|
impl InsertTest {
|
|
fn run(self) {
|
|
let mut router = Router::new();
|
|
for (route, expected) in self.0 {
|
|
let got = router.insert(route, route.to_owned());
|
|
assert_eq!(got, expected, "{route}");
|
|
}
|
|
}
|
|
}
|
|
|
|
fn conflict(with: &'static str) -> InsertError {
|
|
InsertError::Conflict { with: with.into() }
|
|
}
|
|
|
|
#[test]
|
|
fn wildcard_conflict() {
|
|
InsertTest(vec![
|
|
("/cmd/{tool}/{sub}", Ok(())),
|
|
("/cmd/vet", Ok(())),
|
|
("/foo/bar", Ok(())),
|
|
("/foo/{name}", Ok(())),
|
|
("/foo/{names}", Err(conflict("/foo/{name}"))),
|
|
("/cmd/{*path}", Err(conflict("/cmd/{tool}/{sub}"))),
|
|
("/cmd/{xxx}/names", Ok(())),
|
|
("/cmd/{tool}/{xxx}/foo", Ok(())),
|
|
("/src/{*filepath}", Ok(())),
|
|
("/src/{file}", Err(conflict("/src/{*filepath}"))),
|
|
("/src/static.json", Ok(())),
|
|
("/src/$filepathx", Ok(())),
|
|
("/src/", Ok(())),
|
|
("/src/foo/bar", Ok(())),
|
|
("/src1/", Ok(())),
|
|
("/src1/{*filepath}", Ok(())),
|
|
("/src2{*filepath}", Ok(())),
|
|
("/src2/{*filepath}", Ok(())),
|
|
("/src2/", Ok(())),
|
|
("/src2", Ok(())),
|
|
("/src3", Ok(())),
|
|
("/src3/{*filepath}", Ok(())),
|
|
("/search/{query}", Ok(())),
|
|
("/search/valid", Ok(())),
|
|
("/user_{name}", Ok(())),
|
|
("/user_x", Ok(())),
|
|
("/user_{bar}", Err(conflict("/user_{name}"))),
|
|
("/id{id}", Ok(())),
|
|
("/id/{id}", Ok(())),
|
|
])
|
|
.run()
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_catchall() {
|
|
InsertTest(vec![
|
|
("/non-leading-{*catchall}", Ok(())),
|
|
("/foo/bar{*catchall}", Ok(())),
|
|
("/src/{*filepath}/x", Err(InsertError::InvalidCatchAll)),
|
|
("/src2/", Ok(())),
|
|
("/src2/{*filepath}/x", Err(InsertError::InvalidCatchAll)),
|
|
])
|
|
.run()
|
|
}
|
|
|
|
#[test]
|
|
fn catchall_root_conflict() {
|
|
InsertTest(vec![("/", Ok(())), ("/{*filepath}", Ok(()))]).run()
|
|
}
|
|
|
|
#[test]
|
|
fn child_conflict() {
|
|
InsertTest(vec![
|
|
("/cmd/vet", Ok(())),
|
|
("/cmd/{tool}", Ok(())),
|
|
("/cmd/{tool}/{sub}", Ok(())),
|
|
("/cmd/{tool}/misc", Ok(())),
|
|
("/cmd/{tool}/{bad}", Err(conflict("/cmd/{tool}/{sub}"))),
|
|
("/src/AUTHORS", Ok(())),
|
|
("/src/{*filepath}", Ok(())),
|
|
("/user_x", Ok(())),
|
|
("/user_{name}", Ok(())),
|
|
("/id/{id}", Ok(())),
|
|
("/id{id}", Ok(())),
|
|
("/{id}", Ok(())),
|
|
("/{*filepath}", Err(conflict("/{id}"))),
|
|
])
|
|
.run()
|
|
}
|
|
|
|
#[test]
|
|
fn duplicates() {
|
|
InsertTest(vec![
|
|
("/", Ok(())),
|
|
("/", Err(conflict("/"))),
|
|
("/doc/", Ok(())),
|
|
("/doc/", Err(conflict("/doc/"))),
|
|
("/src/{*filepath}", Ok(())),
|
|
("/src/{*filepath}", Err(conflict("/src/{*filepath}"))),
|
|
("/search/{query}", Ok(())),
|
|
("/search/{query}", Err(conflict("/search/{query}"))),
|
|
("/user_{name}", Ok(())),
|
|
("/user_{name}", Err(conflict("/user_{name}"))),
|
|
])
|
|
.run()
|
|
}
|
|
|
|
#[test]
|
|
fn unnamed_param() {
|
|
InsertTest(vec![
|
|
("/{}", Err(InsertError::InvalidParam)),
|
|
("/user{}/", Err(InsertError::InvalidParam)),
|
|
("/cmd/{}/", Err(InsertError::InvalidParam)),
|
|
("/src/{*}", Err(InsertError::InvalidParam)),
|
|
])
|
|
.run()
|
|
}
|
|
|
|
#[test]
|
|
fn double_params() {
|
|
InsertTest(vec![
|
|
("/{foo}{bar}", Err(InsertError::InvalidParamSegment)),
|
|
("/{foo}{bar}/", Err(InsertError::InvalidParamSegment)),
|
|
("/{foo}{{*bar}/", Err(InsertError::InvalidParamSegment)),
|
|
])
|
|
.run()
|
|
}
|
|
|
|
#[test]
|
|
fn normalized_conflict() {
|
|
InsertTest(vec![
|
|
("/x/{foo}/bar", Ok(())),
|
|
("/x/{bar}/bar", Err(conflict("/x/{foo}/bar"))),
|
|
("/{y}/bar/baz", Ok(())),
|
|
("/{y}/baz/baz", Ok(())),
|
|
("/{z}/bar/bat", Ok(())),
|
|
("/{z}/bar/baz", Err(conflict("/{y}/bar/baz"))),
|
|
])
|
|
.run()
|
|
}
|
|
|
|
#[test]
|
|
fn more_conflicts() {
|
|
InsertTest(vec![
|
|
("/con{tact}", Ok(())),
|
|
("/who/are/{*you}", Ok(())),
|
|
("/who/foo/hello", Ok(())),
|
|
("/whose/{users}/{name}", Ok(())),
|
|
("/who/are/foo", Ok(())),
|
|
("/who/are/foo/bar", Ok(())),
|
|
("/con{nection}", Err(conflict("/con{tact}"))),
|
|
(
|
|
"/whose/{users}/{user}",
|
|
Err(conflict("/whose/{users}/{name}")),
|
|
),
|
|
])
|
|
.run()
|
|
}
|
|
|
|
#[test]
|
|
fn catchall_static_overlap() {
|
|
InsertTest(vec![
|
|
("/bar", Ok(())),
|
|
("/bar/", Ok(())),
|
|
("/bar/{*foo}", Ok(())),
|
|
])
|
|
.run();
|
|
|
|
InsertTest(vec![
|
|
("/foo", Ok(())),
|
|
("/{*bar}", Ok(())),
|
|
("/bar", Ok(())),
|
|
("/baz", Ok(())),
|
|
("/baz/{split}", Ok(())),
|
|
("/", Ok(())),
|
|
("/{*bar}", Err(conflict("/{*bar}"))),
|
|
("/{*zzz}", Err(conflict("/{*bar}"))),
|
|
("/{xxx}", Err(conflict("/{*bar}"))),
|
|
])
|
|
.run();
|
|
|
|
InsertTest(vec![
|
|
("/{*bar}", Ok(())),
|
|
("/bar", Ok(())),
|
|
("/bar/x", Ok(())),
|
|
("/bar_{x}", Ok(())),
|
|
("/bar_{x}", Err(conflict("/bar_{x}"))),
|
|
("/bar_{x}/y", Ok(())),
|
|
("/bar/{x}", Ok(())),
|
|
])
|
|
.run();
|
|
}
|
|
|
|
#[test]
|
|
fn duplicate_conflict() {
|
|
InsertTest(vec![
|
|
("/hey", Ok(())),
|
|
("/hey/users", Ok(())),
|
|
("/hey/user", Ok(())),
|
|
("/hey/user", Err(conflict("/hey/user"))),
|
|
])
|
|
.run()
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_param() {
|
|
InsertTest(vec![
|
|
("{", Err(InsertError::InvalidParam)),
|
|
("}", Err(InsertError::InvalidParam)),
|
|
("x{y", Err(InsertError::InvalidParam)),
|
|
("x}", Err(InsertError::InvalidParam)),
|
|
("/{foo}s", Err(InsertError::InvalidParamSegment)),
|
|
])
|
|
.run();
|
|
}
|
|
|
|
#[test]
|
|
fn escaped_param() {
|
|
InsertTest(vec![
|
|
("{{", Ok(())),
|
|
("}}", Ok(())),
|
|
("xx}}", Ok(())),
|
|
("}}yy", Ok(())),
|
|
("}}yy{{}}", Ok(())),
|
|
("}}yy{{}}{{}}y{{", Ok(())),
|
|
("}}yy{{}}{{}}y{{", Err(conflict("}yy{}{}y{"))),
|
|
("/{{yy", Ok(())),
|
|
("/{yy}", Ok(())),
|
|
("/foo", Ok(())),
|
|
("/foo/{{", Ok(())),
|
|
("/foo/{{/{x}", Ok(())),
|
|
("/foo/{ba{{r}", Ok(())),
|
|
("/bar/{ba}}r}", Ok(())),
|
|
("/xxx/{x{{}}y}", Ok(())),
|
|
])
|
|
.run()
|
|
}
|
|
|
|
#[test]
|
|
fn bare_catchall() {
|
|
InsertTest(vec![("{*foo}", Ok(())), ("foo/{*bar}", Ok(()))]).run()
|
|
}
|