use super::*;
use crate::error::ServeError;
use hyper::Response;
use hyper::body::Bytes;
fn dummy_handler() -> Handler<()> {
crate::handler::handler(|_, _| async {
Ok::<_, ServeError>(Response::new(crate::handler::body(Bytes::from("ok"))))
})
}
#[test]
fn insert_and_match_static() {
let mut router = Router::new();
router.insert(Method::GET, "/hello", dummy_handler());
let (_, _) = router.match_route(&Method::GET, "/hello").unwrap();
}
#[test]
fn match_with_path_param() {
let mut router = Router::new();
router.insert(Method::GET, "/users/:id", dummy_handler());
let (_, params) = router.match_route(&Method::GET, "/users/42").unwrap();
assert_eq!(params.0.get("id").unwrap(), "42");
}
#[test]
fn match_with_wildcard() {
let mut router = Router::new();
router.insert(Method::GET, "/files/*", dummy_handler());
let (_, params) = router.match_route(&Method::GET, "/files/a/b/c").unwrap();
assert_eq!(params.0.get("*").unwrap(), "a/b/c");
}
#[test]
fn no_match_for_unregistered_route() {
let mut router = Router::new();
router.insert(Method::GET, "/hello", dummy_handler());
assert!(router.match_route(&Method::GET, "/world").is_none());
}
#[test]
fn method_mismatch_returns_none() {
let mut router = Router::new();
router.insert(Method::GET, "/hello", dummy_handler());
assert!(router.match_route(&Method::POST, "/hello").is_none());
}
#[test]
fn root_path_matches() {
let mut router = Router::new();
router.insert(Method::GET, "/", dummy_handler());
let (_, _) = router.match_route(&Method::GET, "/").unwrap();
}
#[test]
fn method_mismatch_on_static_branch_backtracks_to_param_sibling() {
let mut router = Router::new();
router.insert(Method::GET, "/users/:id", dummy_handler());
router.insert(Method::POST, "/users/new", dummy_handler());
let (_, params) = router.match_route(&Method::GET, "/users/new").unwrap();
assert_eq!(params.0.get("id").unwrap(), "new");
}
#[test]
fn static_branch_with_matching_method_still_wins_over_param_sibling() {
let mut router = Router::new();
router.insert(Method::GET, "/users/:id", dummy_handler());
router.insert(Method::GET, "/users/new", dummy_handler());
let (_, params) = router.match_route(&Method::GET, "/users/new").unwrap();
assert!(params.0.is_empty(), "static branch should win, not fall back to :id");
}
#[test]
fn allowed_methods_unions_across_ambiguous_branches() {
let mut router = Router::new();
router.insert(Method::GET, "/users/:id", dummy_handler());
router.insert(Method::POST, "/users/new", dummy_handler());
let mut allowed = router.allowed_methods("/users/new");
allowed.sort_by_key(|m| m.to_string());
assert_eq!(allowed, vec![Method::GET, Method::POST]);
}
#[test]
fn static_path_traversal_borrows_params_without_cloning() {
let mut router = Router::new();
router.insert(Method::GET, "/api/v1/users/profile", dummy_handler());
let (_, params) = router.match_route(&Method::GET, "/api/v1/users/profile").unwrap();
assert!(params.0.is_empty());
}
#[test]
fn param_backtracking_truncates_params_on_failure() {
let mut router = Router::new();
router.insert(Method::GET, "/users/:id", dummy_handler());
router.insert(Method::POST, "/users/new", dummy_handler());
let (_, params) = router.match_route(&Method::GET, "/users/new").unwrap();
assert_eq!(params.0.get("id").unwrap(), "new");
assert_eq!(params.0.len(), 1);
}
#[test]
fn a_failed_param_branch_leaves_no_params_behind() {
let mut router: Router<()> = Router::new();
router.insert(Method::GET, "/a/:x/b", dummy_handler());
router.insert(Method::GET, "/a/*", dummy_handler());
let (_, params) = router.match_route(&Method::GET, "/a/z/c").unwrap();
assert_eq!(params.0.get("*").map(String::as_str), Some("z/c"));
assert_eq!(
params.0.get("x"),
None,
"the abandoned param branch left its capture behind: {params:?}"
);
assert_eq!(params.0.len(), 1, "only the wildcard should be captured: {params:?}");
}
#[test]
fn a_deeply_failed_branch_unwinds_every_level() {
let mut router: Router<()> = Router::new();
router.insert(Method::GET, "/a/:x/:y/deep", dummy_handler());
router.insert(Method::GET, "/a/*", dummy_handler());
let (_, params) = router.match_route(&Method::GET, "/a/1/2/no").unwrap();
assert_eq!(params.0.get("*").map(String::as_str), Some("1/2/no"));
assert_eq!(params.0.len(), 1, "stale captures survived the unwind: {params:?}");
}