From a58368f871ad3627963c1a6543d69d89ced108ea Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 7 Jun 2024 19:31:34 +0100 Subject: [PATCH] test: split out scope tests --- actix-web-codegen/CHANGES.md | 2 +- .../tests/{test_macro.rs => routes.rs} | 194 +---------------- actix-web-codegen/tests/scopes.rs | 199 ++++++++++++++++++ 3 files changed, 201 insertions(+), 194 deletions(-) rename actix-web-codegen/tests/{test_macro.rs => routes.rs} (65%) create mode 100644 actix-web-codegen/tests/scopes.rs diff --git a/actix-web-codegen/CHANGES.md b/actix-web-codegen/CHANGES.md index e677b1f9e..792f6aa4f 100644 --- a/actix-web-codegen/CHANGES.md +++ b/actix-web-codegen/CHANGES.md @@ -2,9 +2,9 @@ ## Unreleased +- Add `#[scope]` macro. - Prevent inclusion of default `actix-router` features. - Minimum supported Rust version (MSRV) is now 1.72. -- Add a scope macro that takes a path ## 4.2.2 diff --git a/actix-web-codegen/tests/test_macro.rs b/actix-web-codegen/tests/routes.rs similarity index 65% rename from actix-web-codegen/tests/test_macro.rs rename to actix-web-codegen/tests/routes.rs index d62c5315b..fb50d4ae0 100644 --- a/actix-web-codegen/tests/test_macro.rs +++ b/actix-web-codegen/tests/routes.rs @@ -11,7 +11,7 @@ use actix_web::{ web, App, Error, HttpRequest, HttpResponse, Responder, }; use actix_web_codegen::{ - connect, delete, get, head, options, patch, post, put, route, routes, scope, trace, + connect, delete, get, head, options, patch, post, put, route, routes, trace, }; use futures_core::future::LocalBoxFuture; @@ -384,195 +384,3 @@ async fn test_wrap() { let body = String::from_utf8(body.to_vec()).unwrap(); assert!(body.contains("wrong number of parameters")); } - -#[scope("/test")] -mod scope_module { - use actix_web::{delete, get, post, route, routes, web, HttpResponse, Responder}; - - use crate::guard_module; - - #[get("/test/guard", guard = "guard_module::guard")] - pub async fn test_guard() -> impl Responder { - HttpResponse::Ok() - } - - #[get("/test")] - pub async fn test() -> impl Responder { - HttpResponse::Ok().finish() - } - - #[get("/twicetest/{value}")] - pub async fn test_twice(value: web::Path) -> impl actix_web::Responder { - let int_value: i32 = value.parse().unwrap_or(0); - let doubled = int_value * 2; - HttpResponse::Ok().body(format!("Twice value: {}", doubled)) - } - - #[post("/test")] - pub async fn test_post() -> impl Responder { - HttpResponse::Ok().body(format!("post works")) - } - - #[delete("/test")] - pub async fn test_delete() -> impl Responder { - HttpResponse::Ok().body("delete works") - } - - #[route("/test", method = "PUT", method = "PATCH", method = "CUSTOM")] - pub async fn test_multiple_shared_path() -> impl Responder { - HttpResponse::Ok().finish() - } - - #[routes] - #[head("/test")] - #[connect("/test")] - #[options("/test")] - #[trace("/test")] - async fn test_multiple_separate_paths() -> impl Responder { - HttpResponse::Ok().finish() - } - - // test calling this from other mod scope with scope attribute... - pub fn mod_common(message: String) -> impl actix_web::Responder { - HttpResponse::Ok().body(message) - } -} - -#[scope("/v1")] -mod mod_scope_v1 { - use actix_web::{get, Responder}; - - #[get("/test")] - #[doc = "doc string to check in cargo expand"] - pub async fn test() -> impl Responder { - super::scope_module::mod_common("version1 works".to_string()) - } -} - -#[scope("/v2")] -mod mod_scope_v2 { - use actix_web::{get, Responder}; - - // check to make sure non-function tokens in the scope block are preserved... - enum TestEnum { - Works, - } - - #[get("/test")] - pub async fn test() -> impl Responder { - // make sure this type still exists... - let test_enum = TestEnum::Works; - - match test_enum { - TestEnum::Works => super::scope_module::mod_common("version2 works".to_string()), - } - } -} - -#[actix_rt::test] -async fn test_scope_get_async() { - let srv = actix_test::start(|| App::new().service(scope_module::test)); - - let request = srv.request(http::Method::GET, srv.url("/test/test")); - let response = request.send().await.unwrap(); - assert!(response.status().is_success()); -} - -#[actix_rt::test] -async fn test_scope_get_param_async() { - let srv = actix_test::start(|| App::new().service(scope_module::test_twice)); - - let request = srv.request(http::Method::GET, srv.url("/test/twicetest/4")); - let mut response = request.send().await.unwrap(); - let body = response.body().await.unwrap(); - let body_str = String::from_utf8(body.to_vec()).unwrap(); - assert_eq!(body_str, "Twice value: 8"); -} - -#[actix_rt::test] -async fn test_scope_post_async() { - let srv = actix_test::start(|| App::new().service(scope_module::test_post)); - - let request = srv.request(http::Method::POST, srv.url("/test/test")); - let mut response = request.send().await.unwrap(); - let body = response.body().await.unwrap(); - let body_str = String::from_utf8(body.to_vec()).unwrap(); - assert_eq!(body_str, "post works"); -} - -#[actix_rt::test] -async fn test_multiple_shared_path_async() { - let srv = actix_test::start(|| App::new().service(scope_module::test_multiple_shared_path)); - - let request = srv.request(http::Method::PUT, srv.url("/test/test")); - let response = request.send().await.unwrap(); - assert!(response.status().is_success()); - - let request = srv.request(http::Method::PATCH, srv.url("/test/test")); - let response = request.send().await.unwrap(); - assert!(response.status().is_success()); -} - -#[actix_rt::test] -async fn test_multiple_multipaths_async() { - let srv = actix_test::start(|| App::new().service(scope_module::test_multiple_separate_paths)); - - let request = srv.request(http::Method::CONNECT, srv.url("/test/test")); - let response = request.send().await.unwrap(); - assert!(response.status().is_success()); - - let request = srv.request(http::Method::OPTIONS, srv.url("/test/test")); - let response = request.send().await.unwrap(); - assert!(response.status().is_success()); - - let request = srv.request(http::Method::TRACE, srv.url("/test/test")); - let response = request.send().await.unwrap(); - assert!(response.status().is_success()); - - let request = srv.request(http::Method::HEAD, srv.url("/test/test")); - let response = request.send().await.unwrap(); - assert!(response.status().is_success()); -} - -#[actix_rt::test] -async fn test_scope_delete_async() { - let srv = actix_test::start(|| App::new().service(scope_module::test_delete)); - - let request = srv.request(http::Method::DELETE, srv.url("/test/test")); - let mut response = request.send().await.unwrap(); - let body = response.body().await.unwrap(); - let body_str = String::from_utf8(body.to_vec()).unwrap(); - assert_eq!(body_str, "delete works"); -} - -#[actix_rt::test] -async fn test_scope_get_with_guard_async() { - let srv = actix_test::start(|| App::new().service(scope_module::test_guard)); - - let request = srv - .request(http::Method::GET, srv.url("/test/test/guard")) - .insert_header(("Accept", "image/*")); - let response = request.send().await.unwrap(); - assert!(response.status().is_success()); -} - -#[actix_rt::test] -async fn test_scope_v1_v2_async() { - let srv = actix_test::start(|| { - App::new() - .service(mod_scope_v1::test) - .service(mod_scope_v2::test) - }); - - let request = srv.request(http::Method::GET, srv.url("/v1/test")); - let mut response = request.send().await.unwrap(); - let body = response.body().await.unwrap(); - let body_str = String::from_utf8(body.to_vec()).unwrap(); - assert_eq!(body_str, "version1 works"); - - let request = srv.request(http::Method::GET, srv.url("/v2/test")); - let mut response = request.send().await.unwrap(); - let body = response.body().await.unwrap(); - let body_str = String::from_utf8(body.to_vec()).unwrap(); - assert_eq!(body_str, "version2 works"); -} diff --git a/actix-web-codegen/tests/scopes.rs b/actix-web-codegen/tests/scopes.rs new file mode 100644 index 000000000..9499af58b --- /dev/null +++ b/actix-web-codegen/tests/scopes.rs @@ -0,0 +1,199 @@ +use actix_web::{guard::GuardContext, http, http::header, web, App, HttpResponse, Responder}; +use actix_web_codegen::{delete, get, post, route, routes, scope}; + +pub fn image_guard(ctx: &GuardContext) -> bool { + ctx.header::() + .map(|h| h.preference() == "image/*") + .unwrap_or(false) +} + +#[scope("/test")] +mod scope_module { + use super::*; + + #[get("/test/guard", guard = "image_guard")] + pub async fn guard() -> impl Responder { + HttpResponse::Ok() + } + + #[get("/test")] + pub async fn test() -> impl Responder { + HttpResponse::Ok().finish() + } + + #[get("/twice-test/{value}")] + pub async fn twice(value: web::Path) -> impl actix_web::Responder { + let int_value: i32 = value.parse().unwrap_or(0); + let doubled = int_value * 2; + HttpResponse::Ok().body(format!("Twice value: {}", doubled)) + } + + #[post("/test")] + pub async fn post() -> impl Responder { + HttpResponse::Ok().body("post works") + } + + #[delete("/test")] + pub async fn delete() -> impl Responder { + "delete works" + } + + #[route("/test", method = "PUT", method = "PATCH", method = "CUSTOM")] + pub async fn multiple_shared_path() -> impl Responder { + HttpResponse::Ok().finish() + } + + #[routes] + #[head("/test1")] + #[connect("/test2")] + #[options("/test3")] + #[trace("/test4")] + async fn multiple_separate_paths() -> impl Responder { + HttpResponse::Ok().finish() + } + + // test calling this from other mod scope with scope attribute... + pub fn mod_common(message: String) -> impl actix_web::Responder { + HttpResponse::Ok().body(message) + } +} + +/// Scope doc string to check in cargo expand. +#[scope("/v1")] +mod mod_scope_v1 { + use actix_web::{get, Responder}; + + /// Route doc string to check in cargo expand. + #[get("/test")] + pub async fn test() -> impl Responder { + super::scope_module::mod_common("version1 works".to_string()) + } +} + +#[scope("/v2")] +mod mod_scope_v2 { + use actix_web::{get, Responder}; + + // check to make sure non-function tokens in the scope block are preserved... + enum TestEnum { + Works, + } + + #[get("/test")] + pub async fn test() -> impl Responder { + // make sure this type still exists... + let test_enum = TestEnum::Works; + + match test_enum { + TestEnum::Works => super::scope_module::mod_common("version2 works".to_string()), + } + } +} + +#[actix_rt::test] +async fn scope_get_async() { + let srv = actix_test::start(|| App::new().service(scope_module::test)); + + let request = srv.request(http::Method::GET, srv.url("/test/test")); + let response = request.send().await.unwrap(); + assert!(response.status().is_success()); +} + +#[actix_rt::test] +async fn scope_get_param_async() { + let srv = actix_test::start(|| App::new().service(scope_module::twice)); + + let request = srv.request(http::Method::GET, srv.url("/test/twice-test/4")); + let mut response = request.send().await.unwrap(); + let body = response.body().await.unwrap(); + let body_str = String::from_utf8(body.to_vec()).unwrap(); + assert_eq!(body_str, "Twice value: 8"); +} + +#[actix_rt::test] +async fn scope_post_async() { + let srv = actix_test::start(|| App::new().service(scope_module::post)); + + let request = srv.request(http::Method::POST, srv.url("/test/test")); + let mut response = request.send().await.unwrap(); + let body = response.body().await.unwrap(); + let body_str = String::from_utf8(body.to_vec()).unwrap(); + assert_eq!(body_str, "post works"); +} + +#[actix_rt::test] +async fn multiple_shared_path_async() { + let srv = actix_test::start(|| App::new().service(scope_module::multiple_shared_path)); + + let request = srv.request(http::Method::PUT, srv.url("/test/test")); + let response = request.send().await.unwrap(); + assert!(response.status().is_success()); + + let request = srv.request(http::Method::PATCH, srv.url("/test/test")); + let response = request.send().await.unwrap(); + assert!(response.status().is_success()); +} + +#[actix_rt::test] +async fn multiple_multi_path_async() { + let srv = actix_test::start(|| App::new().service(scope_module::multiple_separate_paths)); + + let request = srv.request(http::Method::HEAD, srv.url("/test/test1")); + let response = request.send().await.unwrap(); + assert!(response.status().is_success()); + + let request = srv.request(http::Method::CONNECT, srv.url("/test/test2")); + let response = request.send().await.unwrap(); + assert!(response.status().is_success()); + + let request = srv.request(http::Method::OPTIONS, srv.url("/test/test3")); + let response = request.send().await.unwrap(); + assert!(response.status().is_success()); + + let request = srv.request(http::Method::TRACE, srv.url("/test/test4")); + let response = request.send().await.unwrap(); + assert!(response.status().is_success()); +} + +#[actix_rt::test] +async fn scope_delete_async() { + let srv = actix_test::start(|| App::new().service(scope_module::delete)); + + let request = srv.request(http::Method::DELETE, srv.url("/test/test")); + let mut response = request.send().await.unwrap(); + let body = response.body().await.unwrap(); + let body_str = String::from_utf8(body.to_vec()).unwrap(); + assert_eq!(body_str, "delete works"); +} + +#[actix_rt::test] +async fn scope_get_with_guard_async() { + let srv = actix_test::start(|| App::new().service(scope_module::guard)); + + let request = srv + .request(http::Method::GET, srv.url("/test/test/guard")) + .insert_header(("Accept", "image/*")); + let response = request.send().await.unwrap(); + assert!(response.status().is_success()); +} + +#[actix_rt::test] +async fn scope_v1_v2_async() { + let srv = actix_test::start(|| { + App::new() + .service(mod_scope_v1::test) + .service(mod_scope_v2::test) + }); + + let request = srv.request(http::Method::GET, srv.url("/v1/test")); + let mut response = request.send().await.unwrap(); + let body = response.body().await.unwrap(); + let body_str = String::from_utf8(body.to_vec()).unwrap(); + assert_eq!(body_str, "version1 works"); + + let request = srv.request(http::Method::GET, srv.url("/v2/test")); + let mut response = request.send().await.unwrap(); + let body = response.body().await.unwrap(); + let body_str = String::from_utf8(body.to_vec()).unwrap(); + assert_eq!(body_str, "version2 works"); +}