use super::*;
use crate::config::AppConfig;
fn make_mysql_conn() -> DatabaseConnection {
DatabaseConnection {
r#type: "mysql".to_string(),
hostname: "172.17.16.14".to_string(),
database: "shop".to_string(),
username: "shop".to_string(),
password: String::new(),
hostport: 8802,
charset: "utf8mb4".to_string(),
prefix: "sz_".to_string(),
deploy: 0,
rw_separate: false,
fields_strict: true,
break_reconnect: true,
}
}
#[test]
fn test_app_init_and_global() {
let config = AppConfig::default();
let app = App::init(config);
let app2 = App::global();
assert!(app2.is_some());
assert!(std::ptr::eq(app, app2.unwrap()));
let config2 = AppConfig::default();
let app3 = App::init(config2);
assert!(std::ptr::eq(app, app3));
}
#[test]
fn test_db_connection() {
let mut config = AppConfig::default();
config
.database
.connections
.insert("mysql".to_string(), make_mysql_conn());
let app = App::new(config);
let conn = app.db_connection("mysql");
assert!(conn.is_some());
let conn = conn.unwrap();
assert_eq!(conn.hostname, "172.17.16.14");
assert_eq!(conn.hostport, 8802);
assert_eq!(conn.prefix, "sz_");
}
#[test]
fn test_db_connection_not_found() {
let config = AppConfig::default();
let app = App::new(config);
assert!(app.db_connection("nonexistent").is_none());
}
#[test]
fn test_default_db_connection() {
let mut config = AppConfig::default();
config.database.default = "mysql".to_string();
config
.database
.connections
.insert("mysql".to_string(), make_mysql_conn());
let app = App::new(config);
let conn = app.default_db_connection();
assert!(conn.is_some());
assert_eq!(conn.unwrap().database, "shop");
}
#[test]
fn test_cache() {
let config = AppConfig::default();
let app = App::new(config);
assert!(app.cache().is_none());
app.set_cache("memory_cache");
assert_eq!(app.cache(), Some("memory_cache".to_string()));
}
#[test]
fn test_log() {
let config = AppConfig::default();
let app = App::new(config);
assert!(app.log().is_none());
app.set_log("file_logger");
assert_eq!(app.log(), Some("file_logger".to_string()));
}
#[test]
fn test_db_connection_names() {
let mut config = AppConfig::default();
config
.database
.connections
.insert("mysql".to_string(), make_mysql_conn());
config.database.connections.insert(
"njszjt".to_string(),
DatabaseConnection {
r#type: "mysql".to_string(),
hostname: "172.17.16.14".to_string(),
database: "njszjt".to_string(),
username: "njszjt".to_string(),
password: String::new(),
hostport: 8802,
charset: "utf8mb4".to_string(),
prefix: "soci_".to_string(),
deploy: 0,
rw_separate: false,
fields_strict: true,
break_reconnect: true,
},
);
let app = App::new(config);
let mut names = app.db_connection_names();
names.sort();
assert_eq!(names, vec!["mysql", "njszjt"]);
}
#[test]
fn test_load_5_db_connections() {
let config_dir = std::env::current_dir().ok().and_then(|d| {
let mut current = d.clone();
for _ in 0..5 {
if current.join("config").exists() {
return Some(current.join("config"));
}
if let Some(parent) = current.parent() {
current = parent.to_path_buf();
} else {
break;
}
}
None
});
let Some(config_dir) = config_dir else {
eprintln!("跳过:未找到 config 目录");
return;
};
let config = AppConfig::load_from_dir(&config_dir).unwrap();
let names: Vec<&str> = config
.database
.connections
.keys()
.map(|s| s.as_str())
.collect();
assert!(
names.len() >= 5,
"应有 5 个数据库连接,实际 {}: {:?}",
names.len(),
names
);
assert!(config.database.connections.contains_key("mysql"));
assert!(config.database.connections.contains_key("njszjt"));
assert!(config.database.connections.contains_key("ljclz"));
assert!(config.database.connections.contains_key("food"));
assert!(config.database.connections.contains_key("oceanbase"));
assert_eq!(config.database.default, "mysql");
let default_conn = config.database.connections.get("mysql").unwrap();
assert_eq!(default_conn.hostname, "localhost");
assert_eq!(default_conn.hostport, 8802);
assert_eq!(default_conn.prefix, "sz_");
}
#[derive(Debug, PartialEq)]
struct TestService {
value: i32,
}
impl TestService {
fn new() -> Self {
Self { value: 42 }
}
}
#[test]
fn test_container_bind_transient() {
let container = Container::new();
container.bind(TestService::new);
let s1 = container.make::<TestService>().expect("应能解析服务");
let s2 = container.make::<TestService>().expect("应能解析服务");
assert!(!Arc::ptr_eq(&s1, &s2));
assert_eq!(s1.value, 42);
assert_eq!(s2.value, 42);
}
#[test]
fn test_container_singleton() {
let container = Container::new();
container.singleton(TestService::new);
let s1 = container.make::<TestService>().expect("应能解析服务");
let s2 = container.make::<TestService>().expect("应能解析服务");
assert!(Arc::ptr_eq(&s1, &s2));
assert_eq!(s1.value, 42);
}
#[test]
fn test_container_make_unregistered() {
let container = Container::new();
assert!(container.make::<TestService>().is_none());
}
#[test]
fn test_container_has() {
let container = Container::new();
assert!(!container.has::<TestService>());
container.singleton(TestService::new);
assert!(container.has::<TestService>());
}
#[test]
fn test_container_forget() {
let container = Container::new();
container.singleton(TestService::new);
let _ = container.make::<TestService>();
assert!(container.has::<TestService>());
container.forget::<TestService>();
assert!(!container.has::<TestService>());
assert!(container.make::<TestService>().is_none());
}
#[test]
fn test_container_clear() {
let container = Container::new();
container.singleton(TestService::new);
container.bind(|| 99i32);
assert_eq!(container.count(), 2);
container.clear();
assert_eq!(container.count(), 0);
}
#[test]
fn test_app_di_proxy() {
let config = AppConfig::default();
let app = App::new(config);
app.singleton(TestService::new);
assert!(app.has_service::<TestService>());
let s1 = app.make::<TestService>().expect("应能解析");
let s2 = app.make::<TestService>().expect("应能解析");
assert!(Arc::ptr_eq(&s1, &s2));
}
#[test]
fn test_container_multiple_types() {
let container = Container::new();
container.singleton(TestService::new);
container.singleton(|| String::from("logger"));
container.bind(|| vec![1, 2, 3]);
assert_eq!(container.make::<TestService>().unwrap().value, 42);
assert_eq!(&*container.make::<String>().unwrap(), "logger");
assert_eq!(*container.make::<Vec<i32>>().unwrap(), vec![1, 2, 3]);
}
#[test]
fn test_container_count() {
let container = Container::new();
assert_eq!(container.count(), 0);
container.bind(TestService::new);
assert_eq!(container.count(), 1);
container.singleton(|| String::from("x"));
assert_eq!(container.count(), 2);
}
struct ScopedCounter {
value: i64,
}
impl ScopedCounter {
fn new(value: i64) -> Self {
Self { value }
}
}
#[test]
fn test_container_scoped_same_scope() {
let container = Container::new();
container.scoped(|| ScopedCounter::new(100));
let s1 = container
.make_with_scope::<ScopedCounter>(1)
.expect("应能解析 scoped 服务");
let s2 = container
.make_with_scope::<ScopedCounter>(1)
.expect("应能解析 scoped 服务");
assert!(Arc::ptr_eq(&s1, &s2), "同一作用域内必须返回同一实例");
assert_eq!(s1.value, 100);
}
#[test]
fn test_container_scoped_different_scope() {
let container = Container::new();
container.scoped(|| ScopedCounter::new(200));
let s1 = container
.make_with_scope::<ScopedCounter>(1)
.expect("scope 1 应能解析");
let s2 = container
.make_with_scope::<ScopedCounter>(2)
.expect("scope 2 应能解析");
assert!(!Arc::ptr_eq(&s1, &s2), "不同作用域必须返回不同实例");
assert_eq!(s1.value, 200);
assert_eq!(s2.value, 200);
}
#[test]
fn test_container_clear_scope() {
let container = Container::new();
container.scoped(|| ScopedCounter::new(300));
let s1 = container
.make_with_scope::<ScopedCounter>(1)
.expect("scope 1 应能解析");
assert_eq!(container.active_scope_count(), 1);
container.clear_scope(1);
assert_eq!(container.active_scope_count(), 0);
let s2 = container
.make_with_scope::<ScopedCounter>(1)
.expect("scope 1 清理后应能再次解析");
assert!(!Arc::ptr_eq(&s1, &s2), "清理后再次解析必须返回新实例");
}
#[test]
fn test_container_scoped_with_singleton() {
let container = Container::new();
container.singleton(|| ScopedCounter::new(1000));
container.scoped(|| ScopedCounter::new(2000));
let single_a = container.make_with_scope::<ScopedCounter>(1);
let single_b = container.make_with_scope::<ScopedCounter>(2);
let scoped_a = container
.make_with_scope::<ScopedCounter>(1)
.expect("应能解析");
let scoped_b = container
.make_with_scope::<ScopedCounter>(2)
.expect("应能解析");
assert!(!Arc::ptr_eq(&scoped_a, &scoped_b));
let _ = (single_a, single_b);
}
#[test]
fn test_container_forget_clears_scoped() {
let container = Container::new();
container.scoped(|| ScopedCounter::new(400));
let _ = container.make_with_scope::<ScopedCounter>(1);
let _ = container.make_with_scope::<ScopedCounter>(2);
let _ = container.make_with_scope::<ScopedCounter>(3);
assert_eq!(container.active_scope_count(), 3);
container.forget::<ScopedCounter>();
assert!(!container.has::<ScopedCounter>());
}
#[test]
fn test_container_clear_all() {
let container = Container::new();
container.singleton(TestService::new);
container.scoped(|| ScopedCounter::new(500));
container.alias::<TestService>("svc");
let _ = container.make_with_scope::<ScopedCounter>(1);
assert_eq!(container.count(), 2);
assert_eq!(container.alias_count(), 1);
assert_eq!(container.active_scope_count(), 1);
container.clear();
assert_eq!(container.count(), 0);
assert_eq!(container.alias_count(), 0);
assert_eq!(container.active_scope_count(), 0);
}
#[test]
fn test_container_instance_direct_binding() {
let container = Container::new();
let original = Arc::new(TestService { value: 999 });
container.instance(TestService { value: 999 });
let resolved = container
.make::<TestService>()
.expect("instance() 注册的服务应能解析");
assert_eq!(resolved.value, 999);
let resolved2 = container.make::<TestService>().expect("应能再次解析");
assert!(Arc::ptr_eq(&resolved, &resolved2));
let _ = original;
}
#[test]
fn test_container_instance_has() {
let container = Container::new();
assert!(!container.has::<TestService>());
container.instance(TestService::new());
assert!(container.has::<TestService>());
}
#[test]
fn test_container_instance_forget() {
let container = Container::new();
container.instance(TestService::new());
assert!(container.has::<TestService>());
container.forget::<TestService>();
assert!(!container.has::<TestService>());
assert!(container.make::<TestService>().is_none());
}
#[test]
fn test_app_instance_scoped_alias_proxy() {
let config = AppConfig::default();
let app = App::new(config);
app.instance(TestService { value: 777 });
let s = app.make::<TestService>().expect("App::instance 后应能解析");
assert_eq!(s.value, 777);
app.scoped(|| ScopedCounter::new(888));
let s1 = app
.make_with_scope::<ScopedCounter>(42)
.expect("App::make_with_scope 应能解析");
let s2 = app
.make_with_scope::<ScopedCounter>(42)
.expect("同 scope 应能再次解析");
assert!(Arc::ptr_eq(&s1, &s2));
app.alias::<TestService>("test_svc");
assert!(app.container().is_alias("test_svc"));
let type_id = app
.container()
.resolve_alias("test_svc")
.expect("别名应能解析");
assert_eq!(type_id, std::any::TypeId::of::<TestService>());
app.clear_scope(42);
assert_eq!(app.container().active_scope_count(), 0);
}
#[test]
fn test_container_alias_register_and_resolve() {
let container = Container::new();
container.singleton(TestService::new);
container.alias::<TestService>("test_service");
assert!(container.is_alias("test_service"));
assert!(!container.is_alias("nonexistent"));
let type_id = container
.resolve_alias("test_service")
.expect("别名应能解析");
assert_eq!(type_id, std::any::TypeId::of::<TestService>());
}
#[test]
fn test_container_alias_resolve_unregistered() {
let container = Container::new();
assert!(container.resolve_alias("not_registered").is_none());
}
#[test]
fn test_container_multiple_aliases() {
let container = Container::new();
container.singleton(TestService::new);
container.singleton(|| String::from("logger"));
container.alias::<TestService>("svc1");
container.alias::<TestService>("svc2");
container.alias::<String>("logger");
assert_eq!(container.alias_count(), 3);
let mut aliases = container.debug_aliases();
aliases.sort();
assert_eq!(
aliases,
vec!["logger".to_string(), "svc1".to_string(), "svc2".to_string()]
);
let tid1 = container.resolve_alias("svc1").unwrap();
let tid2 = container.resolve_alias("svc2").unwrap();
assert_eq!(tid1, tid2);
}
#[test]
fn test_container_alias_does_not_affect_make() {
let container = Container::new();
container.singleton(TestService::new);
container.alias::<TestService>("my_svc");
let svc = container.make::<TestService>().expect("make 应正常工作");
assert_eq!(svc.value, 42);
container.alias::<String>("my_str");
assert!(container.is_alias("my_str"));
assert!(container.make::<String>().is_none());
}