use rocket::{*, error::ErrorKind::SentinelAborts}; #[get("/two")] fn two_states(_one: State, _two: State) {} #[get("/one")] fn one_state(_three: State) {} #[async_test] async fn state_sentinel_works() { let err = rocket::build() .configure(Config::debug_default()) .mount("/", routes![two_states]) .ignite().await .unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 2)); let err = rocket::build() .configure(Config::debug_default()) .mount("/", routes![two_states]) .manage(String::new()) .ignite().await .unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 1)); let err = rocket::build() .configure(Config::debug_default()) .mount("/", routes![two_states]) .manage(1 as u32) .ignite().await .unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 1)); let result = rocket::build() .configure(Config::debug_default()) .mount("/", routes![two_states]) .manage(String::new()) .manage(1 as u32) .ignite().await; assert!(result.is_ok()); let err = rocket::build() .configure(Config::debug_default()) .mount("/", routes![one_state]) .ignite().await .unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 1)); let result = rocket::build() .configure(Config::debug_default()) .mount("/", routes![one_state]) .manage(1 as u8) .ignite().await; assert!(result.is_ok()); let err = rocket::build() .configure(Config::debug_default()) .mount("/", routes![one_state, two_states]) .ignite().await .unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 3)); let err = rocket::build() .configure(Config::debug_default()) .mount("/", routes![one_state, two_states]) .manage(1 as u32) .ignite().await .unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 2)); let err = rocket::build() .configure(Config::debug_default()) .mount("/", routes![one_state, two_states]) .manage(1 as u8) .ignite().await .unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 2)); let err = rocket::build() .configure(Config::debug_default()) .mount("/", routes![one_state, two_states]) .manage(1 as u32) .manage(1 as u8) .ignite().await .unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 1)); let result = rocket::build() .configure(Config::debug_default()) .mount("/", routes![one_state, two_states]) .manage(1 as u32) .manage(1 as u8) .manage(String::new()) .ignite().await; assert!(result.is_ok()); } #[test] fn inner_sentinels_detected() { use rocket::local::blocking::Client; #[derive(Responder)] struct MyThing(T); struct ResponderSentinel; impl<'r, 'o: 'r> response::Responder<'r, 'o> for ResponderSentinel { fn respond_to(self, _: &'r Request<'_>) -> response::Result<'o> { todo!() } } impl Sentinel for ResponderSentinel { fn abort(_: &Rocket) -> bool { true } } #[get("/")] fn route() -> MyThing { todo!() } let err = Client::debug_with(routes![route]).unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 1)); #[derive(Responder)] struct Inner(T); #[get("/")] fn inner() -> MyThing> { todo!() } let err = Client::debug_with(routes![inner]).unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 1)); #[get("/")] fn inner_either() -> Either, ResponderSentinel> { todo!() } let err = Client::debug_with(routes![inner_either]).unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 2)); #[derive(Responder)] struct Block(T); impl Sentinel for Block { fn abort(_: &Rocket) -> bool { false } } #[get("/")] fn blocked() -> Block { todo!() } Client::debug_with(routes![blocked]).expect("no sentinel errors"); #[get("/a")] fn inner_b() -> Either>, Block> { todo!() } #[get("/b")] fn inner_b2() -> Either>, Block> { todo!() } Client::debug_with(routes![inner_b, inner_b2]).expect("no sentinel errors"); #[get("/")] fn half_b() -> Either, Block> { todo!() } let err = Client::debug_with(routes![half_b]).unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 1)); use rocket::response::Responder; #[get("/")] fn half_c<'r>() -> Either< Inner>, Result> > { Either::Left(Inner(())) } let err = Client::debug_with(routes![half_c]).unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 2)); #[get("/")] fn half_d<'r>() -> Either< Inner>, Result, Inner> > { Either::Left(Inner(())) } let err = Client::debug_with(routes![half_d]).unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 1)); // The special `Result` implementation. type MyResult = Result; #[get("/")] fn half_e<'r>() -> Either>, MyResult> { Either::Left(Inner(())) } let err = Client::debug_with(routes![half_e]).unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 1)); // Another specialized sentinel. #[get("/")] fn either_route() -> Either { todo!() } let err = Client::debug_with(routes![either_route]).unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 1)); #[get("/")] fn either_route2() -> Either { todo!() } let err = Client::debug_with(routes![either_route2]).unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 1)); #[get("/")] fn either_route3() -> Either<(), ResponderSentinel> { todo!() } let err = Client::debug_with(routes![either_route3]).unwrap_err(); assert!(matches!(err.kind(), SentinelAborts(vec) if vec.len() == 1)); #[get("/")] fn either_route4() -> Either<(), ()> { todo!() } Client::debug_with(routes![either_route4]).expect("no sentinel error"); }