use churust_core::{Call, Churust, TestClient};
use http::{Method, StatusCode};
#[tokio::test]
async fn a_method_mismatch_on_one_route_falls_through_to_another() {
let app = Churust::server()
.routing(|r| {
r.post("/a/{x}", |_c: Call| async { "post-ax" });
r.get("/{y}/b", |_c: Call| async { "get-yb" });
})
.build();
let res = TestClient::new(app).get("/a/b").send().await;
assert_eq!(
res.status(),
StatusCode::OK,
"matching committed to /a/{{x}} and answered 405"
);
assert_eq!(res.text(), "get-yb");
}
#[tokio::test]
async fn registration_order_does_not_decide_it() {
let app = Churust::server()
.routing(|r| {
r.get("/{y}/b", |_c: Call| async { "get-yb" });
r.post("/a/{x}", |_c: Call| async { "post-ax" });
})
.build();
let res = TestClient::new(app).get("/a/b").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text(), "get-yb");
}
#[tokio::test]
async fn a_failing_guard_falls_through_to_another_route() {
let app = Churust::server()
.routing(|r| {
r.get("/a/{x}", |_c: Call| async { "beta" })
.guard(churust_core::guard::header("x-beta", "1"));
r.get("/{y}/b", |_c: Call| async { "stable" });
})
.build();
let client = TestClient::new(app);
let res = client.get("/a/b").send().await;
assert_eq!(
res.status(),
StatusCode::OK,
"a guard on /a/{{x}} hid /{{y}}/b entirely"
);
assert_eq!(res.text(), "stable");
}
#[tokio::test]
async fn the_guarded_route_still_wins_when_its_guard_passes() {
let app = Churust::server()
.routing(|r| {
r.get("/a/{x}", |_c: Call| async { "beta" })
.guard(churust_core::guard::header("x-beta", "1"));
r.get("/{y}/b", |_c: Call| async { "stable" });
})
.build();
let res = TestClient::new(app)
.get("/a/b")
.header("x-beta", "1")
.send()
.await;
assert_eq!(res.text(), "beta");
}
#[tokio::test]
async fn static_still_beats_param_when_both_can_serve() {
let app = Churust::server()
.routing(|r| {
r.get("/a/b", |_c: Call| async { "static" });
r.get("/{y}/b", |_c: Call| async { "param" });
})
.build();
assert_eq!(
TestClient::new(app).get("/a/b").send().await.text(),
"static"
);
}
#[tokio::test]
async fn the_captured_parameters_belong_to_the_route_that_served() {
let app = Churust::server()
.routing(|r| {
r.post("/a/{x}", |_c: Call| async { "post" });
r.get("/{y}/b", |c: Call| async move {
format!(
"y={:?} x={:?}",
c.param_raw("y").unwrap_or("-"),
c.param_raw("x").unwrap_or("-")
)
});
})
.build();
let res = TestClient::new(app).get("/a/b").send().await;
assert_eq!(res.text(), r#"y="a" x="-""#);
}
#[tokio::test]
async fn a_genuine_method_mismatch_is_still_405_listing_every_depth() {
let app = Churust::server()
.routing(|r| {
r.post("/a/{x}", |_c: Call| async { "post" });
r.get("/{y}/b", |_c: Call| async { "get" });
})
.build();
let res = TestClient::new(app)
.request(Method::DELETE, "/a/b")
.send()
.await;
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
let allow = res.header("allow").unwrap_or_default().to_ascii_uppercase();
assert!(allow.contains("POST"), "{allow}");
assert!(allow.contains("GET"), "{allow}");
}
#[tokio::test]
async fn an_unmatched_path_is_still_404() {
let app = Churust::server()
.routing(|r| {
r.get("/a/{x}", |_c: Call| async { "a" });
})
.build();
let res = TestClient::new(app).get("/nope/deep/er").send().await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
}