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