#[cfg(test)]
mod tests {
use std::sync::Arc;
use crate::container::{IocContainer, ServiceBinder};
use crate::foundation::traits::{FrameworkComponent, Service};
#[derive(Clone, Debug, Default)]
pub struct UserRepository {
#[allow(dead_code)]
pub users: Vec<String>,
}
unsafe impl Send for UserRepository {}
unsafe impl Sync for UserRepository {}
impl FrameworkComponent for UserRepository {}
impl Service for UserRepository {}
#[derive(Clone, Debug, Default)]
pub struct EmailService {
#[allow(dead_code)]
pub sent_emails: Vec<String>,
}
unsafe impl Send for EmailService {}
unsafe impl Sync for EmailService {}
impl FrameworkComponent for EmailService {}
impl Service for EmailService {}
#[derive(Clone, Debug, Default)]
pub struct LoggerService {
#[allow(dead_code)]
pub logs: Vec<String>,
}
unsafe impl Send for LoggerService {}
unsafe impl Sync for LoggerService {}
impl FrameworkComponent for LoggerService {}
impl Service for LoggerService {}
pub struct UserController {
pub user_repo: Arc<UserRepository>,
pub email_service: Arc<EmailService>,
pub logger: Arc<LoggerService>,
}
impl UserController {
pub fn from_ioc_container(
container: &IocContainer,
_scope: Option<&crate::container::ScopeId>,
) -> Result<Self, String> {
let user_repo = container
.resolve::<UserRepository>()
.map_err(|e| format!("Failed to resolve UserRepository: {}", e))?;
let email_service = container
.resolve::<EmailService>()
.map_err(|e| format!("Failed to resolve EmailService: {}", e))?;
let logger = container
.resolve::<LoggerService>()
.map_err(|e| format!("Failed to resolve LoggerService: {}", e))?;
Ok(Self {
user_repo,
email_service,
logger,
})
}
pub fn create_user(&self, username: &str) -> Result<(), String> {
if username.is_empty() {
return Err("Username cannot be empty".to_string());
}
println!("Creating user: {}", username);
Ok(())
}
pub fn send_welcome_email(&self, email: &str) -> Result<(), String> {
println!("Sending welcome email to: {}", email);
Ok(())
}
}
pub struct LoggingMiddleware {
pub logger: Arc<LoggerService>,
}
impl LoggingMiddleware {
pub fn from_ioc_container(
container: &IocContainer,
_scope: Option<&crate::container::ScopeId>,
) -> Result<Self, String> {
let logger = container
.resolve::<LoggerService>()
.map_err(|e| format!("Failed to resolve LoggerService: {}", e))?;
Ok(Self { logger })
}
pub fn log_request(&self, path: &str) {
println!("Logging request to: {}", path);
}
}
#[tokio::test]
async fn test_complete_ioc_integration() {
let mut container = IocContainer::new();
container.bind::<UserRepository, UserRepository>();
container.bind::<EmailService, EmailService>();
container.bind::<LoggerService, LoggerService>();
container.build().expect("Container build should succeed");
let user_controller = UserController::from_ioc_container(&container, None)
.expect("Controller creation should succeed");
assert!(Arc::strong_count(&user_controller.user_repo) > 0);
assert!(Arc::strong_count(&user_controller.email_service) > 0);
assert!(Arc::strong_count(&user_controller.logger) > 0);
user_controller
.create_user("test_user")
.expect("User creation should succeed");
user_controller
.send_welcome_email("test@example.com")
.expect("Email sending should succeed");
}
#[tokio::test]
async fn test_middleware_dependency_injection() {
let mut container = IocContainer::new();
container.bind::<LoggerService, LoggerService>();
container.build().expect("Container build should succeed");
let logging_middleware = LoggingMiddleware::from_ioc_container(&container, None)
.expect("Middleware creation should succeed");
logging_middleware.log_request("/api/users");
assert!(Arc::strong_count(&logging_middleware.logger) > 0);
}
#[tokio::test]
async fn test_scoped_service_injection() {
let mut container = IocContainer::new();
let scoped_config = crate::container::AdvancedBindingBuilder::<LoggerService>::new()
.with_lifetime(crate::container::ServiceScope::Scoped)
.config();
container.with_implementation::<LoggerService, LoggerService>(scoped_config);
container.build().expect("Container build should succeed");
let scope_id = container
.create_scope()
.expect("Scope creation should succeed");
let logger1 = container
.resolve_scoped::<LoggerService>(&scope_id)
.expect("Scoped service resolution should succeed");
let logger2 = container
.resolve_scoped::<LoggerService>(&scope_id)
.expect("Second scoped service resolution should succeed");
assert!(Arc::ptr_eq(&logger1, &logger2));
container
.dispose_scope(&scope_id)
.await
.expect("Scope disposal should succeed");
}
#[tokio::test]
async fn test_named_service_injection() {
let mut container = IocContainer::new();
container.bind_named::<LoggerService, LoggerService>("primary");
container.bind_named::<LoggerService, LoggerService>("secondary");
container.build().expect("Container build should succeed");
let primary = container
.resolve_named::<LoggerService>("primary")
.expect("Primary logger resolution should succeed");
let secondary = container
.resolve_named::<LoggerService>("secondary")
.expect("Secondary logger resolution should succeed");
assert!(Arc::strong_count(&primary) > 0);
assert!(Arc::strong_count(&secondary) > 0);
assert!(!Arc::ptr_eq(&primary, &secondary));
}
#[tokio::test]
async fn test_factory_pattern_integration() {
let mut container = IocContainer::new();
container.bind_factory::<LoggerService, _, _>(|| Ok(LoggerService::default()));
container.build().expect("Container build should succeed");
let logger = container
.resolve::<LoggerService>()
.expect("Factory service resolution should succeed");
assert!(Arc::strong_count(&logger) > 0);
}
#[tokio::test]
async fn test_collection_binding_integration() {
let mut container = IocContainer::new();
container.bind::<UserRepository, UserRepository>();
container.bind::<EmailService, EmailService>();
container.bind::<LoggerService, LoggerService>();
container.build().expect("Container build should succeed");
let user_repo = container
.resolve::<UserRepository>()
.expect("UserRepository should be resolvable");
let email_service = container
.resolve::<EmailService>()
.expect("EmailService should be resolvable");
let logger = container
.resolve::<LoggerService>()
.expect("LoggerService should be resolvable");
assert!(Arc::strong_count(&user_repo) > 0);
assert!(Arc::strong_count(&email_service) > 0);
assert!(Arc::strong_count(&logger) > 0);
}
#[tokio::test]
async fn test_conditional_binding() {
let mut container = IocContainer::new();
let is_development = std::env::var("ENVIRONMENT")
.unwrap_or_else(|_| "development".to_string())
== "development";
if is_development {
container.bind::<LoggerService, LoggerService>();
} else {
container.bind::<LoggerService, LoggerService>();
}
container.build().expect("Container build should succeed");
let logger = container
.resolve::<LoggerService>()
.expect("Conditional service resolution should succeed");
assert!(Arc::strong_count(&logger) > 0);
}
#[tokio::test]
async fn test_lazy_initialization() {
let mut container = IocContainer::new();
container.bind_lazy::<LoggerService, _, _>(|| {
println!("Lazy initializing LoggerService");
LoggerService::default()
});
container.build().expect("Container build should succeed");
let logger = container
.resolve::<LoggerService>()
.expect("Lazy service resolution should succeed");
assert!(Arc::strong_count(&logger) > 0);
}
#[tokio::test]
async fn test_parameterized_factory() {
let mut container = IocContainer::new();
container.bind_factory::<LoggerService, _, _>(|| {
let service = LoggerService::default();
println!("Creating logger from factory");
Ok(service)
});
container.build().expect("Container build should succeed");
let logger = container
.resolve::<LoggerService>()
.expect("Factory service resolution should succeed");
assert!(Arc::strong_count(&logger) > 0);
}
#[tokio::test]
async fn test_container_validation() {
let mut container = IocContainer::new();
container.bind::<UserRepository, UserRepository>();
container.bind::<EmailService, EmailService>();
container.bind::<LoggerService, LoggerService>();
container.build().expect("Container build should succeed");
container
.validate()
.expect("Container validation should succeed");
let validation_errors = container.validate_all_services();
assert!(validation_errors.is_ok(), "All services should be valid");
}
#[test]
fn test_service_statistics() {
let mut container = IocContainer::new();
container.bind::<UserRepository, UserRepository>();
container.bind_singleton::<EmailService, EmailService>();
container.bind_transient::<LoggerService, LoggerService>();
container.build().expect("Container build should succeed");
let stats = container.get_statistics();
assert_eq!(stats.total_services, 3);
assert_eq!(stats.singleton_services, 1);
assert_eq!(stats.transient_services, 2); }
#[tokio::test]
async fn test_async_service_initialization() {
{
let mut container = IocContainer::new();
container.bind::<LoggerService, LoggerService>();
container.build().expect("Container build should succeed");
container
.initialize_async()
.await
.expect("Async initialization should succeed");
}
{
let mut container = IocContainer::new();
container.bind::<LoggerService, LoggerService>();
container.build().expect("Container build should succeed");
container
.initialize_async_with_timeout(std::time::Duration::from_secs(5))
.await
.expect("Async initialization with timeout should succeed");
}
}
#[tokio::test]
async fn test_lifecycle_management() {
let mut container = IocContainer::new();
container.bind::<LoggerService, LoggerService>();
container.build().expect("Container build should succeed");
container
.initialize_async()
.await
.expect("Service initialization should succeed");
container
.dispose_all()
.await
.expect("Service disposal should succeed");
}
#[test]
fn test_debug_and_introspection() {
let mut container = IocContainer::new();
container.bind::<UserRepository, UserRepository>();
container.bind::<EmailService, EmailService>();
container.build().expect("Container build should succeed");
let registered_services = container.get_registered_services();
assert!(!registered_services.is_empty());
let service_info = container.get_service_info::<UserRepository>();
assert!(service_info.is_some());
}
}