mirror of
https://github.com/tokio-rs/axum.git
synced 2025-04-26 13:56:22 +02:00
Add internal macro to make tests of nest
easier to write (#1694)
This commit is contained in:
parent
607a20dfac
commit
1be25d9496
31 changed files with 230 additions and 159 deletions
axum-macros
axum
Cargo.toml
src
extract
form.rshandler
json.rslib.rsmiddleware
response
routing
typed_header.rs
|
@ -11,6 +11,10 @@ readme = "README.md"
|
|||
repository = "https://github.com/tokio-rs/axum"
|
||||
version = "0.3.1" # remember to also bump the version that axum and axum-extra depends on
|
||||
|
||||
[features]
|
||||
default = []
|
||||
__private = ["syn/visit-mut"]
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
|
|
45
axum-macros/src/axum_test.rs
Normal file
45
axum-macros/src/axum_test.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{parse::Parse, parse_quote, visit_mut::VisitMut, ItemFn};
|
||||
|
||||
pub(crate) fn expand(_attr: Attrs, mut item_fn: ItemFn) -> TokenStream {
|
||||
item_fn.attrs.push(parse_quote!(#[tokio::test]));
|
||||
|
||||
let nest_service_fn = replace_nest_with_nest_service(item_fn.clone());
|
||||
|
||||
quote! {
|
||||
#item_fn
|
||||
#nest_service_fn
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Attrs;
|
||||
|
||||
impl Parse for Attrs {
|
||||
fn parse(_input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
|
||||
fn replace_nest_with_nest_service(mut item_fn: ItemFn) -> Option<ItemFn> {
|
||||
item_fn.sig.ident = format_ident!("{}_with_nest_service", item_fn.sig.ident);
|
||||
|
||||
let mut visitor = NestToNestService::default();
|
||||
syn::visit_mut::visit_item_fn_mut(&mut visitor, &mut item_fn);
|
||||
|
||||
(visitor.count > 0).then(|| item_fn)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct NestToNestService {
|
||||
count: usize,
|
||||
}
|
||||
|
||||
impl VisitMut for NestToNestService {
|
||||
fn visit_expr_method_call_mut(&mut self, i: &mut syn::ExprMethodCall) {
|
||||
if i.method == "nest" && i.args.len() == 2 {
|
||||
i.method = parse_quote!(nest_service);
|
||||
self.count += 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -48,6 +48,8 @@ use quote::{quote, ToTokens};
|
|||
use syn::{parse::Parse, Type};
|
||||
|
||||
mod attr_parsing;
|
||||
#[cfg(feature = "__private")]
|
||||
mod axum_test;
|
||||
mod debug_handler;
|
||||
mod from_ref;
|
||||
mod from_request;
|
||||
|
@ -555,6 +557,22 @@ pub fn debug_handler(_attr: TokenStream, input: TokenStream) -> TokenStream {
|
|||
return expand_attr_with(_attr, input, debug_handler::expand);
|
||||
}
|
||||
|
||||
/// Private API: Do no use this!
|
||||
///
|
||||
/// Attribute macro to be placed on test functions that'll generate two functions:
|
||||
///
|
||||
/// 1. One identical to the function it was placed on.
|
||||
/// 2. One where calls to `Router::nest` has been replaced with `Router::nest_service`
|
||||
///
|
||||
/// This makes it easy to that `nest` and `nest_service` behaves in the same way, without having to
|
||||
/// manually write identical tests for both methods.
|
||||
#[cfg(feature = "__private")]
|
||||
#[proc_macro_attribute]
|
||||
#[doc(hidden)]
|
||||
pub fn __private_axum_test(_attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
expand_attr_with(_attr, input, axum_test::expand)
|
||||
}
|
||||
|
||||
/// Derive an implementation of [`axum_extra::routing::TypedPath`].
|
||||
///
|
||||
/// See that trait for more details.
|
||||
|
|
|
@ -68,6 +68,7 @@ rustversion = "1.0.9"
|
|||
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0"
|
||||
axum-macros = { path = "../axum-macros", version = "0.3.1", features = ["__private"] }
|
||||
futures = "0.3"
|
||||
quickcheck = "1.0"
|
||||
quickcheck_macros = "1.0"
|
||||
|
|
|
@ -148,7 +148,7 @@ mod tests {
|
|||
use crate::{routing::get, Router, Server};
|
||||
use std::net::{SocketAddr, TcpListener};
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn socket_addr() {
|
||||
async fn handler(ConnectInfo(addr): ConnectInfo<SocketAddr>) -> String {
|
||||
format!("{}", addr)
|
||||
|
@ -175,7 +175,7 @@ mod tests {
|
|||
assert!(body.starts_with("127.0.0.1:"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn custom() {
|
||||
#[derive(Clone, Debug)]
|
||||
struct MyConnectInfo {
|
||||
|
|
|
@ -90,7 +90,7 @@ mod tests {
|
|||
TestClient::new(Router::new().route("/", get(host_as_body)))
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn host_header() {
|
||||
let original_host = "some-domain:123";
|
||||
let host = test_client()
|
||||
|
@ -103,7 +103,7 @@ mod tests {
|
|||
assert_eq!(host, original_host);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn x_forwarded_host_header() {
|
||||
let original_host = "some-domain:456";
|
||||
let host = test_client()
|
||||
|
@ -116,7 +116,7 @@ mod tests {
|
|||
assert_eq!(host, original_host);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn x_forwarded_host_precedence_over_host_header() {
|
||||
let x_forwarded_host_header = "some-domain:456";
|
||||
let host_header = "some-domain:123";
|
||||
|
@ -131,7 +131,7 @@ mod tests {
|
|||
assert_eq!(host, x_forwarded_host_header);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn uri_host() {
|
||||
let host = test_client().get("/").send().await.text().await;
|
||||
assert!(host.contains("127.0.0.1"));
|
||||
|
|
|
@ -177,7 +177,7 @@ mod tests {
|
|||
};
|
||||
use http::{Request, StatusCode};
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn extracting_on_handler() {
|
||||
let app = Router::new().route(
|
||||
"/:a",
|
||||
|
@ -190,7 +190,7 @@ mod tests {
|
|||
assert_eq!(res.text().await, "/:a");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn extracting_on_handler_in_nested_router() {
|
||||
let app = Router::new().nest(
|
||||
"/:a",
|
||||
|
@ -206,7 +206,7 @@ mod tests {
|
|||
assert_eq!(res.text().await, "/:a/:b");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn extracting_on_handler_in_deeply_nested_router() {
|
||||
let app = Router::new().nest(
|
||||
"/:a",
|
||||
|
@ -225,7 +225,7 @@ mod tests {
|
|||
assert_eq!(res.text().await, "/:a/:b/:c");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn cannot_extract_nested_matched_path_in_middleware() {
|
||||
async fn extract_matched_path<B>(
|
||||
matched_path: Option<MatchedPath>,
|
||||
|
@ -245,7 +245,7 @@ mod tests {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn cannot_extract_nested_matched_path_in_middleware_via_extension() {
|
||||
async fn assert_no_matched_path<B>(req: Request<B>) -> Request<B> {
|
||||
assert!(req.extensions().get::<MatchedPath>().is_none());
|
||||
|
@ -262,7 +262,7 @@ mod tests {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn can_extract_nested_matched_path_in_middleware_on_nested_router() {
|
||||
async fn extract_matched_path<B>(matched_path: MatchedPath, req: Request<B>) -> Request<B> {
|
||||
assert_eq!(matched_path.as_str(), "/:a/:b");
|
||||
|
@ -282,7 +282,7 @@ mod tests {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn can_extract_nested_matched_path_in_middleware_on_nested_router_via_extension() {
|
||||
async fn extract_matched_path<B>(req: Request<B>) -> Request<B> {
|
||||
let matched_path = req.extensions().get::<MatchedPath>().unwrap();
|
||||
|
@ -303,7 +303,7 @@ mod tests {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn extracting_on_nested_handler() {
|
||||
async fn handler(path: Option<MatchedPath>) {
|
||||
assert!(path.is_none());
|
||||
|
|
|
@ -102,7 +102,7 @@ pub(super) fn has_content_type(headers: &HeaderMap, expected_content_type: &mime
|
|||
mod tests {
|
||||
use crate::{routing::get, test_helpers::*, Router};
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn consume_body() {
|
||||
let app = Router::new().route("/", get(|body: String| async { body }));
|
||||
|
||||
|
|
|
@ -250,7 +250,7 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::{body::Body, response::IntoResponse, routing::post, test_helpers::*, Router};
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn content_type_with_encoding() {
|
||||
const BYTES: &[u8] = "<!doctype html><title>🦀</title>".as_bytes();
|
||||
const FILE_NAME: &str = "index.html";
|
||||
|
|
|
@ -440,7 +440,7 @@ mod tests {
|
|||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn extracting_url_params() {
|
||||
let app = Router::new().route(
|
||||
"/users/:id",
|
||||
|
@ -461,7 +461,7 @@ mod tests {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn extracting_url_params_multiple_times() {
|
||||
let app = Router::new().route("/users/:id", get(|_: Path<i32>, _: Path<String>| async {}));
|
||||
|
||||
|
@ -471,7 +471,7 @@ mod tests {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn percent_decoding() {
|
||||
let app = Router::new().route(
|
||||
"/:key",
|
||||
|
@ -485,7 +485,7 @@ mod tests {
|
|||
assert_eq!(res.text().await, "one two");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn supports_128_bit_numbers() {
|
||||
let app = Router::new()
|
||||
.route(
|
||||
|
@ -506,7 +506,7 @@ mod tests {
|
|||
assert_eq!(res.text().await, "123");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn wildcard() {
|
||||
let app = Router::new()
|
||||
.route(
|
||||
|
@ -529,7 +529,7 @@ mod tests {
|
|||
assert_eq!(res.text().await, "baz/qux");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn captures_dont_match_empty_segments() {
|
||||
let app = Router::new().route("/:key", get(|| async {}));
|
||||
|
||||
|
@ -542,7 +542,7 @@ mod tests {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn str_reference_deserialize() {
|
||||
struct Param(String);
|
||||
impl<'de> serde::Deserialize<'de> for Param {
|
||||
|
@ -567,7 +567,7 @@ mod tests {
|
|||
assert_eq!(res.text().await, "foo bar");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn two_path_extractors() {
|
||||
let app = Router::new().route("/:a/:b", get(|_: Path<String>, _: Path<String>| async {}));
|
||||
|
||||
|
@ -582,7 +582,7 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn deserialize_into_vec_of_tuples() {
|
||||
let app = Router::new().route(
|
||||
"/:a/:b",
|
||||
|
@ -603,7 +603,7 @@ mod tests {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn type_that_uses_deserialize_any() {
|
||||
use time::Date;
|
||||
|
||||
|
@ -694,7 +694,7 @@ mod tests {
|
|||
assert_eq!(res.text().await, "struct: 2023-01-01 2023-01-02 2023-01-03");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn wrong_number_of_parameters_json() {
|
||||
use serde_json::Value;
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ mod tests {
|
|||
assert_eq!(Query::<T>::from_request(req, &()).await.unwrap().0, value);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn test_query() {
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
struct Pagination {
|
||||
|
@ -127,7 +127,7 @@ mod tests {
|
|||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn correct_rejection_status_code() {
|
||||
#[derive(Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
|
|
|
@ -92,21 +92,21 @@ mod tests {
|
|||
assert_eq!(RawForm::from_request(req, &()).await.unwrap().0, body);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn test_from_query() {
|
||||
check_query("http://example.com/test", b"").await;
|
||||
|
||||
check_query("http://example.com/test?page=0&size=10", b"page=0&size=10").await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn test_from_body() {
|
||||
check_body(b"").await;
|
||||
|
||||
check_body(b"username=user&password=secure%20password").await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn test_incorrect_content_type() {
|
||||
let req = Request::post("http://example.com/test")
|
||||
.body(Full::<Bytes>::from(Bytes::from("page=0&size=10")))
|
||||
|
|
|
@ -226,7 +226,7 @@ mod tests {
|
|||
use crate::{extract::Extension, routing::get, test_helpers::*, Router};
|
||||
use http::{Method, StatusCode};
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn extract_request_parts() {
|
||||
#[derive(Clone)]
|
||||
struct Ext;
|
||||
|
|
|
@ -814,7 +814,7 @@ mod tests {
|
|||
use http::{Request, Version};
|
||||
use tower::ServiceExt;
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn rejects_http_1_0_requests() {
|
||||
let svc = get(|ws: Result<WebSocketUpgrade, WebSocketUpgradeRejection>| {
|
||||
let rejection = ws.unwrap_err();
|
||||
|
|
|
@ -149,7 +149,7 @@ mod tests {
|
|||
assert_eq!(Form::<T>::from_request(req, &()).await.unwrap().0, value);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn test_form_query() {
|
||||
check_query(
|
||||
"http://example.com/test",
|
||||
|
@ -179,7 +179,7 @@ mod tests {
|
|||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn test_form_body() {
|
||||
check_body(Pagination {
|
||||
size: None,
|
||||
|
@ -200,7 +200,7 @@ mod tests {
|
|||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn test_incorrect_content_type() {
|
||||
let req = Request::builder()
|
||||
.uri("http://example.com/test")
|
||||
|
|
|
@ -352,7 +352,7 @@ mod tests {
|
|||
timeout::TimeoutLayer,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn handler_into_service() {
|
||||
async fn handle(body: String) -> impl IntoResponse {
|
||||
format!("you said: {}", body)
|
||||
|
@ -365,7 +365,7 @@ mod tests {
|
|||
assert_eq!(res.text().await, "you said: hi there!");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn with_layer_that_changes_request_body_and_state() {
|
||||
async fn handle(State(state): State<&'static str>) -> &'static str {
|
||||
state
|
||||
|
|
|
@ -226,7 +226,7 @@ mod tests {
|
|||
use serde::Deserialize;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn deserialize_body() {
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Input {
|
||||
|
@ -242,7 +242,7 @@ mod tests {
|
|||
assert_eq!(body, "bar");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn consume_body_to_json_requires_json_content_type() {
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Input {
|
||||
|
@ -259,7 +259,7 @@ mod tests {
|
|||
assert_eq!(status, StatusCode::UNSUPPORTED_MEDIA_TYPE);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn json_content_types() {
|
||||
async fn valid_json_content_type(content_type: &str) -> bool {
|
||||
println!("testing {:?}", content_type);
|
||||
|
@ -283,7 +283,7 @@ mod tests {
|
|||
assert!(!valid_json_content_type("text/json").await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn invalid_json_syntax() {
|
||||
let app = Router::new().route("/", post(|_: Json<serde_json::Value>| async {}));
|
||||
|
||||
|
@ -314,7 +314,7 @@ mod tests {
|
|||
y: i32,
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn invalid_json_data() {
|
||||
let app = Router::new().route("/", post(|_: Json<Foo>| async {}));
|
||||
|
||||
|
|
|
@ -493,3 +493,6 @@ pub use axum_core::{BoxError, Error, RequestExt, RequestPartsExt};
|
|||
pub use axum_macros::debug_handler;
|
||||
|
||||
pub use self::service_ext::ServiceExt;
|
||||
|
||||
#[cfg(test)]
|
||||
use axum_macros::__private_axum_test as test;
|
||||
|
|
|
@ -309,7 +309,7 @@ mod tests {
|
|||
use http::{header, request::Parts, StatusCode};
|
||||
use tower_http::limit::RequestBodyLimitLayer;
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn test_from_extractor() {
|
||||
#[derive(Clone)]
|
||||
struct Secret(&'static str);
|
||||
|
|
|
@ -372,7 +372,7 @@ mod tests {
|
|||
use http::{HeaderMap, StatusCode};
|
||||
use tower::ServiceExt;
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn basic() {
|
||||
async fn insert_header<B>(mut req: Request<B>, next: Next<B>) -> impl IntoResponse {
|
||||
req.headers_mut()
|
||||
|
|
|
@ -385,7 +385,7 @@ mod tests {
|
|||
use crate::{routing::get, test_helpers::TestClient, Router};
|
||||
use http::{HeaderMap, StatusCode};
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn works() {
|
||||
async fn add_header<B>(mut req: Request<B>) -> Request<B> {
|
||||
req.headers_mut().insert("x-foo", "foo".parse().unwrap());
|
||||
|
@ -410,7 +410,7 @@ mod tests {
|
|||
assert_eq!(res.text().await, "foo");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn works_for_short_circutting() {
|
||||
async fn add_header<B>(_req: Request<B>) -> Result<Request<B>, (StatusCode, &'static str)> {
|
||||
Err((StatusCode::INTERNAL_SERVER_ERROR, "something went wrong"))
|
||||
|
|
|
@ -346,7 +346,7 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::{test_helpers::TestClient, Router};
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn works() {
|
||||
async fn add_header<B>(mut res: Response<B>) -> Response<B> {
|
||||
res.headers_mut().insert("x-foo", "foo".parse().unwrap());
|
||||
|
|
|
@ -508,7 +508,7 @@ mod tests {
|
|||
assert_eq!(&*leading_space.finalize(), b"data: foobar\n\n");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn basic() {
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
|
|
|
@ -1280,7 +1280,7 @@ mod tests {
|
|||
use tower::{timeout::TimeoutLayer, Service, ServiceBuilder, ServiceExt};
|
||||
use tower_http::{auth::RequireAuthorizationLayer, services::fs::ServeDir};
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn method_not_allowed_by_default() {
|
||||
let mut svc = MethodRouter::new();
|
||||
let (status, _, body) = call(Method::GET, &mut svc).await;
|
||||
|
@ -1288,7 +1288,7 @@ mod tests {
|
|||
assert!(body.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn get_service_fn() {
|
||||
async fn handle(_req: Request<Body>) -> Result<Response<Body>, Infallible> {
|
||||
Ok(Response::new(Body::from("ok")))
|
||||
|
@ -1301,7 +1301,7 @@ mod tests {
|
|||
assert_eq!(body, "ok");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn get_handler() {
|
||||
let mut svc = MethodRouter::new().get(ok);
|
||||
let (status, _, body) = call(Method::GET, &mut svc).await;
|
||||
|
@ -1309,7 +1309,7 @@ mod tests {
|
|||
assert_eq!(body, "ok");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn get_accepts_head() {
|
||||
let mut svc = MethodRouter::new().get(ok);
|
||||
let (status, _, body) = call(Method::HEAD, &mut svc).await;
|
||||
|
@ -1317,7 +1317,7 @@ mod tests {
|
|||
assert!(body.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn head_takes_precedence_over_get() {
|
||||
let mut svc = MethodRouter::new().head(created).get(ok);
|
||||
let (status, _, body) = call(Method::HEAD, &mut svc).await;
|
||||
|
@ -1325,7 +1325,7 @@ mod tests {
|
|||
assert!(body.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn merge() {
|
||||
let mut svc = get(ok).merge(post(ok));
|
||||
|
||||
|
@ -1336,7 +1336,7 @@ mod tests {
|
|||
assert_eq!(status, StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn layer() {
|
||||
let mut svc = MethodRouter::new()
|
||||
.get(|| async { std::future::pending::<()>().await })
|
||||
|
@ -1351,7 +1351,7 @@ mod tests {
|
|||
assert_eq!(status, StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn route_layer() {
|
||||
let mut svc = MethodRouter::new()
|
||||
.get(|| async { std::future::pending::<()>().await })
|
||||
|
@ -1392,7 +1392,7 @@ mod tests {
|
|||
crate::Server::bind(&"0.0.0.0:0".parse().unwrap()).serve(app.into_make_service());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn sets_allow_header() {
|
||||
let mut svc = MethodRouter::new().put(ok).patch(ok);
|
||||
let (status, headers, _) = call(Method::GET, &mut svc).await;
|
||||
|
@ -1400,7 +1400,7 @@ mod tests {
|
|||
assert_eq!(headers[ALLOW], "PUT,PATCH");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn sets_allow_header_get_head() {
|
||||
let mut svc = MethodRouter::new().get(ok).head(ok);
|
||||
let (status, headers, _) = call(Method::PUT, &mut svc).await;
|
||||
|
@ -1408,7 +1408,7 @@ mod tests {
|
|||
assert_eq!(headers[ALLOW], "GET,HEAD");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn empty_allow_header_by_default() {
|
||||
let mut svc = MethodRouter::new();
|
||||
let (status, headers, _) = call(Method::PATCH, &mut svc).await;
|
||||
|
@ -1416,7 +1416,7 @@ mod tests {
|
|||
assert_eq!(headers[ALLOW], "");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn allow_header_when_merging() {
|
||||
let a = put(ok).patch(ok);
|
||||
let b = get(ok).head(ok);
|
||||
|
@ -1427,7 +1427,7 @@ mod tests {
|
|||
assert_eq!(headers[ALLOW], "PUT,PATCH,GET,HEAD");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn allow_header_any() {
|
||||
let mut svc = any(ok);
|
||||
|
||||
|
@ -1436,7 +1436,7 @@ mod tests {
|
|||
assert!(!headers.contains_key(ALLOW));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn allow_header_with_fallback() {
|
||||
let mut svc = MethodRouter::new()
|
||||
.get(ok)
|
||||
|
@ -1447,7 +1447,7 @@ mod tests {
|
|||
assert_eq!(headers[ALLOW], "GET,HEAD");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn allow_header_with_fallback_that_sets_allow() {
|
||||
async fn fallback(method: Method) -> Response {
|
||||
if method == Method::POST {
|
||||
|
@ -1475,7 +1475,7 @@ mod tests {
|
|||
assert_eq!(headers[ALLOW], "GET,POST");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
#[should_panic(
|
||||
expected = "Overlapping method route. Cannot add two method routes that both handle `GET`"
|
||||
)]
|
||||
|
@ -1483,7 +1483,7 @@ mod tests {
|
|||
let _: MethodRouter<()> = get(ok).get(ok);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
#[should_panic(
|
||||
expected = "Overlapping method route. Cannot add two method routes that both handle `POST`"
|
||||
)]
|
||||
|
@ -1491,17 +1491,17 @@ mod tests {
|
|||
let _: MethodRouter<()> = post_service(ok.into_service()).post_service(ok.into_service());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn get_head_does_not_overlap() {
|
||||
let _: MethodRouter<()> = get(ok).head(ok);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn head_get_does_not_overlap() {
|
||||
let _: MethodRouter<()> = head(ok).get(ok);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn accessing_state() {
|
||||
let mut svc = MethodRouter::new()
|
||||
.get(|State(state): State<&'static str>| async move { state })
|
||||
|
@ -1513,7 +1513,7 @@ mod tests {
|
|||
assert_eq!(text, "state");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn fallback_accessing_state() {
|
||||
let mut svc = MethodRouter::new()
|
||||
.fallback(|State(state): State<&'static str>| async move { state })
|
||||
|
@ -1525,7 +1525,7 @@ mod tests {
|
|||
assert_eq!(text, "state");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn merge_accessing_state() {
|
||||
let one = get(|State(state): State<&'static str>| async move { state });
|
||||
let two = post(|State(state): State<&'static str>| async move { state });
|
||||
|
|
|
@ -3,7 +3,7 @@ use tower::ServiceExt;
|
|||
use super::*;
|
||||
use crate::middleware::{map_request, map_response};
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn basic() {
|
||||
let app = Router::new()
|
||||
.route("/foo", get(|| async {}))
|
||||
|
@ -18,7 +18,7 @@ async fn basic() {
|
|||
assert_eq!(res.text().await, "fallback");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nest() {
|
||||
let app = Router::new()
|
||||
.nest("/foo", Router::new().route("/bar", get(|| async {})))
|
||||
|
@ -33,7 +33,7 @@ async fn nest() {
|
|||
assert_eq!(res.text().await, "fallback");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn or() {
|
||||
let one = Router::new().route("/one", get(|| async {}));
|
||||
let two = Router::new().route("/two", get(|| async {}));
|
||||
|
@ -50,7 +50,7 @@ async fn or() {
|
|||
assert_eq!(res.text().await, "fallback");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn fallback_accessing_state() {
|
||||
let app = Router::new()
|
||||
.fallback(|State(state): State<&'static str>| async move { state })
|
||||
|
@ -71,7 +71,7 @@ async fn outer_fallback() -> impl IntoResponse {
|
|||
(StatusCode::NOT_FOUND, "outer")
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nested_router_inherits_fallback() {
|
||||
let inner = Router::new();
|
||||
let app = Router::new().nest("/foo", inner).fallback(outer_fallback);
|
||||
|
@ -83,7 +83,7 @@ async fn nested_router_inherits_fallback() {
|
|||
assert_eq!(res.text().await, "outer");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn doesnt_inherit_fallback_if_overriden() {
|
||||
let inner = Router::new().fallback(inner_fallback);
|
||||
let app = Router::new().nest("/foo", inner).fallback(outer_fallback);
|
||||
|
@ -95,7 +95,7 @@ async fn doesnt_inherit_fallback_if_overriden() {
|
|||
assert_eq!(res.text().await, "inner");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn deeply_nested_inherit_from_top() {
|
||||
let app = Router::new()
|
||||
.nest("/foo", Router::new().nest("/bar", Router::new()))
|
||||
|
@ -108,7 +108,7 @@ async fn deeply_nested_inherit_from_top() {
|
|||
assert_eq!(res.text().await, "outer");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn deeply_nested_inherit_from_middle() {
|
||||
let app = Router::new().nest(
|
||||
"/foo",
|
||||
|
@ -124,7 +124,7 @@ async fn deeply_nested_inherit_from_middle() {
|
|||
assert_eq!(res.text().await, "outer");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn with_middleware_on_inner_fallback() {
|
||||
async fn never_called<B>(_: Request<B>) -> Request<B> {
|
||||
panic!("should never be called")
|
||||
|
@ -140,7 +140,7 @@ async fn with_middleware_on_inner_fallback() {
|
|||
assert_eq!(res.text().await, "outer");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn also_inherits_default_layered_fallback() {
|
||||
async fn set_header<B>(mut res: Response<B>) -> Response<B> {
|
||||
res.headers_mut()
|
||||
|
@ -162,7 +162,7 @@ async fn also_inherits_default_layered_fallback() {
|
|||
assert_eq!(res.text().await, "outer");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn fallback_inherited_into_nested_router_service() {
|
||||
let inner = Router::new()
|
||||
.route(
|
||||
|
@ -182,7 +182,7 @@ async fn fallback_inherited_into_nested_router_service() {
|
|||
assert_eq!(res.text().await, "outer");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn fallback_inherited_into_nested_opaque_service() {
|
||||
let inner = Router::new()
|
||||
.route(
|
||||
|
|
|
@ -6,7 +6,7 @@ mod for_handlers {
|
|||
use super::*;
|
||||
use http::HeaderMap;
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn get_handles_head() {
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
|
@ -41,7 +41,7 @@ mod for_services {
|
|||
use super::*;
|
||||
use crate::routing::get_service;
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn get_handles_head() {
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
|
|
|
@ -29,7 +29,7 @@ impl<R> Service<R> for Svc {
|
|||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn handler() {
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
|
@ -48,7 +48,7 @@ async fn handler() {
|
|||
assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn handler_multiple_methods_first() {
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
|
@ -68,7 +68,7 @@ async fn handler_multiple_methods_first() {
|
|||
assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn handler_multiple_methods_middle() {
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
|
@ -91,7 +91,7 @@ async fn handler_multiple_methods_middle() {
|
|||
assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn handler_multiple_methods_last() {
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{error_handling::HandleErrorLayer, extract::OriginalUri, response::In
|
|||
use serde_json::{json, Value};
|
||||
use tower::{limit::ConcurrencyLimitLayer, timeout::TimeoutLayer};
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn basic() {
|
||||
let one = Router::new()
|
||||
.route("/foo", get(|| async {}))
|
||||
|
@ -26,7 +26,7 @@ async fn basic() {
|
|||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn multiple_ors_balanced_differently() {
|
||||
let one = Router::new().route("/one", get(|| async { "one" }));
|
||||
let two = Router::new().route("/two", get(|| async { "two" }));
|
||||
|
@ -71,7 +71,7 @@ async fn multiple_ors_balanced_differently() {
|
|||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nested_or() {
|
||||
let bar = Router::new().route("/bar", get(|| async { "bar" }));
|
||||
let baz = Router::new().route("/baz", get(|| async { "baz" }));
|
||||
|
@ -87,7 +87,7 @@ async fn nested_or() {
|
|||
assert_eq!(client.get("/foo/baz").send().await.text().await, "baz");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn or_with_route_following() {
|
||||
let one = Router::new().route("/one", get(|| async { "one" }));
|
||||
let two = Router::new().route("/two", get(|| async { "two" }));
|
||||
|
@ -105,7 +105,7 @@ async fn or_with_route_following() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn layer() {
|
||||
let one = Router::new().route("/foo", get(|| async {}));
|
||||
let two = Router::new()
|
||||
|
@ -122,7 +122,7 @@ async fn layer() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn layer_and_handle_error() {
|
||||
let one = Router::new().route("/foo", get(|| async {}));
|
||||
let two = Router::new()
|
||||
|
@ -142,7 +142,7 @@ async fn layer_and_handle_error() {
|
|||
assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nesting() {
|
||||
let one = Router::new().route("/foo", get(|| async {}));
|
||||
let two = Router::new().nest("/bar", Router::new().route("/baz", get(|| async {})));
|
||||
|
@ -154,7 +154,7 @@ async fn nesting() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn boxed() {
|
||||
let one = Router::new().route("/foo", get(|| async {}));
|
||||
let two = Router::new().route("/bar", get(|| async {}));
|
||||
|
@ -166,7 +166,7 @@ async fn boxed() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn many_ors() {
|
||||
let app = Router::new()
|
||||
.route("/r1", get(|| async {}))
|
||||
|
@ -188,7 +188,7 @@ async fn many_ors() {
|
|||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn services() {
|
||||
use crate::routing::get_service;
|
||||
|
||||
|
@ -227,7 +227,7 @@ async fn all_the_uris(
|
|||
}))
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nesting_and_seeing_the_right_uri() {
|
||||
let one = Router::new().nest("/foo/", Router::new().route("/bar", get(all_the_uris)));
|
||||
let two = Router::new().route("/foo", get(all_the_uris));
|
||||
|
@ -257,7 +257,7 @@ async fn nesting_and_seeing_the_right_uri() {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nesting_and_seeing_the_right_uri_at_more_levels_of_nesting() {
|
||||
let one = Router::new().nest(
|
||||
"/foo/",
|
||||
|
@ -290,7 +290,7 @@ async fn nesting_and_seeing_the_right_uri_at_more_levels_of_nesting() {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nesting_and_seeing_the_right_uri_ors_with_nesting() {
|
||||
let one = Router::new().nest(
|
||||
"/one",
|
||||
|
@ -335,7 +335,7 @@ async fn nesting_and_seeing_the_right_uri_ors_with_nesting() {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nesting_and_seeing_the_right_uri_ors_with_multi_segment_uris() {
|
||||
let one = Router::new().nest(
|
||||
"/one",
|
||||
|
@ -368,7 +368,7 @@ async fn nesting_and_seeing_the_right_uri_ors_with_multi_segment_uris() {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn middleware_that_return_early() {
|
||||
let private = Router::new()
|
||||
.route("/", get(|| async {}))
|
||||
|
|
|
@ -29,7 +29,7 @@ mod handle_error;
|
|||
mod merge;
|
||||
mod nest;
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn hello_world() {
|
||||
async fn root(_: Request<Body>) -> &'static str {
|
||||
"Hello, World!"
|
||||
|
@ -62,7 +62,7 @@ async fn hello_world() {
|
|||
assert_eq!(body, "users#create");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn routing() {
|
||||
let app = Router::new()
|
||||
.route(
|
||||
|
@ -98,7 +98,7 @@ async fn routing() {
|
|||
assert_eq!(res.text().await, "users#action");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn router_type_doesnt_change() {
|
||||
let app: Router = Router::new()
|
||||
.route(
|
||||
|
@ -123,7 +123,7 @@ async fn router_type_doesnt_change() {
|
|||
assert_eq!(res.text().await, "hi from POST");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn routing_between_services() {
|
||||
use std::convert::Infallible;
|
||||
use tower::service_fn;
|
||||
|
@ -169,7 +169,7 @@ async fn routing_between_services() {
|
|||
assert_eq!(res.text().await, "handler");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn middleware_on_single_route() {
|
||||
use tower::ServiceBuilder;
|
||||
use tower_http::{compression::CompressionLayer, trace::TraceLayer};
|
||||
|
@ -196,7 +196,7 @@ async fn middleware_on_single_route() {
|
|||
assert_eq!(body, "Hello, World!");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn service_in_bottom() {
|
||||
async fn handler(_req: Request<Body>) -> Result<Response<Body>, Infallible> {
|
||||
Ok(Response::new(hyper::Body::empty()))
|
||||
|
@ -207,7 +207,7 @@ async fn service_in_bottom() {
|
|||
TestClient::new(app);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn wrong_method_handler() {
|
||||
let app = Router::new()
|
||||
.route("/", get(|| async {}).post(|| async {}))
|
||||
|
@ -230,7 +230,7 @@ async fn wrong_method_handler() {
|
|||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn wrong_method_service() {
|
||||
#[derive(Clone)]
|
||||
struct Svc;
|
||||
|
@ -270,7 +270,7 @@ async fn wrong_method_service() {
|
|||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn multiple_methods_for_one_handler() {
|
||||
async fn root(_: Request<Body>) -> &'static str {
|
||||
"Hello, World!"
|
||||
|
@ -287,7 +287,7 @@ async fn multiple_methods_for_one_handler() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn wildcard_sees_whole_url() {
|
||||
let app = Router::new().route("/api/*rest", get(|uri: Uri| async move { uri.to_string() }));
|
||||
|
||||
|
@ -297,7 +297,7 @@ async fn wildcard_sees_whole_url() {
|
|||
assert_eq!(res.text().await, "/api/foo/bar");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn middleware_applies_to_routes_above() {
|
||||
let app = Router::new()
|
||||
.route("/one", get(std::future::pending::<()>))
|
||||
|
@ -319,7 +319,7 @@ async fn middleware_applies_to_routes_above() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn not_found_for_extra_trailing_slash() {
|
||||
let app = Router::new().route("/foo", get(|| async {}));
|
||||
|
||||
|
@ -332,7 +332,7 @@ async fn not_found_for_extra_trailing_slash() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn not_found_for_missing_trailing_slash() {
|
||||
let app = Router::new().route("/foo/", get(|| async {}));
|
||||
|
||||
|
@ -342,7 +342,7 @@ async fn not_found_for_missing_trailing_slash() {
|
|||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn with_and_without_trailing_slash() {
|
||||
let app = Router::new()
|
||||
.route("/foo", get(|| async { "without tsr" }))
|
||||
|
@ -360,7 +360,7 @@ async fn with_and_without_trailing_slash() {
|
|||
}
|
||||
|
||||
// for https://github.com/tokio-rs/axum/issues/420
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn wildcard_doesnt_match_just_trailing_slash() {
|
||||
let app = Router::new().route(
|
||||
"/x/*path",
|
||||
|
@ -380,7 +380,7 @@ async fn wildcard_doesnt_match_just_trailing_slash() {
|
|||
assert_eq!(res.text().await, "foo/bar");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn static_and_dynamic_paths() {
|
||||
let app = Router::new()
|
||||
.route(
|
||||
|
@ -398,14 +398,14 @@ async fn static_and_dynamic_paths() {
|
|||
assert_eq!(res.text().await, "static");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
#[should_panic(expected = "Paths must start with a `/`. Use \"/\" for root routes")]
|
||||
async fn empty_route() {
|
||||
let app = Router::new().route("", get(|| async {}));
|
||||
TestClient::new(app);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn middleware_still_run_for_unmatched_requests() {
|
||||
#[derive(Clone)]
|
||||
struct CountMiddleware<S>(S);
|
||||
|
@ -445,7 +445,7 @@ async fn middleware_still_run_for_unmatched_requests() {
|
|||
assert_eq!(COUNT.load(Ordering::SeqCst), 2);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
#[should_panic(expected = "\
|
||||
Invalid route: `Router::route_service` cannot be used with `Router`s. \
|
||||
Use `Router::nest` instead\
|
||||
|
@ -454,7 +454,7 @@ async fn routing_to_router_panics() {
|
|||
TestClient::new(Router::new().route_service("/", Router::new()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn route_layer() {
|
||||
let app = Router::new()
|
||||
.route("/foo", get(|| async {}))
|
||||
|
@ -482,7 +482,7 @@ async fn route_layer() {
|
|||
assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn different_methods_added_in_different_routes() {
|
||||
let app = Router::new()
|
||||
.route("/", get(|| async { "GET" }))
|
||||
|
@ -499,7 +499,7 @@ async fn different_methods_added_in_different_routes() {
|
|||
assert_eq!(body, "POST");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
#[should_panic(expected = "Cannot merge two `Router`s that both have a fallback")]
|
||||
async fn merging_routers_with_fallbacks_panics() {
|
||||
async fn fallback() {}
|
||||
|
@ -525,7 +525,7 @@ fn merging_with_overlapping_method_routes() {
|
|||
app.clone().merge(app);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn merging_routers_with_same_paths_but_different_methods() {
|
||||
let one = Router::new().route("/", get(|| async { "GET" }));
|
||||
let two = Router::new().route("/", post(|| async { "POST" }));
|
||||
|
@ -541,7 +541,7 @@ async fn merging_routers_with_same_paths_but_different_methods() {
|
|||
assert_eq!(body, "POST");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn head_content_length_through_hyper_server() {
|
||||
let app = Router::new()
|
||||
.route("/", get(|| async { "foo" }))
|
||||
|
@ -558,7 +558,7 @@ async fn head_content_length_through_hyper_server() {
|
|||
assert!(res.text().await.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn head_content_length_through_hyper_server_that_hits_fallback() {
|
||||
let app = Router::new().fallback(|| async { "foo" });
|
||||
|
||||
|
@ -568,7 +568,7 @@ async fn head_content_length_through_hyper_server_that_hits_fallback() {
|
|||
assert_eq!(res.headers()["content-length"], "3");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn head_with_middleware_applied() {
|
||||
use tower_http::compression::{predicate::SizeAbove, CompressionLayer};
|
||||
|
||||
|
@ -601,14 +601,14 @@ async fn head_with_middleware_applied() {
|
|||
assert!(!res.headers().contains_key("content-length"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
#[should_panic(expected = "Paths must start with a `/`")]
|
||||
async fn routes_must_start_with_slash() {
|
||||
let app = Router::new().route(":foo", get(|| async {}));
|
||||
TestClient::new(app);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn body_limited_by_default() {
|
||||
let app = Router::new()
|
||||
.route("/bytes", post(|_: Bytes| async {}))
|
||||
|
@ -636,7 +636,7 @@ async fn body_limited_by_default() {
|
|||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn disabling_the_default_limit() {
|
||||
let app = Router::new()
|
||||
.route("/", post(|_: Bytes| async {}))
|
||||
|
@ -652,7 +652,7 @@ async fn disabling_the_default_limit() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn limited_body_with_content_length() {
|
||||
const LIMIT: usize = 3;
|
||||
|
||||
|
@ -674,7 +674,7 @@ async fn limited_body_with_content_length() {
|
|||
assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn changing_the_default_limit() {
|
||||
let new_limit = 2;
|
||||
|
||||
|
@ -699,7 +699,7 @@ async fn changing_the_default_limit() {
|
|||
assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn limited_body_with_streaming_body() {
|
||||
const LIMIT: usize = 3;
|
||||
|
||||
|
@ -731,7 +731,7 @@ async fn limited_body_with_streaming_body() {
|
|||
assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn extract_state() {
|
||||
#[derive(Clone)]
|
||||
struct AppState {
|
||||
|
@ -767,7 +767,7 @@ async fn extract_state() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn explicitly_set_state() {
|
||||
let app = Router::new()
|
||||
.route_service(
|
||||
|
@ -781,7 +781,7 @@ async fn explicitly_set_state() {
|
|||
assert_eq!(res.text().await, "foo");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn layer_response_into_response() {
|
||||
fn map_response<B>(_res: Response<B>) -> Result<Response<B>, impl IntoResponse> {
|
||||
let headers = [("x-foo", "bar")];
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{body::boxed, extract::Extension};
|
|||
use std::collections::HashMap;
|
||||
use tower_http::services::ServeDir;
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nesting_apps() {
|
||||
let api_routes = Router::new()
|
||||
.route(
|
||||
|
@ -58,7 +58,7 @@ async fn nesting_apps() {
|
|||
assert_eq!(res.text().await, "v0: games#show (123)");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn wrong_method_nest() {
|
||||
let nested_app = Router::new().route("/", get(|| async {}));
|
||||
let app = Router::new().nest("/", nested_app);
|
||||
|
@ -76,7 +76,7 @@ async fn wrong_method_nest() {
|
|||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nesting_router_at_root() {
|
||||
let nested = Router::new().route("/foo", get(|uri: Uri| async move { uri.to_string() }));
|
||||
let app = Router::new().nest("/", nested);
|
||||
|
@ -94,7 +94,7 @@ async fn nesting_router_at_root() {
|
|||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nesting_router_at_empty_path() {
|
||||
let nested = Router::new().route("/foo", get(|uri: Uri| async move { uri.to_string() }));
|
||||
let app = Router::new().nest("", nested);
|
||||
|
@ -112,7 +112,7 @@ async fn nesting_router_at_empty_path() {
|
|||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nesting_handler_at_root() {
|
||||
let app = Router::new().nest_service("/", get(|uri: Uri| async move { uri.to_string() }));
|
||||
|
||||
|
@ -131,7 +131,7 @@ async fn nesting_handler_at_root() {
|
|||
assert_eq!(res.text().await, "/foo/bar");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nested_url_extractor() {
|
||||
let app = Router::new().nest(
|
||||
"/foo",
|
||||
|
@ -157,7 +157,7 @@ async fn nested_url_extractor() {
|
|||
assert_eq!(res.text().await, "/qux");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nested_url_original_extractor() {
|
||||
let app = Router::new().nest(
|
||||
"/foo",
|
||||
|
@ -177,7 +177,7 @@ async fn nested_url_original_extractor() {
|
|||
assert_eq!(res.text().await, "/foo/bar/baz");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nested_service_sees_stripped_uri() {
|
||||
let app = Router::new().nest(
|
||||
"/foo",
|
||||
|
@ -200,7 +200,7 @@ async fn nested_service_sees_stripped_uri() {
|
|||
assert_eq!(res.text().await, "/baz");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nest_static_file_server() {
|
||||
let app = Router::new().nest_service(
|
||||
"/static",
|
||||
|
@ -218,7 +218,7 @@ async fn nest_static_file_server() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nested_multiple_routes() {
|
||||
let app = Router::new()
|
||||
.nest(
|
||||
|
@ -244,7 +244,7 @@ fn nested_at_root_with_other_routes() {
|
|||
.route("/", get(|| async {}));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn multiple_top_level_nests() {
|
||||
let app = Router::new()
|
||||
.nest(
|
||||
|
@ -262,13 +262,13 @@ async fn multiple_top_level_nests() {
|
|||
assert_eq!(client.get("/two/route").send().await.text().await, "two");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
#[should_panic(expected = "Invalid route: nested routes cannot contain wildcards (*)")]
|
||||
async fn nest_cannot_contain_wildcards() {
|
||||
Router::<(), Body>::new().nest("/one/*rest", Router::new());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn outer_middleware_still_see_whole_url() {
|
||||
#[derive(Clone)]
|
||||
struct SetUriExtension<S>(S);
|
||||
|
@ -319,7 +319,7 @@ async fn outer_middleware_still_see_whole_url() {
|
|||
assert_eq!(client.get("/one/two").send().await.text().await, "/one/two");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nest_at_capture() {
|
||||
let api_routes = Router::new().route(
|
||||
"/:b",
|
||||
|
@ -335,7 +335,7 @@ async fn nest_at_capture() {
|
|||
assert_eq!(res.text().await, "a=foo b=bar");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nest_with_and_without_trailing() {
|
||||
let app = Router::new().nest_service("/foo", get(|| async {}));
|
||||
|
||||
|
@ -351,7 +351,7 @@ async fn nest_with_and_without_trailing() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn nesting_with_root_inner_router() {
|
||||
let app = Router::new().nest(
|
||||
"/foo",
|
||||
|
@ -371,7 +371,7 @@ async fn nesting_with_root_inner_router() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn fallback_on_inner() {
|
||||
let app = Router::new()
|
||||
.nest(
|
||||
|
@ -399,7 +399,7 @@ macro_rules! nested_route_test {
|
|||
// the route we expect to be able to call
|
||||
expected = $expected_path:literal $(,)?
|
||||
) => {
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn $name() {
|
||||
let inner = Router::new().route($route_path, get(|| async {}));
|
||||
let app = Router::new().nest($nested_path, inner);
|
||||
|
|
|
@ -170,7 +170,7 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::{response::IntoResponse, routing::get, test_helpers::*, Router};
|
||||
|
||||
#[tokio::test]
|
||||
#[crate::test]
|
||||
async fn typed_header() {
|
||||
async fn handle(
|
||||
TypedHeader(user_agent): TypedHeader<headers::UserAgent>,
|
||||
|
|
Loading…
Add table
Reference in a new issue