1use super::{HttpMethod, RouteInfo, RouteRegistry};
4use crate::controller::{factory::IocControllable, ElifController};
5use crate::errors::HttpResult;
6use crate::handlers::elif_handler;
7use crate::middleware::v2::{Middleware, MiddlewarePipelineV2};
8use crate::request::ElifRequest;
9use crate::response::{ElifResponse, IntoElifResponse};
10use axum::{
11 routing::{delete, get, patch, post, put},
12 Router as AxumRouter,
13};
14use elif_core::container::IocContainer;
15use std::collections::HashMap;
16use std::future::Future;
17use std::pin::Pin;
18use std::sync::{Arc, Mutex};
19
20#[derive(Debug)]
22pub struct Router<S = ()>
23where
24 S: Clone + Send + Sync + 'static,
25{
26 axum_router: AxumRouter<S>,
27 registry: Arc<Mutex<RouteRegistry>>,
28 route_counter: Arc<Mutex<usize>>,
29 middleware_stack: MiddlewarePipelineV2,
30 middleware_groups: HashMap<String, MiddlewarePipelineV2>,
31 route_middleware: HashMap<String, Vec<String>>, controller_registry: Arc<Mutex<ControllerRegistry>>,
33 ioc_container: Option<Arc<IocContainer>>,
34}
35
36impl<S> Router<S>
37where
38 S: Clone + Send + Sync + 'static,
39{
40 pub fn new() -> Self {
42 Self {
43 axum_router: AxumRouter::new(),
44 registry: Arc::new(Mutex::new(RouteRegistry::new())),
45 route_counter: Arc::new(Mutex::new(0)),
46 middleware_stack: MiddlewarePipelineV2::new(),
47 middleware_groups: HashMap::new(),
48 route_middleware: HashMap::new(),
49 controller_registry: Arc::new(Mutex::new(ControllerRegistry::new())),
50 ioc_container: None,
51 }
52 }
53
54 pub fn with_state(state: S) -> Self {
56 Self {
57 axum_router: AxumRouter::new().with_state(state),
58 registry: Arc::new(Mutex::new(RouteRegistry::new())),
59 route_counter: Arc::new(Mutex::new(0)),
60 middleware_stack: MiddlewarePipelineV2::new(),
61 middleware_groups: HashMap::new(),
62 route_middleware: HashMap::new(),
63 controller_registry: Arc::new(Mutex::new(ControllerRegistry::new())),
64 ioc_container: None,
65 }
66 }
67
68 fn next_route_id(&self) -> String {
70 let mut counter = self.route_counter.lock().unwrap();
71 *counter += 1;
72 format!("route_{}", counter)
73 }
74
75 fn register_route(&self, method: HttpMethod, path: &str, name: Option<String>) -> String {
77 let route_id = self.next_route_id();
78 let params = self.extract_param_names(path);
79
80 let route_info = RouteInfo {
81 name: name.clone(),
82 path: path.to_string(),
83 method,
84 params,
85 group: None, };
87
88 self.registry
89 .lock()
90 .unwrap()
91 .register(route_id.clone(), route_info);
92 route_id
93 }
94
95 fn extract_param_names(&self, path: &str) -> Vec<String> {
97 path.split('/')
98 .filter_map(|segment| {
99 if segment.starts_with('{') && segment.ends_with('}') {
100 Some(segment[1..segment.len() - 1].to_string())
101 } else {
102 None
103 }
104 })
105 .collect()
106 }
107
108 pub fn use_middleware<M: Middleware + 'static>(mut self, middleware: M) -> Self {
110 self.middleware_stack = self.middleware_stack.add(middleware);
111 self
112 }
113
114 pub fn extend_middleware(mut self, external_middleware: MiddlewarePipelineV2) -> Self {
117 self.middleware_stack = external_middleware.extend(self.middleware_stack);
118 self
119 }
120
121 pub fn middleware_group(mut self, name: &str, middleware: Vec<Arc<dyn Middleware>>) -> Self {
123 let pipeline = MiddlewarePipelineV2::from(middleware);
124 self.middleware_groups.insert(name.to_string(), pipeline);
125 self
126 }
127
128 pub fn route(self, path: &str) -> RouteBuilder<S> {
130 RouteBuilder::new(self, path.to_string())
131 }
132
133 fn add_route<F, Fut, R, M>(
135 mut self,
136 method: HttpMethod,
137 path: &str,
138 handler: F,
139 method_router_fn: M,
140 ) -> Self
141 where
142 F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
143 Fut: Future<Output = HttpResult<R>> + Send + 'static,
144 R: IntoElifResponse + Send + 'static,
145 M: FnOnce(
146 crate::handlers::handler::ElifHandlerWrapper<F, Fut, R>,
147 ) -> axum::routing::MethodRouter<S>,
148 {
149 self.register_route(method, path, None);
150 let method_router = method_router_fn(elif_handler(handler));
151 self.axum_router = self.axum_router.route(path, method_router);
152 self
153 }
154
155 pub fn get<F, Fut, R>(self, path: &str, handler: F) -> Self
157 where
158 F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
159 Fut: Future<Output = HttpResult<R>> + Send + 'static,
160 R: IntoElifResponse + Send + 'static,
161 {
162 self.add_route(HttpMethod::GET, path, handler, get)
163 }
164
165 pub fn post<F, Fut, R>(self, path: &str, handler: F) -> Self
167 where
168 F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
169 Fut: Future<Output = HttpResult<R>> + Send + 'static,
170 R: IntoElifResponse + Send + 'static,
171 {
172 self.add_route(HttpMethod::POST, path, handler, post)
173 }
174
175 pub fn put<F, Fut, R>(self, path: &str, handler: F) -> Self
177 where
178 F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
179 Fut: Future<Output = HttpResult<R>> + Send + 'static,
180 R: IntoElifResponse + Send + 'static,
181 {
182 self.add_route(HttpMethod::PUT, path, handler, put)
183 }
184
185 pub fn delete<F, Fut, R>(self, path: &str, handler: F) -> Self
187 where
188 F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
189 Fut: Future<Output = HttpResult<R>> + Send + 'static,
190 R: IntoElifResponse + Send + 'static,
191 {
192 self.add_route(HttpMethod::DELETE, path, handler, delete)
193 }
194
195 pub fn patch<F, Fut, R>(self, path: &str, handler: F) -> Self
197 where
198 F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
199 Fut: Future<Output = HttpResult<R>> + Send + 'static,
200 R: IntoElifResponse + Send + 'static,
201 {
202 self.add_route(HttpMethod::PATCH, path, handler, patch)
203 }
204
205 pub fn controller<C>(mut self, controller: C) -> Self
207 where
208 C: ElifController + 'static,
209 {
210 let base_path = controller.base_path().to_string();
211 let controller_name = controller.name().to_string();
212 let controller_arc = Arc::new(controller);
213
214 for route in controller_arc.routes() {
216 let full_path = self.combine_paths(&base_path, &route.path);
217 let handler =
218 controller_handler(Arc::clone(&controller_arc), route.handler_name.clone());
219
220 self = match route.method {
221 HttpMethod::GET => self.get(&full_path, handler),
222 HttpMethod::POST => self.post(&full_path, handler),
223 HttpMethod::PUT => self.put(&full_path, handler),
224 HttpMethod::DELETE => self.delete(&full_path, handler),
225 HttpMethod::PATCH => self.patch(&full_path, handler),
226 _ => {
227 continue;
230 }
231 };
232
233 }
236
237 if let Ok(mut registry) = self.controller_registry.lock() {
239 registry.register(controller_name, controller_arc as Arc<dyn ElifController>);
240 }
241
242 self
243 }
244
245 pub fn with_ioc_container(mut self, container: Arc<IocContainer>) -> Self {
247 self.ioc_container = Some(container);
248 self
249 }
250
251 pub fn controller_from_container<C>(self) -> Self
254 where
255 C: ElifController + IocControllable + 'static,
256 {
257 let container = self.ioc_container.as_ref()
258 .expect("IoC container must be set before registering IoC controllers. Use .with_ioc_container() first");
259
260 let controller_arc = match C::from_ioc_container(container, None) {
262 Ok(controller) => Arc::new(controller),
263 Err(err) => {
264 eprintln!(
265 "Warning: Failed to create singleton controller instance: {}",
266 err
267 );
268 return self;
269 }
270 };
271
272 let base_path = controller_arc.base_path().to_string();
273 let controller_name = controller_arc.name().to_string();
274
275 let mut router = self;
277 for route in controller_arc.routes() {
278 let full_path = router.combine_paths(&base_path, &route.path);
279 let handler_controller_arc = Arc::clone(&controller_arc);
280 let method_name = route.handler_name.clone();
281
282 let handler = move |request: ElifRequest| {
283 let controller = Arc::clone(&handler_controller_arc);
284 let method_name = method_name.clone();
285 Box::pin(async move { controller.handle_request(method_name, request).await })
286 };
287
288 router = match route.method {
289 HttpMethod::GET => router.get(&full_path, handler),
290 HttpMethod::POST => router.post(&full_path, handler),
291 HttpMethod::PUT => router.put(&full_path, handler),
292 HttpMethod::DELETE => router.delete(&full_path, handler),
293 HttpMethod::PATCH => router.patch(&full_path, handler),
294 _ => {
295 continue;
297 }
298 };
299
300 }
302
303 if let Ok(mut registry) = router.controller_registry.lock() {
305 registry.register(controller_name, controller_arc as Arc<dyn ElifController>);
306 }
307
308 router
309 }
310
311 pub fn scoped_controller_from_container<C>(self) -> Self
314 where
315 C: ElifController + IocControllable + 'static,
316 {
317 let container = self.ioc_container.as_ref()
318 .expect("IoC container must be set before registering IoC controllers. Use .with_ioc_container() first");
319 let container_arc = Arc::clone(container);
320
321 let temp_controller = match C::from_ioc_container(container, None) {
323 Ok(controller) => controller,
324 Err(err) => {
325 eprintln!(
326 "Warning: Failed to create controller for route registration: {}",
327 err
328 );
329 return self;
330 }
331 };
332
333 let base_path = temp_controller.base_path().to_string();
334 let controller_name = temp_controller.name().to_string();
335
336 let mut router = self;
338 for route in temp_controller.routes() {
339 let full_path = router.combine_paths(&base_path, &route.path);
340 let handler = scoped_ioc_controller_handler::<C>(
341 Arc::clone(&container_arc),
342 route.handler_name.clone(),
343 );
344
345 router = match route.method {
346 HttpMethod::GET => router.get(&full_path, handler),
347 HttpMethod::POST => router.post(&full_path, handler),
348 HttpMethod::PUT => router.put(&full_path, handler),
349 HttpMethod::DELETE => router.delete(&full_path, handler),
350 HttpMethod::PATCH => router.patch(&full_path, handler),
351 _ => {
352 continue;
353 }
354 };
355 }
356
357 if let Ok(mut registry) = router.controller_registry.lock() {
359 let controller_arc = Arc::new(temp_controller);
360 registry.register(controller_name, controller_arc as Arc<dyn ElifController>);
361 }
362
363 router
364 }
365
366 fn combine_paths(&self, base: &str, route: &str) -> String {
368 let base = base.trim_end_matches('/');
369 let route = route.trim_start_matches('/');
370
371 let path = if route.is_empty() {
372 base.to_string()
373 } else if base.is_empty() {
374 format!("/{}", route)
375 } else {
376 format!("{}/{}", base, route)
377 };
378
379 if path.is_empty() {
381 "/".to_string()
382 } else {
383 path
384 }
385 }
386
387 pub fn merge(mut self, other: Router<S>) -> Self {
389 if let (Ok(mut self_registry), Ok(other_registry)) =
391 (self.registry.lock(), other.registry.lock())
392 {
393 for route_info in other_registry.all_routes().values() {
394 let new_id = self.next_route_id();
396 self_registry.register(new_id, route_info.clone());
397 }
398 }
399
400 self.middleware_groups.extend(other.middleware_groups);
402 self.route_middleware.extend(other.route_middleware);
403
404 if let Ok(other_controller_registry) = other.controller_registry.lock() {
406 let controllers_to_merge: Vec<_> = other_controller_registry
407 .all_controllers()
408 .map(|(name, controller)| (name.clone(), Arc::clone(controller)))
409 .collect();
410
411 drop(other_controller_registry);
413
414 if let Ok(mut self_controller_registry) = self.controller_registry.lock() {
415 for (name, controller) in controllers_to_merge {
416 self_controller_registry.register(name, controller);
417 }
418 }
419 }
420
421 if self.ioc_container.is_none() && other.ioc_container.is_some() {
423 self.ioc_container = other.ioc_container;
424 }
425
426 self.middleware_stack = self.middleware_stack.extend(other.middleware_stack);
428
429 self.axum_router = self.axum_router.merge(other.axum_router);
431 self
432 }
433
434 pub(crate) fn merge_axum(mut self, other: AxumRouter<S>) -> Self {
436 self.axum_router = self.axum_router.merge(other);
437 self
438 }
439
440 pub fn nest(mut self, path: &str, router: Router<S>) -> Self {
446 if let (Ok(mut self_registry), Ok(router_registry)) =
450 (self.registry.lock(), router.registry.lock())
451 {
452 for route_info in router_registry.all_routes().values() {
453 let new_id = self.next_route_id();
455 self_registry.register(new_id, route_info.clone());
456 }
457 }
458
459 self.middleware_groups.extend(router.middleware_groups);
461 self.route_middleware.extend(router.route_middleware);
462
463 let has_nested_middleware = !router.middleware_stack.is_empty();
466 let nested_middleware = router.middleware_stack.clone();
467 let nested_axum_router = router.axum_router;
468
469 let nested_axum_router = if has_nested_middleware {
470 use axum::extract::Request;
471 use axum::middleware::from_fn;
472 use axum::middleware::Next;
473
474 nested_axum_router.layer(from_fn(move |req: Request, next: Next| {
476 let pipeline = nested_middleware.clone();
477 async move {
478 let elif_req = crate::request::ElifRequest::from_axum_request(req).await;
480
481 let response = pipeline
483 .execute(elif_req, |req| {
484 Box::pin(async move {
485 let axum_req = req.into_axum_request();
487 let axum_response = next.run(axum_req).await;
488 crate::response::ElifResponse::from_axum_response(axum_response)
490 .await
491 })
492 })
493 .await;
494
495 response.into_axum_response()
497 }
498 }))
499 } else {
500 nested_axum_router
501 };
502
503 self.axum_router = self.axum_router.nest(path, nested_axum_router);
504 self
505 }
506
507 pub fn into_axum_router(self) -> AxumRouter<S> {
509 self.axum_router
510 }
511
512 pub fn registry(&self) -> Arc<Mutex<RouteRegistry>> {
514 Arc::clone(&self.registry)
515 }
516
517 pub fn url_for(&self, name: &str, params: &HashMap<String, String>) -> Option<String> {
519 let registry = self.registry.lock().unwrap();
520 if let Some(route) = registry.get_by_name(name) {
521 let mut url = route.path.clone();
522 for (key, value) in params {
523 url = url.replace(&format!("{{{}}}", key), value);
524 }
525 Some(url)
526 } else {
527 None
528 }
529 }
530
531 pub fn middleware_pipeline(&self) -> &MiddlewarePipelineV2 {
533 &self.middleware_stack
534 }
535
536 pub fn middleware_groups(&self) -> &HashMap<String, MiddlewarePipelineV2> {
538 &self.middleware_groups
539 }
540
541 pub fn route_middleware(&self) -> &HashMap<String, Vec<String>> {
543 &self.route_middleware
544 }
545
546 pub fn controller_registry(&self) -> Arc<Mutex<ControllerRegistry>> {
548 Arc::clone(&self.controller_registry)
549 }
550
551 pub fn ioc_container(&self) -> Option<&Arc<IocContainer>> {
553 self.ioc_container.as_ref()
554 }
555
556 pub(crate) fn add_axum_route(
558 mut self,
559 path: &str,
560 method_router: axum::routing::MethodRouter<S>,
561 ) -> Self {
562 self.axum_router = self.axum_router.route(path, method_router);
563 self
564 }
565}
566
567impl<S> Default for Router<S>
568where
569 S: Clone + Send + Sync + 'static,
570{
571 fn default() -> Self {
572 Self::new()
573 }
574}
575
576pub struct RouteBuilder<S = ()>
578where
579 S: Clone + Send + Sync + 'static,
580{
581 router: Router<S>,
582 path: String,
583 middleware_groups: Vec<String>,
584 name: Option<String>,
585}
586
587impl<S> RouteBuilder<S>
588where
589 S: Clone + Send + Sync + 'static,
590{
591 pub fn new(router: Router<S>, path: String) -> Self {
592 Self {
593 router,
594 path,
595 middleware_groups: Vec::new(),
596 name: None,
597 }
598 }
599
600 pub fn use_group(mut self, group_name: &str) -> Self {
602 self.middleware_groups.push(group_name.to_string());
603 self
604 }
605
606 pub fn name(mut self, name: &str) -> Self {
608 self.name = Some(name.to_string());
609 self
610 }
611
612 fn add_method_route<F, Fut, R, M>(
614 mut self,
615 method: HttpMethod,
616 handler: F,
617 method_router_fn: M,
618 ) -> Router<S>
619 where
620 F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
621 Fut: Future<Output = HttpResult<R>> + Send + 'static,
622 R: IntoElifResponse + Send + 'static,
623 M: FnOnce(
624 crate::handlers::handler::ElifHandlerWrapper<F, Fut, R>,
625 ) -> axum::routing::MethodRouter<S>,
626 {
627 let route_id = self
628 .router
629 .register_route(method, &self.path, self.name.clone());
630 self.router
631 .route_middleware
632 .insert(route_id, self.middleware_groups);
633 let method_router = method_router_fn(elif_handler(handler));
634 self.router.axum_router = self.router.axum_router.route(&self.path, method_router);
635 self.router
636 }
637
638 pub fn get<F, Fut, R>(self, handler: F) -> Router<S>
640 where
641 F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
642 Fut: Future<Output = HttpResult<R>> + Send + 'static,
643 R: IntoElifResponse + Send + 'static,
644 {
645 self.add_method_route(HttpMethod::GET, handler, get)
646 }
647
648 pub fn post<F, Fut, R>(self, handler: F) -> Router<S>
650 where
651 F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
652 Fut: Future<Output = HttpResult<R>> + Send + 'static,
653 R: IntoElifResponse + Send + 'static,
654 {
655 self.add_method_route(HttpMethod::POST, handler, post)
656 }
657
658 pub fn put<F, Fut, R>(self, handler: F) -> Router<S>
660 where
661 F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
662 Fut: Future<Output = HttpResult<R>> + Send + 'static,
663 R: IntoElifResponse + Send + 'static,
664 {
665 self.add_method_route(HttpMethod::PUT, handler, put)
666 }
667
668 pub fn delete<F, Fut, R>(self, handler: F) -> Router<S>
670 where
671 F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
672 Fut: Future<Output = HttpResult<R>> + Send + 'static,
673 R: IntoElifResponse + Send + 'static,
674 {
675 self.add_method_route(HttpMethod::DELETE, handler, delete)
676 }
677
678 pub fn patch<F, Fut, R>(self, handler: F) -> Router<S>
680 where
681 F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
682 Fut: Future<Output = HttpResult<R>> + Send + 'static,
683 R: IntoElifResponse + Send + 'static,
684 {
685 self.add_method_route(HttpMethod::PATCH, handler, patch)
686 }
687}
688
689#[cfg(test)]
690mod tests {
691 use super::*;
692 use crate::errors::HttpResult;
693 use crate::request::ElifRequest;
694 use crate::response::ElifResponse;
695
696 async fn elif_handler(_req: ElifRequest) -> HttpResult<ElifResponse> {
697 Ok(ElifResponse::ok().text("Hello, World!"))
698 }
699
700 #[test]
701 fn test_router_creation() {
702 let router = Router::<()>::new()
703 .get("/", elif_handler)
704 .post("/users", elif_handler)
705 .get("/users/{id}", elif_handler);
706
707 let registry = router.registry();
708 let reg = registry.lock().unwrap();
709 assert_eq!(reg.all_routes().len(), 3);
710 }
711
712 #[test]
713 fn test_param_extraction() {
714 let router = Router::<()>::new();
715 let params = router.extract_param_names("/users/{id}/posts/{slug}");
716 assert_eq!(params, vec!["id", "slug"]);
717 }
718
719 #[test]
720 fn test_url_generation() {
721 let router = Router::<()>::new().get("/users/{id}/posts/{slug}", elif_handler);
722
723 {
725 let mut registry = router.registry.lock().unwrap();
726 let route_info = RouteInfo {
727 name: Some("user.posts.show".to_string()),
728 path: "/users/{id}/posts/{slug}".to_string(),
729 method: HttpMethod::GET,
730 params: vec!["id".to_string(), "slug".to_string()],
731 group: None,
732 };
733 registry.register("test_route".to_string(), route_info);
734 }
735
736 let mut params = HashMap::new();
737 params.insert("id".to_string(), "123".to_string());
738 params.insert("slug".to_string(), "hello-world".to_string());
739
740 let url = router.url_for("user.posts.show", ¶ms);
741 assert_eq!(url, Some("/users/123/posts/hello-world".to_string()));
742 }
743
744 #[test]
745 fn test_middleware_integration() {
746 use crate::middleware::v2::LoggingMiddleware;
747
748 let router = Router::<()>::new()
749 .use_middleware(LoggingMiddleware)
750 .get("/", elif_handler);
751
752 assert_eq!(router.middleware_pipeline().len(), 1);
754 assert_eq!(
755 router.middleware_pipeline().names(),
756 vec!["LoggingMiddleware"]
757 );
758 }
759
760 #[test]
761 fn test_middleware_groups() {
762 use crate::middleware::v2::LoggingMiddleware;
763 use std::sync::Arc;
764
765 let router = Router::<()>::new()
766 .middleware_group("api", vec![Arc::new(LoggingMiddleware)])
767 .get("/", elif_handler);
768
769 assert!(router.middleware_groups().contains_key("api"));
771
772 let api_group = router.middleware_groups().get("api").unwrap();
774 assert_eq!(api_group.len(), 1);
775 assert_eq!(api_group.names(), vec!["LoggingMiddleware"]);
776 }
777
778 #[test]
779 fn test_router_merge_with_middleware() {
780 use crate::middleware::v2::{LoggingMiddleware, SimpleAuthMiddleware};
781 use std::sync::Arc;
782
783 let router1 = Router::<()>::new()
784 .use_middleware(LoggingMiddleware)
785 .middleware_group(
786 "auth",
787 vec![Arc::new(SimpleAuthMiddleware::new("secret".to_string()))],
788 );
789
790 let router2 = Router::<()>::new()
791 .use_middleware(SimpleAuthMiddleware::new("token".to_string()))
792 .middleware_group("api", vec![Arc::new(LoggingMiddleware)]);
793
794 let merged = router1.merge(router2);
795
796 assert!(merged.middleware_groups().contains_key("auth"));
798 assert!(merged.middleware_groups().contains_key("api"));
799
800 let auth_group = merged.middleware_groups().get("auth").unwrap();
802 assert_eq!(auth_group.len(), 1);
803 assert_eq!(auth_group.names(), vec!["SimpleAuthMiddleware"]);
804
805 let api_group = merged.middleware_groups().get("api").unwrap();
806 assert_eq!(api_group.len(), 1);
807 assert_eq!(api_group.names(), vec!["LoggingMiddleware"]);
808
809 assert_eq!(merged.middleware_pipeline().len(), 2);
811 assert_eq!(
812 merged.middleware_pipeline().names(),
813 vec!["LoggingMiddleware", "SimpleAuthMiddleware"]
814 );
815 }
816
817 #[test]
818 fn test_middleware_group_with_multiple_middleware() {
819 use crate::middleware::v2::{LoggingMiddleware, SimpleAuthMiddleware};
820 use std::sync::Arc;
821
822 let router = Router::<()>::new()
823 .middleware_group(
824 "api",
825 vec![
826 Arc::new(LoggingMiddleware),
827 Arc::new(SimpleAuthMiddleware::new("secret".to_string())),
828 ],
829 )
830 .get("/", elif_handler);
831
832 let api_group = router.middleware_groups().get("api").unwrap();
834 assert_eq!(api_group.len(), 2);
835 assert_eq!(
836 api_group.names(),
837 vec!["LoggingMiddleware", "SimpleAuthMiddleware"]
838 );
839 }
840
841 #[test]
842 fn test_middleware_merge_preserves_global_middleware() {
843 use crate::middleware::v2::{LoggingMiddleware, SimpleAuthMiddleware};
844
845 let router1 = Router::<()>::new()
847 .use_middleware(LoggingMiddleware)
848 .use_middleware(SimpleAuthMiddleware::new("router1".to_string()));
849
850 let router2 = Router::<()>::new()
851 .use_middleware(SimpleAuthMiddleware::new("router2".to_string()))
852 .use_middleware(LoggingMiddleware);
853
854 let merged = router1.merge(router2);
855
856 assert_eq!(merged.middleware_pipeline().len(), 4);
858
859 assert_eq!(
861 merged.middleware_pipeline().names(),
862 vec![
863 "LoggingMiddleware",
864 "SimpleAuthMiddleware",
865 "SimpleAuthMiddleware",
866 "LoggingMiddleware"
867 ]
868 );
869 }
870
871 #[test]
872 fn test_nested_router_middleware_scoping() {
873 use crate::middleware::v2::{LoggingMiddleware, SimpleAuthMiddleware};
874
875 let parent_router = Router::<()>::new()
877 .use_middleware(LoggingMiddleware)
878 .get("/parent", elif_handler);
879
880 let nested_router = Router::<()>::new()
882 .use_middleware(SimpleAuthMiddleware::new("nested_secret".to_string()))
883 .get("/nested", elif_handler);
884
885 let composed_router = parent_router.nest("/api", nested_router);
887
888 assert_eq!(composed_router.middleware_pipeline().len(), 1);
890 assert_eq!(
891 composed_router.middleware_pipeline().names(),
892 vec!["LoggingMiddleware"]
893 );
894
895 let registry = composed_router.registry();
898 let reg = registry.lock().unwrap();
899 let route_count = reg.all_routes().len();
900
901 assert_eq!(
904 route_count, 2,
905 "Expected 2 routes after nesting (parent + nested)"
906 );
907
908 }
912
913 #[test]
914 fn test_nested_router_middleware_groups_merged() {
915 use crate::middleware::v2::LoggingMiddleware;
916 use std::sync::Arc;
917
918 let parent_router = Router::<()>::new()
920 .middleware_group("parent_group", vec![Arc::new(LoggingMiddleware)])
921 .get("/parent", elif_handler);
922
923 let nested_router = Router::<()>::new()
925 .middleware_group("nested_group", vec![Arc::new(LoggingMiddleware)])
926 .get("/nested", elif_handler);
927
928 let composed_router = parent_router.nest("/api", nested_router);
930
931 assert!(composed_router
933 .middleware_groups()
934 .contains_key("parent_group"));
935 assert!(composed_router
936 .middleware_groups()
937 .contains_key("nested_group"));
938
939 let parent_group = composed_router
941 .middleware_groups()
942 .get("parent_group")
943 .unwrap();
944 assert_eq!(parent_group.len(), 1);
945 assert_eq!(parent_group.names(), vec!["LoggingMiddleware"]);
946
947 let nested_group = composed_router
948 .middleware_groups()
949 .get("nested_group")
950 .unwrap();
951 assert_eq!(nested_group.len(), 1);
952 assert_eq!(nested_group.names(), vec!["LoggingMiddleware"]);
953 }
954
955 #[test]
956 fn test_nested_router_empty_middleware_optimization() {
957 use crate::middleware::v2::LoggingMiddleware;
958
959 let parent_router = Router::<()>::new()
961 .use_middleware(LoggingMiddleware)
962 .get("/parent", elif_handler);
963
964 let nested_router = Router::<()>::new().get("/nested", elif_handler);
966
967 assert_eq!(nested_router.middleware_pipeline().len(), 0);
969 assert!(nested_router.middleware_pipeline().is_empty());
970
971 let composed_router = parent_router.nest("/api", nested_router);
973
974 assert_eq!(composed_router.middleware_pipeline().len(), 1);
976 assert_eq!(
977 composed_router.middleware_pipeline().names(),
978 vec!["LoggingMiddleware"]
979 );
980
981 }
984
985 #[test]
986 fn test_controller_registration() {
987 use crate::controller::{ControllerRoute, ElifController, RouteParam};
988 use crate::routing::params::ParamType;
989
990 struct TestController;
992
993 #[async_trait::async_trait]
994 impl ElifController for TestController {
995 fn name(&self) -> &str {
996 "TestController"
997 }
998 fn base_path(&self) -> &str {
999 "/test"
1000 }
1001
1002 fn routes(&self) -> Vec<ControllerRoute> {
1003 vec![
1004 ControllerRoute::new(HttpMethod::GET, "", "list"),
1005 ControllerRoute::new(HttpMethod::GET, "/{id}", "show")
1006 .add_param(RouteParam::new("id", ParamType::Integer)),
1007 ControllerRoute::new(HttpMethod::POST, "", "create"),
1008 ]
1009 }
1010
1011 async fn handle_request(
1012 self: std::sync::Arc<Self>,
1013 method_name: String,
1014 _request: ElifRequest,
1015 ) -> HttpResult<ElifResponse> {
1016 match method_name.as_str() {
1017 "list" => Ok(ElifResponse::ok().text("List method")),
1018 "show" => Ok(ElifResponse::ok().text("Show method")),
1019 "create" => Ok(ElifResponse::ok().text("Create method")),
1020 _ => Ok(ElifResponse::not_found().text("Method not found")),
1021 }
1022 }
1023 }
1024
1025 let controller = TestController;
1026 let router = Router::<()>::new().controller(controller);
1027
1028 let registry = router.registry();
1030 let reg = registry.lock().unwrap();
1031 assert_eq!(reg.all_routes().len(), 3);
1032
1033 let controller_registry = router.controller_registry();
1035 let ctrl_reg = controller_registry.lock().unwrap();
1036 assert!(ctrl_reg.get_controller("TestController").is_some());
1037 }
1038
1039 #[test]
1040 fn test_combine_paths_edge_cases() {
1041 let router = Router::<()>::new();
1042
1043 assert_eq!(router.combine_paths("/users", "/posts"), "/users/posts");
1045 assert_eq!(router.combine_paths("/users", "posts"), "/users/posts");
1046 assert_eq!(router.combine_paths("users", "/posts"), "users/posts");
1047 assert_eq!(router.combine_paths("users", "posts"), "users/posts");
1048
1049 assert_eq!(router.combine_paths("", ""), "/"); assert_eq!(router.combine_paths("/", ""), "/"); assert_eq!(router.combine_paths("", "/"), "/"); assert_eq!(router.combine_paths("/", "/"), "/"); assert_eq!(router.combine_paths("/users/", ""), "/users");
1057 assert_eq!(router.combine_paths("/users/", "/posts"), "/users/posts");
1058 assert_eq!(router.combine_paths("/", "posts"), "/posts");
1059 assert_eq!(router.combine_paths("users", "/"), "users");
1060 }
1061
1062 #[test]
1063 fn test_controller_with_root_base_path() {
1064 use crate::controller::{ControllerRoute, ElifController};
1065
1066 struct RootController;
1068
1069 #[async_trait::async_trait]
1070 impl ElifController for RootController {
1071 fn name(&self) -> &str {
1072 "RootController"
1073 }
1074 fn base_path(&self) -> &str {
1075 "/"
1076 } fn routes(&self) -> Vec<ControllerRoute> {
1079 vec![
1080 ControllerRoute::new(HttpMethod::GET, "", "home"), ControllerRoute::new(HttpMethod::GET, "/health", "health"), ]
1083 }
1084
1085 async fn handle_request(
1086 self: std::sync::Arc<Self>,
1087 method_name: String,
1088 _request: ElifRequest,
1089 ) -> HttpResult<ElifResponse> {
1090 match method_name.as_str() {
1091 "home" => Ok(ElifResponse::ok().text("Home")),
1092 "health" => Ok(ElifResponse::ok().text("Health")),
1093 _ => Ok(ElifResponse::not_found().text("Not found")),
1094 }
1095 }
1096 }
1097
1098 let controller = RootController;
1099 let router = Router::<()>::new().controller(controller);
1100
1101 let registry = router.registry();
1103 let reg = registry.lock().unwrap();
1104 let routes = reg.all_routes();
1105
1106 assert_eq!(routes.len(), 2);
1108
1109 let paths: Vec<&String> = routes.values().map(|route| &route.path).collect();
1111 assert!(paths.contains(&&"/".to_string()));
1112 assert!(paths.contains(&&"/health".to_string()));
1113 }
1114
1115 #[test]
1116 fn test_controller_with_empty_base_path() {
1117 use crate::controller::{ControllerRoute, ElifController};
1118
1119 struct EmptyBaseController;
1121
1122 #[async_trait::async_trait]
1123 impl ElifController for EmptyBaseController {
1124 fn name(&self) -> &str {
1125 "EmptyBaseController"
1126 }
1127 fn base_path(&self) -> &str {
1128 ""
1129 } fn routes(&self) -> Vec<ControllerRoute> {
1132 vec![
1133 ControllerRoute::new(HttpMethod::GET, "", "root"), ControllerRoute::new(HttpMethod::GET, "/api", "api"), ]
1136 }
1137
1138 async fn handle_request(
1139 self: std::sync::Arc<Self>,
1140 method_name: String,
1141 _request: ElifRequest,
1142 ) -> HttpResult<ElifResponse> {
1143 match method_name.as_str() {
1144 "root" => Ok(ElifResponse::ok().text("Root")),
1145 "api" => Ok(ElifResponse::ok().text("API")),
1146 _ => Ok(ElifResponse::not_found().text("Not found")),
1147 }
1148 }
1149 }
1150
1151 let controller = EmptyBaseController;
1152 let router = Router::<()>::new().controller(controller);
1153
1154 let registry = router.registry();
1156 let reg = registry.lock().unwrap();
1157 let routes = reg.all_routes();
1158
1159 assert_eq!(routes.len(), 2);
1161
1162 let paths: Vec<&String> = routes.values().map(|route| &route.path).collect();
1164 assert!(paths.contains(&&"/".to_string()));
1165 assert!(paths.contains(&&"/api".to_string()));
1166 }
1167
1168 #[tokio::test]
1169 async fn test_concurrent_router_merge_no_deadlock() {
1170 use crate::controller::{ControllerRoute, ElifController};
1171 use tokio::time::{timeout, Duration};
1172
1173 struct TestControllerA;
1175 #[async_trait::async_trait]
1176 impl ElifController for TestControllerA {
1177 fn name(&self) -> &str {
1178 "TestControllerA"
1179 }
1180 fn base_path(&self) -> &str {
1181 "/a"
1182 }
1183 fn routes(&self) -> Vec<ControllerRoute> {
1184 vec![ControllerRoute::new(HttpMethod::GET, "", "test")]
1185 }
1186 async fn handle_request(
1187 self: std::sync::Arc<Self>,
1188 _method_name: String,
1189 _request: ElifRequest,
1190 ) -> HttpResult<ElifResponse> {
1191 Ok(ElifResponse::ok().text("A"))
1192 }
1193 }
1194
1195 struct TestControllerB;
1196 #[async_trait::async_trait]
1197 impl ElifController for TestControllerB {
1198 fn name(&self) -> &str {
1199 "TestControllerB"
1200 }
1201 fn base_path(&self) -> &str {
1202 "/b"
1203 }
1204 fn routes(&self) -> Vec<ControllerRoute> {
1205 vec![ControllerRoute::new(HttpMethod::GET, "", "test")]
1206 }
1207 async fn handle_request(
1208 self: std::sync::Arc<Self>,
1209 _method_name: String,
1210 _request: ElifRequest,
1211 ) -> HttpResult<ElifResponse> {
1212 Ok(ElifResponse::ok().text("B"))
1213 }
1214 }
1215
1216 let task1 = tokio::spawn(async move {
1218 let a_copy = Router::<()>::new().controller(TestControllerA);
1220 let b_copy = Router::<()>::new().controller(TestControllerB);
1221 let _merged = a_copy.merge(b_copy);
1222 });
1223
1224 let task2 = tokio::spawn(async move {
1225 let a_copy = Router::<()>::new().controller(TestControllerA);
1227 let b_copy = Router::<()>::new().controller(TestControllerB);
1228 let _merged = b_copy.merge(a_copy);
1229 });
1230
1231 let result = timeout(Duration::from_millis(100), async {
1233 let _ = tokio::try_join!(task1, task2);
1234 })
1235 .await;
1236
1237 assert!(
1239 result.is_ok(),
1240 "Router merge operations should not deadlock"
1241 );
1242 }
1243
1244 #[test]
1245 fn test_controller_merge_preserves_all_controllers() {
1246 use crate::controller::{ControllerRoute, ElifController};
1247
1248 struct ControllerA;
1249 #[async_trait::async_trait]
1250 impl ElifController for ControllerA {
1251 fn name(&self) -> &str {
1252 "ControllerA"
1253 }
1254 fn base_path(&self) -> &str {
1255 "/a"
1256 }
1257 fn routes(&self) -> Vec<ControllerRoute> {
1258 vec![ControllerRoute::new(HttpMethod::GET, "", "test")]
1259 }
1260 async fn handle_request(
1261 self: std::sync::Arc<Self>,
1262 _method_name: String,
1263 _request: ElifRequest,
1264 ) -> HttpResult<ElifResponse> {
1265 Ok(ElifResponse::ok().text("A"))
1266 }
1267 }
1268
1269 struct ControllerB;
1270 #[async_trait::async_trait]
1271 impl ElifController for ControllerB {
1272 fn name(&self) -> &str {
1273 "ControllerB"
1274 }
1275 fn base_path(&self) -> &str {
1276 "/b"
1277 }
1278 fn routes(&self) -> Vec<ControllerRoute> {
1279 vec![ControllerRoute::new(HttpMethod::GET, "", "test")]
1280 }
1281 async fn handle_request(
1282 self: std::sync::Arc<Self>,
1283 _method_name: String,
1284 _request: ElifRequest,
1285 ) -> HttpResult<ElifResponse> {
1286 Ok(ElifResponse::ok().text("B"))
1287 }
1288 }
1289
1290 let router_a = Router::<()>::new().controller(ControllerA);
1291 let router_b = Router::<()>::new().controller(ControllerB);
1292
1293 let merged_router = router_a.merge(router_b);
1294
1295 let controller_registry = merged_router.controller_registry();
1297 let registry = controller_registry.lock().unwrap();
1298
1299 assert!(registry.get_controller("ControllerA").is_some());
1300 assert!(registry.get_controller("ControllerB").is_some());
1301
1302 let names = registry.controller_names();
1304 assert_eq!(names.len(), 2);
1305 assert!(names.contains(&&"ControllerA".to_string()));
1306 assert!(names.contains(&&"ControllerB".to_string()));
1307 }
1308
1309 #[test]
1310 fn test_simple_nest_route_registration() {
1311 let parent_router = Router::<()>::new().get("/parent", elif_handler);
1313
1314 let nested_router = Router::<()>::new().get("/nested", elif_handler);
1315
1316 assert_eq!(
1318 parent_router.registry().lock().unwrap().all_routes().len(),
1319 1
1320 );
1321 assert_eq!(
1322 nested_router.registry().lock().unwrap().all_routes().len(),
1323 1
1324 );
1325
1326 let composed_router = parent_router.nest("/api", nested_router);
1328
1329 let route_count = composed_router
1331 .registry()
1332 .lock()
1333 .unwrap()
1334 .all_routes()
1335 .len();
1336
1337 assert_eq!(
1340 route_count, 2,
1341 "Expected both parent and nested routes to be registered, got: {}",
1342 route_count
1343 );
1344 }
1345
1346 #[test]
1347 fn test_route_builder_with_middleware_groups() {
1348 use crate::middleware::v2::LoggingMiddleware;
1349 use std::sync::Arc;
1350
1351 let router = Router::<()>::new()
1353 .middleware_group("api", vec![Arc::new(LoggingMiddleware)])
1354 .middleware_group("auth", vec![Arc::new(LoggingMiddleware)])
1355 .route("/api/users")
1356 .use_group("api")
1357 .use_group("auth")
1358 .get(elif_handler);
1359
1360 assert!(router.middleware_groups().contains_key("api"));
1362 assert!(router.middleware_groups().contains_key("auth"));
1363
1364 assert_eq!(router.route_middleware().len(), 1);
1366
1367 let route_middleware = router.route_middleware().values().next().unwrap();
1369 assert_eq!(route_middleware.len(), 2);
1370 assert!(route_middleware.contains(&"api".to_string()));
1371 assert!(route_middleware.contains(&"auth".to_string()));
1372 }
1373
1374 #[test]
1375 fn test_route_builder_chaining() {
1376 use crate::middleware::v2::LoggingMiddleware;
1377 use std::sync::Arc;
1378
1379 let router = Router::<()>::new()
1380 .middleware_group("api", vec![Arc::new(LoggingMiddleware)])
1381 .route("/api/users")
1382 .use_group("api")
1383 .name("users.index")
1384 .get(elif_handler);
1385
1386 let binding = router.registry();
1388 let registry = binding.lock().unwrap();
1389 let routes: Vec<_> = registry.all_routes().values().collect();
1390 assert_eq!(routes.len(), 1);
1391
1392 let route = routes[0];
1393 assert_eq!(route.path, "/api/users");
1394 assert_eq!(route.name, Some("users.index".to_string()));
1395 assert_eq!(route.method, HttpMethod::GET);
1396 }
1397
1398 #[test]
1399 fn test_multiple_routes_with_different_middleware() {
1400 use crate::middleware::v2::{LoggingMiddleware, SimpleAuthMiddleware};
1401 use std::sync::Arc;
1402
1403 let router = Router::<()>::new()
1404 .middleware_group("api", vec![Arc::new(LoggingMiddleware)])
1405 .middleware_group(
1406 "auth",
1407 vec![Arc::new(SimpleAuthMiddleware::new("secret".to_string()))],
1408 )
1409 .route("/api/public")
1410 .use_group("api")
1411 .get(elif_handler)
1412 .route("/api/protected")
1413 .use_group("api")
1414 .use_group("auth")
1415 .get(elif_handler)
1416 .route("/api/admin")
1417 .use_group("auth")
1418 .get(elif_handler);
1419
1420 assert_eq!(router.registry().lock().unwrap().all_routes().len(), 3);
1422
1423 let route_middleware = router.route_middleware();
1425 assert_eq!(route_middleware.len(), 3);
1426
1427 let middleware_counts: Vec<usize> = route_middleware.values().map(|v| v.len()).collect();
1429 middleware_counts
1430 .iter()
1431 .for_each(|&count| assert!(count > 0));
1432
1433 let total_middleware_assignments: usize = middleware_counts.iter().sum();
1435 assert_eq!(total_middleware_assignments, 4); }
1437
1438 #[test]
1439 fn test_ioc_controller_registration() {
1440 use crate::controller::{factory::IocControllable, ControllerRoute, ElifController};
1441 use elif_core::container::IocContainer;
1442 use elif_core::ServiceBinder;
1443 use std::sync::Arc;
1444
1445 #[derive(Default)]
1447 struct TestService {
1448 #[allow(dead_code)]
1449 name: String,
1450 }
1451
1452 unsafe impl Send for TestService {}
1453 unsafe impl Sync for TestService {}
1454
1455 struct IocTestController {
1457 #[allow(dead_code)]
1458 service: Arc<TestService>,
1459 }
1460
1461 #[async_trait::async_trait]
1462 impl ElifController for IocTestController {
1463 fn name(&self) -> &str {
1464 "IocTestController"
1465 }
1466 fn base_path(&self) -> &str {
1467 "/ioc-test"
1468 }
1469
1470 fn routes(&self) -> Vec<ControllerRoute> {
1471 vec![
1472 ControllerRoute::new(HttpMethod::GET, "", "list"),
1473 ControllerRoute::new(HttpMethod::GET, "/{id}", "show"),
1474 ]
1475 }
1476
1477 async fn handle_request(
1478 self: Arc<Self>,
1479 method_name: String,
1480 _request: ElifRequest,
1481 ) -> HttpResult<ElifResponse> {
1482 match method_name.as_str() {
1483 "list" => Ok(ElifResponse::ok().text("IoC List")),
1484 "show" => Ok(ElifResponse::ok().text("IoC Show")),
1485 _ => Ok(ElifResponse::not_found().text("Method not found")),
1486 }
1487 }
1488 }
1489
1490 impl IocControllable for IocTestController {
1491 fn from_ioc_container(
1492 container: &IocContainer,
1493 _scope: Option<&elif_core::container::ScopeId>,
1494 ) -> Result<Self, String> {
1495 let service = container
1496 .resolve::<TestService>()
1497 .map_err(|e| format!("Failed to resolve TestService: {}", e))?;
1498
1499 Ok(Self { service })
1500 }
1501 }
1502
1503 let mut container = IocContainer::new();
1505 container.bind::<TestService, TestService>();
1506 container.build().expect("Container build failed");
1507
1508 let container_arc = Arc::new(container);
1509
1510 let router = Router::<()>::new()
1512 .with_ioc_container(Arc::clone(&container_arc))
1513 .controller_from_container::<IocTestController>();
1514
1515 let registry = router.registry();
1517 let reg = registry.lock().unwrap();
1518 assert_eq!(reg.all_routes().len(), 2);
1519
1520 let controller_registry = router.controller_registry();
1522 let ctrl_reg = controller_registry.lock().unwrap();
1523 assert!(ctrl_reg.get_controller("IocTestController").is_some());
1524 }
1525
1526 #[test]
1527 #[should_panic(expected = "IoC container must be set before registering IoC controllers")]
1528 fn test_ioc_controller_without_container() {
1529 use crate::controller::{factory::IocControllable, ControllerRoute, ElifController};
1530 use elif_core::container::IocContainer;
1531
1532 struct TestController;
1533
1534 #[async_trait::async_trait]
1535 impl ElifController for TestController {
1536 fn name(&self) -> &str {
1537 "TestController"
1538 }
1539 fn base_path(&self) -> &str {
1540 "/test"
1541 }
1542 fn routes(&self) -> Vec<ControllerRoute> {
1543 vec![]
1544 }
1545
1546 async fn handle_request(
1547 self: std::sync::Arc<Self>,
1548 _method_name: String,
1549 _request: ElifRequest,
1550 ) -> HttpResult<ElifResponse> {
1551 Ok(ElifResponse::ok().text("test"))
1552 }
1553 }
1554
1555 impl IocControllable for TestController {
1556 fn from_ioc_container(
1557 _container: &IocContainer,
1558 _scope: Option<&elif_core::container::ScopeId>,
1559 ) -> Result<Self, String> {
1560 Ok(Self)
1561 }
1562 }
1563
1564 Router::<()>::new().controller_from_container::<TestController>();
1566 }
1567
1568 #[test]
1569 fn test_router_with_ioc_container() {
1570 use elif_core::container::IocContainer;
1571 use std::sync::Arc;
1572
1573 let container = Arc::new(IocContainer::new());
1574 let router = Router::<()>::new().with_ioc_container(Arc::clone(&container));
1575
1576 assert!(router.ioc_container().is_some());
1577 assert!(Arc::ptr_eq(router.ioc_container().unwrap(), &container));
1578 }
1579
1580 #[test]
1581 fn test_merge_preserves_ioc_container() {
1582 use elif_core::container::IocContainer;
1583 use std::sync::Arc;
1584
1585 let container = Arc::new(IocContainer::new());
1586
1587 let router1 = Router::<()>::new().with_ioc_container(Arc::clone(&container));
1588
1589 let router2 = Router::<()>::new();
1590
1591 let merged = router1.merge(router2);
1592
1593 assert!(merged.ioc_container().is_some());
1595 assert!(Arc::ptr_eq(merged.ioc_container().unwrap(), &container));
1596 }
1597
1598 #[test]
1599 fn test_merge_prefers_first_container() {
1600 use elif_core::container::IocContainer;
1601 use std::sync::Arc;
1602
1603 let container1 = Arc::new(IocContainer::new());
1604 let container2 = Arc::new(IocContainer::new());
1605
1606 let router1 = Router::<()>::new().with_ioc_container(Arc::clone(&container1));
1607
1608 let router2 = Router::<()>::new().with_ioc_container(Arc::clone(&container2));
1609
1610 let merged = router1.merge(router2);
1611
1612 assert!(merged.ioc_container().is_some());
1614 assert!(Arc::ptr_eq(merged.ioc_container().unwrap(), &container1));
1615 }
1616
1617 #[test]
1618 fn test_scoped_controller_registration() {
1619 use crate::controller::{factory::IocControllable, ControllerRoute, ElifController};
1620 use elif_core::container::IocContainer;
1621 use elif_core::ServiceBinder;
1622 use std::sync::Arc;
1623
1624 #[derive(Default)]
1625 struct ScopedService {
1626 #[allow(dead_code)]
1627 id: String,
1628 }
1629
1630 unsafe impl Send for ScopedService {}
1631 unsafe impl Sync for ScopedService {}
1632
1633 struct ScopedController {
1634 #[allow(dead_code)]
1635 service: Arc<ScopedService>,
1636 }
1637
1638 #[async_trait::async_trait]
1639 impl ElifController for ScopedController {
1640 fn name(&self) -> &str {
1641 "ScopedController"
1642 }
1643 fn base_path(&self) -> &str {
1644 "/scoped"
1645 }
1646
1647 fn routes(&self) -> Vec<ControllerRoute> {
1648 vec![ControllerRoute::new(HttpMethod::GET, "/test", "test")]
1649 }
1650
1651 async fn handle_request(
1652 self: Arc<Self>,
1653 _method_name: String,
1654 _request: ElifRequest,
1655 ) -> HttpResult<ElifResponse> {
1656 Ok(ElifResponse::ok().text("Scoped"))
1657 }
1658 }
1659
1660 impl IocControllable for ScopedController {
1661 fn from_ioc_container(
1662 container: &IocContainer,
1663 _scope: Option<&elif_core::container::ScopeId>,
1664 ) -> Result<Self, String> {
1665 let service = container
1666 .resolve::<ScopedService>()
1667 .map_err(|e| format!("Failed to resolve ScopedService: {}", e))?;
1668
1669 Ok(Self { service })
1670 }
1671 }
1672
1673 let mut container = IocContainer::new();
1675 container.bind::<ScopedService, ScopedService>();
1676 container.build().expect("Container build failed");
1677
1678 let container_arc = Arc::new(container);
1679
1680 let router = Router::<()>::new()
1682 .with_ioc_container(Arc::clone(&container_arc))
1683 .scoped_controller_from_container::<ScopedController>();
1684
1685 let registry = router.registry();
1687 let reg = registry.lock().unwrap();
1688 assert_eq!(reg.all_routes().len(), 1);
1689
1690 let controller_registry = router.controller_registry();
1692 let ctrl_reg = controller_registry.lock().unwrap();
1693 assert!(ctrl_reg.get_controller("ScopedController").is_some());
1694 }
1695
1696 #[test]
1697 fn test_route_without_middleware_groups() {
1698 let router = Router::<()>::new().route("/simple").get(elif_handler);
1699
1700 let binding = router.registry();
1702 let registry = binding.lock().unwrap();
1703 assert_eq!(registry.all_routes().len(), 1);
1704
1705 let route_middleware = router.route_middleware();
1706 assert_eq!(route_middleware.len(), 1);
1707
1708 let middleware_groups = route_middleware.values().next().unwrap();
1710 assert_eq!(middleware_groups.len(), 0);
1711 }
1712}
1713
1714#[cfg(test)]
1715mod integration_tests {
1716 use super::*;
1717 use crate::middleware::v2::{Middleware, Next, NextFuture};
1718 use crate::response::ElifResponse;
1719 use serde_json::json;
1720 use std::collections::HashMap;
1721 use std::sync::{Arc, Mutex};
1722
1723 #[derive(Debug, Clone)]
1725 struct HeaderTestMiddleware {
1726 name: String,
1727 counter: Arc<Mutex<usize>>,
1728 }
1729
1730 impl HeaderTestMiddleware {
1731 fn new(name: &str) -> Self {
1732 Self {
1733 name: name.to_string(),
1734 counter: Arc::new(Mutex::new(0)),
1735 }
1736 }
1737 }
1738
1739 impl Middleware for HeaderTestMiddleware {
1740 fn handle(&self, mut request: ElifRequest, next: Next) -> NextFuture<'static> {
1741 let name = self.name.clone();
1742 let counter = self.counter.clone();
1743
1744 Box::pin(async move {
1745 {
1747 let mut count = counter.lock().unwrap();
1748 *count += 1;
1749 }
1750
1751 let header_name = crate::response::headers::ElifHeaderName::from_str(&format!(
1753 "x-middleware-{}",
1754 name.to_lowercase()
1755 ))
1756 .unwrap();
1757 let header_value =
1758 crate::response::headers::ElifHeaderValue::from_str("executed").unwrap();
1759 request.headers.insert(header_name, header_value);
1760
1761 let response = next.run(request).await;
1763
1764 let response_header = format!("x-response-{}", name.to_lowercase());
1766 response
1767 .header(&response_header, "executed")
1768 .unwrap_or_else(|_| {
1769 ElifResponse::ok().text("Middleware executed")
1771 })
1772 })
1773 }
1774
1775 fn name(&self) -> &'static str {
1776 match self.name.as_str() {
1778 "Parent" => "Parent",
1779 "Nested" => "Nested",
1780 "Global" => "Global",
1781 "First" => "First",
1782 "Second" => "Second",
1783 "Third" => "Third",
1784 "Router1" => "Router1",
1785 "Router2" => "Router2",
1786 _ => "TestMiddleware",
1787 }
1788 }
1789 }
1790
1791 async fn test_handler(request: ElifRequest) -> HttpResult<ElifResponse> {
1793 let mut response_headers = HashMap::new();
1795
1796 for (key, value) in request.headers.iter() {
1797 let key_str = key.as_str().to_string();
1798 if let Ok(value_str) = value.to_str() {
1799 response_headers.insert(key_str, value_str.to_string());
1800 }
1801 }
1802
1803 Ok(ElifResponse::ok().json(&json!({
1804 "message": "Hello from handler",
1805 "request_headers": response_headers,
1806 "path": request.path()
1807 }))?)
1808 }
1809
1810 async fn nested_handler(request: ElifRequest) -> HttpResult<ElifResponse> {
1811 Ok(ElifResponse::ok().json(&json!({
1812 "message": "Hello from nested handler",
1813 "path": request.path()
1814 }))?)
1815 }
1816
1817 #[tokio::test]
1818 async fn test_global_middleware_execution() {
1819 let test_middleware = HeaderTestMiddleware::new("Global");
1821 let middleware_counter = test_middleware.counter.clone();
1822
1823 let router = Router::<()>::new()
1825 .use_middleware(test_middleware)
1826 .get("/test", test_handler);
1827
1828 assert_eq!(router.middleware_pipeline().len(), 1);
1830 assert_eq!(router.middleware_pipeline().names(), vec!["Global"]);
1831
1832 assert_eq!(middleware_counter.lock().unwrap().clone(), 0);
1834
1835 let request = ElifRequest::new(
1837 crate::request::ElifMethod::GET,
1838 "/test".parse().unwrap(),
1839 crate::response::headers::ElifHeaderMap::new(),
1840 );
1841
1842 let response = router
1843 .middleware_pipeline()
1844 .execute(request, |req| {
1845 Box::pin(async move {
1846 let header_name =
1848 crate::response::headers::ElifHeaderName::from_str("x-middleware-global")
1849 .unwrap();
1850 assert!(req.headers.contains_key(&header_name));
1851 ElifResponse::ok().text("Pipeline test response")
1852 })
1853 })
1854 .await;
1855
1856 assert_eq!(middleware_counter.lock().unwrap().clone(), 1);
1858 assert_eq!(
1859 response.status_code(),
1860 crate::response::status::ElifStatusCode::OK
1861 );
1862 }
1863
1864 #[tokio::test]
1865 async fn test_nested_router_middleware_isolation() {
1866 let parent_middleware = HeaderTestMiddleware::new("Parent");
1868 let nested_middleware = HeaderTestMiddleware::new("Nested");
1869
1870 let parent_counter = parent_middleware.counter.clone();
1871 let nested_counter = nested_middleware.counter.clone();
1872
1873 let parent_router = Router::<()>::new()
1875 .use_middleware(parent_middleware)
1876 .get("/parent", test_handler);
1877
1878 let nested_router = Router::<()>::new()
1880 .use_middleware(nested_middleware)
1881 .get("/nested", nested_handler);
1882
1883 let composed_router = parent_router.nest("/api", nested_router);
1885
1886 assert_eq!(composed_router.middleware_pipeline().len(), 1); assert_eq!(
1889 composed_router.middleware_pipeline().names(),
1890 vec!["Parent"]
1891 );
1892
1893 assert_eq!(parent_counter.lock().unwrap().clone(), 0);
1895 assert_eq!(nested_counter.lock().unwrap().clone(), 0);
1896
1897 let parent_request = ElifRequest::new(
1901 crate::request::ElifMethod::GET,
1902 "/parent".parse().unwrap(),
1903 crate::response::headers::ElifHeaderMap::new(),
1904 );
1905
1906 let parent_response = composed_router
1907 .middleware_pipeline()
1908 .execute(parent_request, |req| {
1909 Box::pin(async move {
1910 let parent_header =
1912 crate::response::headers::ElifHeaderName::from_str("x-middleware-parent")
1913 .unwrap();
1914 let nested_header =
1915 crate::response::headers::ElifHeaderName::from_str("x-middleware-nested")
1916 .unwrap();
1917 assert!(req.headers.contains_key(&parent_header));
1918 assert!(!req.headers.contains_key(&nested_header));
1919 ElifResponse::ok().text("Parent response")
1920 })
1921 })
1922 .await;
1923
1924 assert_eq!(
1925 parent_response.status_code(),
1926 crate::response::status::ElifStatusCode::OK
1927 );
1928 assert_eq!(parent_counter.lock().unwrap().clone(), 1);
1929 assert_eq!(nested_counter.lock().unwrap().clone(), 0); }
1935
1936 #[tokio::test]
1937 async fn test_middleware_execution_order() {
1938 let first_middleware = HeaderTestMiddleware::new("First");
1940 let second_middleware = HeaderTestMiddleware::new("Second");
1941 let third_middleware = HeaderTestMiddleware::new("Third");
1942
1943 let first_counter = first_middleware.counter.clone();
1944 let second_counter = second_middleware.counter.clone();
1945 let third_counter = third_middleware.counter.clone();
1946
1947 let router = Router::<()>::new()
1949 .use_middleware(first_middleware)
1950 .use_middleware(second_middleware)
1951 .use_middleware(third_middleware)
1952 .get("/test", test_handler);
1953
1954 assert_eq!(router.middleware_pipeline().len(), 3);
1956 assert_eq!(
1957 router.middleware_pipeline().names(),
1958 vec!["First", "Second", "Third"]
1959 );
1960
1961 let request = ElifRequest::new(
1963 crate::request::ElifMethod::GET,
1964 "/test".parse().unwrap(),
1965 crate::response::headers::ElifHeaderMap::new(),
1966 );
1967
1968 let response = router
1969 .middleware_pipeline()
1970 .execute(request, |req| {
1971 Box::pin(async move {
1972 let first_header =
1974 crate::response::headers::ElifHeaderName::from_str("x-middleware-first")
1975 .unwrap();
1976 let second_header =
1977 crate::response::headers::ElifHeaderName::from_str("x-middleware-second")
1978 .unwrap();
1979 let third_header =
1980 crate::response::headers::ElifHeaderName::from_str("x-middleware-third")
1981 .unwrap();
1982 assert!(req.headers.contains_key(&first_header));
1983 assert!(req.headers.contains_key(&second_header));
1984 assert!(req.headers.contains_key(&third_header));
1985
1986 ElifResponse::ok().text("Handler executed after all middleware")
1987 })
1988 })
1989 .await;
1990
1991 assert_eq!(first_counter.lock().unwrap().clone(), 1);
1993 assert_eq!(second_counter.lock().unwrap().clone(), 1);
1994 assert_eq!(third_counter.lock().unwrap().clone(), 1);
1995 assert_eq!(
1996 response.status_code(),
1997 crate::response::status::ElifStatusCode::OK
1998 );
1999 }
2000
2001 #[tokio::test]
2002 async fn test_router_merge_middleware_execution() {
2003 let router1_middleware = HeaderTestMiddleware::new("Router1");
2005 let router2_middleware = HeaderTestMiddleware::new("Router2");
2006
2007 let router1_counter = router1_middleware.counter.clone();
2008 let router2_counter = router2_middleware.counter.clone();
2009
2010 let router1 = Router::<()>::new()
2012 .use_middleware(router1_middleware)
2013 .get("/router1", test_handler);
2014
2015 let router2 = Router::<()>::new()
2016 .use_middleware(router2_middleware)
2017 .get("/router2", test_handler);
2018
2019 let merged_router = router1.merge(router2);
2021
2022 assert_eq!(merged_router.middleware_pipeline().len(), 2);
2024 assert_eq!(
2025 merged_router.middleware_pipeline().names(),
2026 vec!["Router1", "Router2"]
2027 );
2028
2029 let request = ElifRequest::new(
2031 crate::request::ElifMethod::GET,
2032 "/test".parse().unwrap(),
2033 crate::response::headers::ElifHeaderMap::new(),
2034 );
2035
2036 let response = merged_router
2037 .middleware_pipeline()
2038 .execute(request, |req| {
2039 Box::pin(async move {
2040 let router1_header =
2042 crate::response::headers::ElifHeaderName::from_str("x-middleware-router1")
2043 .unwrap();
2044 let router2_header =
2045 crate::response::headers::ElifHeaderName::from_str("x-middleware-router2")
2046 .unwrap();
2047 assert!(req.headers.contains_key(&router1_header));
2048 assert!(req.headers.contains_key(&router2_header));
2049
2050 ElifResponse::ok().text("Merged router response")
2051 })
2052 })
2053 .await;
2054
2055 assert_eq!(router1_counter.lock().unwrap().clone(), 1);
2057 assert_eq!(router2_counter.lock().unwrap().clone(), 1);
2058 assert_eq!(
2059 response.status_code(),
2060 crate::response::status::ElifStatusCode::OK
2061 );
2062 }
2063
2064 #[tokio::test]
2065 async fn test_middleware_with_early_return() {
2066 #[derive(Debug)]
2068 struct AuthMiddleware {
2069 required_token: String,
2070 }
2071
2072 impl AuthMiddleware {
2073 fn new(token: String) -> Self {
2074 Self {
2075 required_token: token,
2076 }
2077 }
2078 }
2079
2080 impl Middleware for AuthMiddleware {
2081 fn handle(&self, request: ElifRequest, next: Next) -> NextFuture<'static> {
2082 let required_token = self.required_token.clone();
2083 Box::pin(async move {
2084 let auth_header = request
2086 .header("authorization")
2087 .and_then(|h| h.to_str().ok());
2088
2089 match auth_header {
2090 Some(header) if header.starts_with("Bearer ") => {
2091 let token = &header[7..];
2092 if token == required_token {
2093 next.run(request).await
2095 } else {
2096 ElifResponse::unauthorized().json_value(json!({
2098 "error": {
2099 "code": "invalid_token",
2100 "message": "Invalid authorization token"
2101 }
2102 }))
2103 }
2104 }
2105 _ => {
2106 ElifResponse::unauthorized().json_value(json!({
2108 "error": {
2109 "code": "missing_token",
2110 "message": "Authorization header required"
2111 }
2112 }))
2113 }
2114 }
2115 })
2116 }
2117
2118 fn name(&self) -> &'static str {
2119 "AuthMiddleware"
2120 }
2121 }
2122
2123 let router = Router::<()>::new()
2125 .use_middleware(AuthMiddleware::new("secret123".to_string()))
2126 .get("/protected", test_handler);
2127
2128 let request_no_auth = ElifRequest::new(
2130 crate::request::ElifMethod::GET,
2131 "/protected".parse().unwrap(),
2132 crate::response::headers::ElifHeaderMap::new(),
2133 );
2134
2135 let response_no_auth = router
2136 .middleware_pipeline()
2137 .execute(request_no_auth, |_req| {
2138 Box::pin(async move {
2139 panic!("Handler should not be called when auth fails");
2141 })
2142 })
2143 .await;
2144
2145 assert_eq!(
2146 response_no_auth.status_code(),
2147 crate::response::status::ElifStatusCode::UNAUTHORIZED
2148 );
2149
2150 let mut headers = crate::response::headers::ElifHeaderMap::new();
2152 let auth_header =
2153 crate::response::headers::ElifHeaderName::from_str("authorization").unwrap();
2154 let auth_value =
2155 crate::response::headers::ElifHeaderValue::from_str("Bearer secret123").unwrap();
2156 headers.insert(auth_header, auth_value);
2157 let request_valid_auth = ElifRequest::new(
2158 crate::request::ElifMethod::GET,
2159 "/protected".parse().unwrap(),
2160 headers,
2161 );
2162
2163 let response_valid_auth = router
2164 .middleware_pipeline()
2165 .execute(request_valid_auth, |req| {
2166 Box::pin(async move {
2167 assert!(req.header("authorization").is_some());
2169 ElifResponse::ok().text("Protected content accessed")
2170 })
2171 })
2172 .await;
2173
2174 assert_eq!(
2175 response_valid_auth.status_code(),
2176 crate::response::status::ElifStatusCode::OK
2177 );
2178
2179 let mut headers = crate::response::headers::ElifHeaderMap::new();
2181 let auth_header =
2182 crate::response::headers::ElifHeaderName::from_str("authorization").unwrap();
2183 let auth_value =
2184 crate::response::headers::ElifHeaderValue::from_str("Bearer invalid").unwrap();
2185 headers.insert(auth_header, auth_value);
2186 let request_invalid_auth = ElifRequest::new(
2187 crate::request::ElifMethod::GET,
2188 "/protected".parse().unwrap(),
2189 headers,
2190 );
2191
2192 let response_invalid_auth = router
2193 .middleware_pipeline()
2194 .execute(request_invalid_auth, |_req| {
2195 Box::pin(async move {
2196 panic!("Handler should not be called when auth token is invalid");
2198 })
2199 })
2200 .await;
2201
2202 assert_eq!(
2203 response_invalid_auth.status_code(),
2204 crate::response::status::ElifStatusCode::UNAUTHORIZED
2205 );
2206 }
2207}
2208
2209pub fn controller_handler<C>(
2211 controller: Arc<C>,
2212 method_name: String,
2213) -> impl Fn(ElifRequest) -> Pin<Box<dyn Future<Output = HttpResult<ElifResponse>> + Send>>
2214 + Clone
2215 + Send
2216 + Sync
2217 + 'static
2218where
2219 C: ElifController + 'static,
2220{
2221 move |request: ElifRequest| {
2222 let controller = Arc::clone(&controller);
2223 let method_name = method_name.clone();
2224
2225 Box::pin(async move { controller.handle_request(method_name, request).await })
2226 }
2227}
2228
2229pub struct ControllerRegistry {
2231 controllers: HashMap<String, Arc<dyn ElifController>>,
2232}
2233
2234impl std::fmt::Debug for ControllerRegistry {
2235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2236 f.debug_struct("ControllerRegistry")
2237 .field(
2238 "controllers",
2239 &format!("{} controllers", self.controllers.len()),
2240 )
2241 .finish()
2242 }
2243}
2244
2245impl Default for ControllerRegistry {
2246 fn default() -> Self {
2247 Self::new()
2248 }
2249}
2250
2251impl ControllerRegistry {
2252 pub fn new() -> Self {
2253 Self {
2254 controllers: HashMap::new(),
2255 }
2256 }
2257
2258 pub fn register(&mut self, name: String, controller: Arc<dyn ElifController>) {
2259 self.controllers.insert(name, controller);
2260 }
2261
2262 pub fn get_controller(&self, name: &str) -> Option<&Arc<dyn ElifController>> {
2263 self.controllers.get(name)
2264 }
2265
2266 pub fn all_controllers(&self) -> impl Iterator<Item = (&String, &Arc<dyn ElifController>)> {
2267 self.controllers.iter()
2268 }
2269
2270 pub fn controller_names(&self) -> Vec<&String> {
2271 self.controllers.keys().collect()
2272 }
2273}
2274
2275pub fn scoped_ioc_controller_handler<C>(
2277 container: Arc<IocContainer>,
2278 method_name: String,
2279) -> impl Fn(ElifRequest) -> Pin<Box<dyn Future<Output = HttpResult<ElifResponse>> + Send>>
2280 + Clone
2281 + Send
2282 + Sync
2283 + 'static
2284where
2285 C: ElifController + IocControllable + 'static,
2286{
2287 move |request: ElifRequest| {
2288 let container = Arc::clone(&container);
2289 let method_name = method_name.clone();
2290
2291 Box::pin(async move {
2292 let scope_id =
2294 container
2295 .create_scope()
2296 .map_err(|e| crate::errors::HttpError::InternalError {
2297 message: format!("Failed to create request scope: {}", e),
2298 })?;
2299
2300 let controller = C::from_ioc_container(&container, Some(&scope_id)).map_err(|e| {
2302 crate::errors::HttpError::InternalError {
2303 message: format!("Failed to resolve scoped controller: {}", e),
2304 }
2305 })?;
2306
2307 let controller_arc = Arc::new(controller);
2308 let result = controller_arc.handle_request(method_name, request).await;
2309
2310 let container_clone = Arc::clone(&container);
2312 tokio::spawn(async move {
2313 if let Err(e) = container_clone.dispose_scope(&scope_id).await {
2314 eprintln!("Failed to dispose request scope: {}", e);
2315 }
2316 });
2317
2318 result
2319 })
2320 }
2321}