#![allow(non_snake_case)]
mod common;
use rust_dix::*;
use rust_dix_macros::Inject;
use std::sync::Arc;
#[derive(Inject)]
struct HandlerWithProvider {
#[inject(provider)]
provider: Arc<ServiceProvider>,
}
impl HandlerWithProvider {
fn resolve_dep(&self) -> common::MyService {
self.provider.get_owned::<common::MyService>().unwrap()
}
}
#[test]
fn provider_inject_resolves_via_build() {
let p = ServiceCollection::new()
.transient(|_| Arc::new(common::MyService { value: 42 }))
.transient(|r| __rdi_construct_HandlerWithProvider(r))
.build()
.unwrap();
let h = p.get_owned::<HandlerWithProvider>().unwrap();
assert_eq!(h.resolve_dep().value, 42);
}
#[test]
fn provider_inject_field_is_some() {
let p = ServiceCollection::new()
.transient(|_| Arc::new(common::MyService { value: 0 }))
.transient(|r| __rdi_construct_HandlerWithProvider(r))
.build()
.unwrap();
let h = p.get_owned::<HandlerWithProvider>().unwrap();
assert!(IServiceResolver::provider_arc(&*p).is_some());
assert_eq!(h.provider.get_owned::<common::MyService>().unwrap().value, 0);
}
#[test]
fn provider_inject_works_through_scope() {
let p = ServiceCollection::new()
.scoped(|_| Arc::new(common::MyService { value: 99 }))
.transient(|r| __rdi_construct_HandlerWithProvider(r))
.build()
.unwrap();
let scope = p.scope();
let h: HandlerWithProvider = scope.get_owned().unwrap();
assert_eq!(h.resolve_dep().value, 99);
let s1: Arc<common::MyService> = h.provider.get().unwrap();
let s2: Arc<common::MyService> = h.provider.get().unwrap();
assert!(
Arc::ptr_eq(&s1, &s2),
"scope 内 Scoped 应缓存复用(同一 Arc)"
);
let root_svc: Arc<common::MyService> = p.get().unwrap();
assert!(
!Arc::ptr_eq(&s1, &root_svc),
"scope 与 root 的 Scoped 实例应独立"
);
}
#[test]
fn scope_provider_resolves_scoped_within_scope() {
use std::sync::atomic::{AtomicU64, Ordering};
static CALLS: AtomicU64 = AtomicU64::new(0);
struct ScopedSvc(u64);
let p = ServiceCollection::new()
.scoped(|_| {
let n = CALLS.fetch_add(1, Ordering::SeqCst);
Arc::new(ScopedSvc(n))
})
.transient(|r| __rdi_construct_HandlerWithProvider(r))
.build()
.unwrap();
let scope1 = p.scope();
let h1: HandlerWithProvider = scope1.get_owned().unwrap();
let a: Arc<ScopedSvc> = h1.provider.get().unwrap();
let b: Arc<ScopedSvc> = h1.provider.get().unwrap();
assert_eq!(a.0, b.0, "scope1 内 ScopedSvc 复用同一序号");
assert!(Arc::ptr_eq(&a, &b), "scope1 缓存命中(同一 Arc)");
let scope2 = p.scope();
let h2: HandlerWithProvider = scope2.get_owned().unwrap();
let c: Arc<ScopedSvc> = h2.provider.get().unwrap();
assert_ne!(a.0, c.0, "scope2 应有独立 ScopedSvc 实例");
assert!(!Arc::ptr_eq(&a, &c), "不同 scope 的 ScopedSvc 必须独立");
let root_svc: Arc<ScopedSvc> = p.get().unwrap();
assert_ne!(a.0, root_svc.0);
assert_ne!(c.0, root_svc.0);
assert_eq!(
CALLS.load(Ordering::SeqCst),
3,
"ScopedSvc 工厂应执行 3 次(三 scope 各一次)"
);
}
#[derive(Inject)]
struct MixedProviderHandler {
#[inject]
logger: Arc<common::Logger>,
#[inject(provider)]
provider: Arc<ServiceProvider>,
}
#[test]
fn provider_inject_mixed_with_regular_inject() {
let p = ServiceCollection::new()
.singleton(|_| Arc::new(common::Logger { prefix: "log".into() }))
.transient(|_| Arc::new(common::MyService { value: 7 }))
.transient(|r| __rdi_construct_MixedProviderHandler(r))
.build()
.unwrap();
let h = p.get_owned::<MixedProviderHandler>().unwrap();
assert_eq!(h.logger.prefix, "log");
assert_eq!(h.provider.get_owned::<common::MyService>().unwrap().value, 7);
}