mirror of https://github.com/fafhrd91/actix-web
add tests again. refactor nested code.
This commit is contained in:
parent
455c064728
commit
ab73c72596
|
@ -1,11 +1,11 @@
|
|||
use std::{collections::HashSet};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use actix_router::ResourceDef;
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
use quote::{quote, ToTokens, TokenStreamExt};
|
||||
use syn::{punctuated::Punctuated, Ident, LitStr, Path, Token, ItemFn};
|
||||
use syn::Item::Fn; // todo: cleanup
|
||||
use syn::Item::Fn;
|
||||
use syn::{punctuated::Punctuated, Ident, ItemFn, LitStr, Path, Token}; // todo: cleanup
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RouteArgs {
|
||||
|
@ -556,72 +556,83 @@ fn input_and_compile_error(mut item: TokenStream, err: syn::Error) -> TokenStrea
|
|||
item
|
||||
}
|
||||
|
||||
// todo: regular new scoped path test...
|
||||
// todo: test with enums in module...
|
||||
// todo: test with different namespaces...
|
||||
// todo: test with multiple get/post methods...
|
||||
// todo: test with doc strings in attributes...
|
||||
// todo: clean up the nested tree of death, tell it about the input_and_compile_error convenience function...
|
||||
// todo: add in the group functions for convenient handling of group...
|
||||
// todo: see if can cleanup the Attribute with a clone plus one field change...
|
||||
// todo: #[actix_web::get("/test")] the namespace is messing matching up
|
||||
pub fn with_scope(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
// get the path of the scope argument
|
||||
// Attempt to parse the scope path, returning on error
|
||||
if args.is_empty() {
|
||||
return input_and_compile_error(
|
||||
args, syn::Error::new(proc_macro2::Span::call_site(), "invalid server definition, expected: #[scope(\"some path\")]"));
|
||||
args.clone(),
|
||||
syn::Error::new(
|
||||
Span::call_site(),
|
||||
"Missing arguments for scope macro, expected: #[scope(\"some path\")]",
|
||||
),
|
||||
);
|
||||
}
|
||||
let scope_path = syn::parse::<LitStr>(args.clone().into());
|
||||
if let Err(_err) = scope_path {
|
||||
return input_and_compile_error(
|
||||
args.clone(),
|
||||
syn::Error::new(
|
||||
Span::call_site(),
|
||||
"Missing arguments for scope macro, expected: #[scope(\"some path\")]",
|
||||
),
|
||||
);
|
||||
}
|
||||
let scope_path = syn::parse::<syn::LitStr>(args.clone()).map_err(|_| syn::Error::new(
|
||||
proc_macro2::Span::call_site(),
|
||||
"Scope macro needs a path to be specified.",
|
||||
));
|
||||
|
||||
// modify the attribute of functions with method attributes in the module
|
||||
let mut ast: syn::ItemMod = syn::parse(input.clone()).expect("expecting module for macro scope attribute");
|
||||
match scope_path {
|
||||
Ok(scope_path) => { // scope_path : LitStr
|
||||
if let Some((_, ref mut all_items)) = ast.content {
|
||||
for item in all_items.iter_mut() {
|
||||
// Expect macro to be for a module
|
||||
match syn::parse::<syn::ItemMod>(input) {
|
||||
Ok(mut ast) => {
|
||||
// Modify the attributes of functions within the module with method with scope, if any
|
||||
if let Some((_, ref mut items)) = ast.content {
|
||||
items.iter_mut().for_each(|item| {
|
||||
if let Fn(fun) = item {
|
||||
let mut new_attrs = Vec::new();
|
||||
for attr in fun.attrs.iter() {
|
||||
if let Ok(_method) = MethodType::from_path(attr.path()) {
|
||||
if let Ok(route_args) = attr.parse_args::<RouteArgs>() {
|
||||
if let syn::Meta::List(meta_list) = attr.clone().meta {
|
||||
let modified_path = format!("{}{}", scope_path.value(), route_args.path.value());
|
||||
let modified_tokens = quote! {
|
||||
#modified_path
|
||||
};
|
||||
let new_attr = syn::Attribute {
|
||||
pound_token: attr.pound_token,
|
||||
style: attr.style,
|
||||
bracket_token: attr.bracket_token,
|
||||
meta: syn::Meta::List(syn::MetaList {
|
||||
path: meta_list.path,
|
||||
delimiter: meta_list.delimiter,
|
||||
tokens: modified_tokens,
|
||||
})
|
||||
};
|
||||
new_attrs.push(new_attr);
|
||||
}
|
||||
else {
|
||||
new_attrs.push(attr.clone());
|
||||
}
|
||||
}
|
||||
else {
|
||||
new_attrs.push(attr.clone());
|
||||
}
|
||||
}
|
||||
else {
|
||||
new_attrs.push(attr.clone());
|
||||
}
|
||||
}
|
||||
fun.attrs = new_attrs;
|
||||
fun.attrs = fun
|
||||
.attrs
|
||||
.iter()
|
||||
.map(|attr| {
|
||||
modify_attribute_with_scope(
|
||||
attr,
|
||||
&scope_path.clone().unwrap().value(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
return input_and_compile_error(args, err);
|
||||
TokenStream::from(quote! { #ast })
|
||||
}
|
||||
};
|
||||
Err(err) => {
|
||||
input_and_compile_error(args, syn::Error::new(Span::call_site(), err.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TokenStream::from(quote! { #ast })
|
||||
}
|
||||
// Check if the attribute is a method type and has a route path, then modify it
|
||||
fn modify_attribute_with_scope(attr: &syn::Attribute, scope_path: &str) -> syn::Attribute {
|
||||
match (
|
||||
MethodType::from_path(attr.path()),
|
||||
attr.parse_args::<RouteArgs>(),
|
||||
attr.clone().meta,
|
||||
) {
|
||||
(Ok(_method), Ok(route_args), syn::Meta::List(meta_list)) => {
|
||||
let modified_path = format!("{}{}", scope_path, route_args.path.value());
|
||||
let modified_tokens = quote! { #modified_path };
|
||||
syn::Attribute {
|
||||
meta: syn::Meta::List(syn::MetaList {
|
||||
tokens: modified_tokens,
|
||||
..meta_list.clone()
|
||||
}),
|
||||
..attr.clone()
|
||||
}
|
||||
}
|
||||
_ => attr.clone(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -387,37 +387,24 @@ async fn test_wrap() {
|
|||
*/
|
||||
#[scope("/test")]
|
||||
mod scope_module {
|
||||
use actix_web::{HttpResponse, Responder};
|
||||
use actix_web_codegen::{
|
||||
connect, delete, get, head, options, patch, post, put, route, routes, scope, trace,
|
||||
};
|
||||
|
||||
#[get("/get_test")]
|
||||
async fn get_test() -> impl Responder {
|
||||
HttpResponse::Ok()
|
||||
}
|
||||
}
|
||||
/*
|
||||
#[scope("/test")]
|
||||
const mod_inner: () = {
|
||||
use actix_web::{
|
||||
connect, delete, head, options, patch, put, trace, web, web::Json, HttpRequest,
|
||||
get, post, connect, delete, head, options, patch, put, trace, web, HttpRequest,
|
||||
HttpResponse, Responder,
|
||||
};
|
||||
|
||||
#[actix_web::get("/test")]
|
||||
#[get("/test")]
|
||||
pub async fn test() -> impl Responder {
|
||||
mod_test2()
|
||||
HttpResponse::Ok().finish()
|
||||
}
|
||||
|
||||
#[actix_web::get("/twicetest/{value}")]
|
||||
#[get("/twicetest/{value}")]
|
||||
pub async fn test_twice(value: web::Path<String>) -> 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))
|
||||
}
|
||||
|
||||
#[actix_web::post("/test")]
|
||||
#[post("/test")]
|
||||
pub async fn test_post() -> impl Responder {
|
||||
HttpResponse::Ok().body(format!("post works"))
|
||||
}
|
||||
|
@ -464,31 +451,31 @@ const mod_inner: () = {
|
|||
pub fn mod_common(message: String) -> impl actix_web::Responder {
|
||||
HttpResponse::Ok().body(message)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[scope("/v1")]
|
||||
const mod_inner_v1: () = {
|
||||
use actix_web::Responder;
|
||||
mod mod_inner_v1 {
|
||||
use actix_web::{get, Responder};
|
||||
|
||||
#[actix_web::get("/test")]
|
||||
#[get("/test")]
|
||||
pub async fn test() -> impl Responder {
|
||||
super::mod_inner_scope::mod_common("version1 works".to_string())
|
||||
super::scope_module::mod_common("version1 works".to_string())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[scope("/v2")]
|
||||
const mod_inner_v2: () = {
|
||||
use actix_web::Responder;
|
||||
mod mod_inner_v2 {
|
||||
use actix_web::{get, Responder};
|
||||
|
||||
#[actix_web::get("/test")]
|
||||
#[get("/test")]
|
||||
pub async fn test() -> impl Responder {
|
||||
super::mod_inner_scope::mod_common("version2 works".to_string())
|
||||
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(mod_inner));
|
||||
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();
|
||||
|
@ -497,7 +484,7 @@ async fn test_scope_get_async() {
|
|||
|
||||
#[actix_rt::test]
|
||||
async fn test_scope_get_param_async() {
|
||||
let srv = actix_test::start(|| App::new().service(mod_inner));
|
||||
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();
|
||||
|
@ -508,7 +495,7 @@ async fn test_scope_get_param_async() {
|
|||
|
||||
#[actix_rt::test]
|
||||
async fn test_scope_post_async() {
|
||||
let srv = actix_test::start(|| App::new().service(mod_inner));
|
||||
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();
|
||||
|
@ -519,7 +506,7 @@ async fn test_scope_post_async() {
|
|||
|
||||
#[actix_rt::test]
|
||||
async fn test_scope_put_async() {
|
||||
let srv = actix_test::start(|| App::new().service(mod_inner));
|
||||
let srv = actix_test::start(|| App::new().service(scope_module::test_put));
|
||||
|
||||
let request = srv.request(http::Method::PUT, srv.url("/test/test"));
|
||||
let mut response = request.send().await.unwrap();
|
||||
|
@ -530,7 +517,7 @@ async fn test_scope_put_async() {
|
|||
|
||||
#[actix_rt::test]
|
||||
async fn test_scope_head_async() {
|
||||
let srv = actix_test::start(|| App::new().service(mod_inner));
|
||||
let srv = actix_test::start(|| App::new().service(scope_module::test_head));
|
||||
|
||||
let request = srv.request(http::Method::HEAD, srv.url("/test/test"));
|
||||
let response = request.send().await.unwrap();
|
||||
|
@ -539,7 +526,7 @@ async fn test_scope_head_async() {
|
|||
|
||||
#[actix_rt::test]
|
||||
async fn test_scope_connect_async() {
|
||||
let srv = actix_test::start(|| App::new().service(mod_inner));
|
||||
let srv = actix_test::start(|| App::new().service(scope_module::test_connect));
|
||||
|
||||
let request = srv.request(http::Method::CONNECT, srv.url("/test/test"));
|
||||
let mut response = request.send().await.unwrap();
|
||||
|
@ -550,7 +537,7 @@ async fn test_scope_connect_async() {
|
|||
|
||||
#[actix_rt::test]
|
||||
async fn test_scope_options_async() {
|
||||
let srv = actix_test::start(|| App::new().service(mod_inner));
|
||||
let srv = actix_test::start(|| App::new().service(scope_module::test_options));
|
||||
|
||||
let request = srv.request(http::Method::OPTIONS, srv.url("/test/test"));
|
||||
let mut response = request.send().await.unwrap();
|
||||
|
@ -561,7 +548,7 @@ async fn test_scope_options_async() {
|
|||
|
||||
#[actix_rt::test]
|
||||
async fn test_scope_trace_async() {
|
||||
let srv = actix_test::start(|| App::new().service(mod_inner));
|
||||
let srv = actix_test::start(|| App::new().service(scope_module::test_trace));
|
||||
|
||||
let request = srv.request(http::Method::TRACE, srv.url("/test/test"));
|
||||
let mut response = request.send().await.unwrap();
|
||||
|
@ -572,7 +559,7 @@ async fn test_scope_trace_async() {
|
|||
|
||||
#[actix_rt::test]
|
||||
async fn test_scope_patch_async() {
|
||||
let srv = actix_test::start(|| App::new().service(mod_inner));
|
||||
let srv = actix_test::start(|| App::new().service(scope_module::test_patch));
|
||||
|
||||
let request = srv.request(http::Method::PATCH, srv.url("/test/test"));
|
||||
let mut response = request.send().await.unwrap();
|
||||
|
@ -583,7 +570,7 @@ async fn test_scope_patch_async() {
|
|||
|
||||
#[actix_rt::test]
|
||||
async fn test_scope_delete_async() {
|
||||
let srv = actix_test::start(|| App::new().service(mod_inner));
|
||||
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();
|
||||
|
@ -594,7 +581,7 @@ async fn test_scope_delete_async() {
|
|||
|
||||
#[actix_rt::test]
|
||||
async fn test_scope_v1_v2_async() {
|
||||
let srv = actix_test::start(|| App::new().service(mod_inner_v1).service(mod_inner_v2));
|
||||
let srv = actix_test::start(|| App::new().service(mod_inner_v1::test).service(mod_inner_v2::test));
|
||||
|
||||
let request = srv.request(http::Method::GET, srv.url("/v1/test"));
|
||||
let mut response = request.send().await.unwrap();
|
||||
|
@ -608,4 +595,3 @@ async fn test_scope_v1_v2_async() {
|
|||
let body_str = String::from_utf8(body.to_vec()).unwrap();
|
||||
assert_eq!(body_str, "version2 works");
|
||||
}
|
||||
*/
|
Loading…
Reference in New Issue