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 actix_router::ResourceDef;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||||
use quote::{quote, ToTokens, TokenStreamExt};
|
use quote::{quote, ToTokens, TokenStreamExt};
|
||||||
use syn::{punctuated::Punctuated, Ident, LitStr, Path, Token, ItemFn};
|
use syn::Item::Fn;
|
||||||
use syn::Item::Fn; // todo: cleanup
|
use syn::{punctuated::Punctuated, Ident, ItemFn, LitStr, Path, Token}; // todo: cleanup
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RouteArgs {
|
pub struct RouteArgs {
|
||||||
|
@ -556,72 +556,83 @@ fn input_and_compile_error(mut item: TokenStream, err: syn::Error) -> TokenStrea
|
||||||
item
|
item
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: regular new scoped path test...
|
||||||
// todo: test with enums in module...
|
// todo: test with enums in module...
|
||||||
|
// todo: test with different namespaces...
|
||||||
// todo: test with multiple get/post methods...
|
// todo: test with multiple get/post methods...
|
||||||
// todo: test with doc strings in attributes...
|
// 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: 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: 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: 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 {
|
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() {
|
if args.is_empty() {
|
||||||
return input_and_compile_error(
|
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
|
// Expect macro to be for a module
|
||||||
let mut ast: syn::ItemMod = syn::parse(input.clone()).expect("expecting module for macro scope attribute");
|
match syn::parse::<syn::ItemMod>(input) {
|
||||||
match scope_path {
|
Ok(mut ast) => {
|
||||||
Ok(scope_path) => { // scope_path : LitStr
|
// Modify the attributes of functions within the module with method with scope, if any
|
||||||
if let Some((_, ref mut all_items)) = ast.content {
|
if let Some((_, ref mut items)) = ast.content {
|
||||||
for item in all_items.iter_mut() {
|
items.iter_mut().for_each(|item| {
|
||||||
if let Fn(fun) = item {
|
if let Fn(fun) = item {
|
||||||
let mut new_attrs = Vec::new();
|
fun.attrs = fun
|
||||||
for attr in fun.attrs.iter() {
|
.attrs
|
||||||
if let Ok(_method) = MethodType::from_path(attr.path()) {
|
.iter()
|
||||||
if let Ok(route_args) = attr.parse_args::<RouteArgs>() {
|
.map(|attr| {
|
||||||
if let syn::Meta::List(meta_list) = attr.clone().meta {
|
modify_attribute_with_scope(
|
||||||
let modified_path = format!("{}{}", scope_path.value(), route_args.path.value());
|
attr,
|
||||||
let modified_tokens = quote! {
|
&scope_path.clone().unwrap().value(),
|
||||||
#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,
|
|
||||||
})
|
})
|
||||||
};
|
.collect();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(err) => {
|
|
||||||
return input_and_compile_error(args, err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TokenStream::from(quote! { #ast })
|
TokenStream::from(quote! { #ast })
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
input_and_compile_error(args, syn::Error::new(Span::call_site(), err.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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")]
|
#[scope("/test")]
|
||||||
mod scope_module {
|
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::{
|
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,
|
HttpResponse, Responder,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[actix_web::get("/test")]
|
#[get("/test")]
|
||||||
pub async fn test() -> impl Responder {
|
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 {
|
pub async fn test_twice(value: web::Path<String>) -> impl actix_web::Responder {
|
||||||
let int_value: i32 = value.parse().unwrap_or(0);
|
let int_value: i32 = value.parse().unwrap_or(0);
|
||||||
let doubled = int_value * 2;
|
let doubled = int_value * 2;
|
||||||
HttpResponse::Ok().body(format!("Twice value: {}", doubled))
|
HttpResponse::Ok().body(format!("Twice value: {}", doubled))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_web::post("/test")]
|
#[post("/test")]
|
||||||
pub async fn test_post() -> impl Responder {
|
pub async fn test_post() -> impl Responder {
|
||||||
HttpResponse::Ok().body(format!("post works"))
|
HttpResponse::Ok().body(format!("post works"))
|
||||||
}
|
}
|
||||||
|
@ -464,31 +451,31 @@ const mod_inner: () = {
|
||||||
pub fn mod_common(message: String) -> impl actix_web::Responder {
|
pub fn mod_common(message: String) -> impl actix_web::Responder {
|
||||||
HttpResponse::Ok().body(message)
|
HttpResponse::Ok().body(message)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
#[scope("/v1")]
|
#[scope("/v1")]
|
||||||
const mod_inner_v1: () = {
|
mod mod_inner_v1 {
|
||||||
use actix_web::Responder;
|
use actix_web::{get, Responder};
|
||||||
|
|
||||||
#[actix_web::get("/test")]
|
#[get("/test")]
|
||||||
pub async fn test() -> impl Responder {
|
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")]
|
#[scope("/v2")]
|
||||||
const mod_inner_v2: () = {
|
mod mod_inner_v2 {
|
||||||
use actix_web::Responder;
|
use actix_web::{get, Responder};
|
||||||
|
|
||||||
#[actix_web::get("/test")]
|
#[get("/test")]
|
||||||
pub async fn test() -> impl Responder {
|
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]
|
#[actix_rt::test]
|
||||||
async fn test_scope_get_async() {
|
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 request = srv.request(http::Method::GET, srv.url("/test/test"));
|
||||||
let response = request.send().await.unwrap();
|
let response = request.send().await.unwrap();
|
||||||
|
@ -497,7 +484,7 @@ async fn test_scope_get_async() {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_scope_get_param_async() {
|
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 request = srv.request(http::Method::GET, srv.url("/test/twicetest/4"));
|
||||||
let mut response = request.send().await.unwrap();
|
let mut response = request.send().await.unwrap();
|
||||||
|
@ -508,7 +495,7 @@ async fn test_scope_get_param_async() {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_scope_post_async() {
|
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 request = srv.request(http::Method::POST, srv.url("/test/test"));
|
||||||
let mut response = request.send().await.unwrap();
|
let mut response = request.send().await.unwrap();
|
||||||
|
@ -519,7 +506,7 @@ async fn test_scope_post_async() {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_scope_put_async() {
|
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 request = srv.request(http::Method::PUT, srv.url("/test/test"));
|
||||||
let mut response = request.send().await.unwrap();
|
let mut response = request.send().await.unwrap();
|
||||||
|
@ -530,7 +517,7 @@ async fn test_scope_put_async() {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_scope_head_async() {
|
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 request = srv.request(http::Method::HEAD, srv.url("/test/test"));
|
||||||
let response = request.send().await.unwrap();
|
let response = request.send().await.unwrap();
|
||||||
|
@ -539,7 +526,7 @@ async fn test_scope_head_async() {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_scope_connect_async() {
|
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 request = srv.request(http::Method::CONNECT, srv.url("/test/test"));
|
||||||
let mut response = request.send().await.unwrap();
|
let mut response = request.send().await.unwrap();
|
||||||
|
@ -550,7 +537,7 @@ async fn test_scope_connect_async() {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_scope_options_async() {
|
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 request = srv.request(http::Method::OPTIONS, srv.url("/test/test"));
|
||||||
let mut response = request.send().await.unwrap();
|
let mut response = request.send().await.unwrap();
|
||||||
|
@ -561,7 +548,7 @@ async fn test_scope_options_async() {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_scope_trace_async() {
|
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 request = srv.request(http::Method::TRACE, srv.url("/test/test"));
|
||||||
let mut response = request.send().await.unwrap();
|
let mut response = request.send().await.unwrap();
|
||||||
|
@ -572,7 +559,7 @@ async fn test_scope_trace_async() {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_scope_patch_async() {
|
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 request = srv.request(http::Method::PATCH, srv.url("/test/test"));
|
||||||
let mut response = request.send().await.unwrap();
|
let mut response = request.send().await.unwrap();
|
||||||
|
@ -583,7 +570,7 @@ async fn test_scope_patch_async() {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_scope_delete_async() {
|
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 request = srv.request(http::Method::DELETE, srv.url("/test/test"));
|
||||||
let mut response = request.send().await.unwrap();
|
let mut response = request.send().await.unwrap();
|
||||||
|
@ -594,7 +581,7 @@ async fn test_scope_delete_async() {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_scope_v1_v2_async() {
|
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 request = srv.request(http::Method::GET, srv.url("/v1/test"));
|
||||||
let mut response = request.send().await.unwrap();
|
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();
|
let body_str = String::from_utf8(body.to_vec()).unwrap();
|
||||||
assert_eq!(body_str, "version2 works");
|
assert_eq!(body_str, "version2 works");
|
||||||
}
|
}
|
||||||
*/
|
|
Loading…
Reference in New Issue