use std::marker::PhantomData; use std::sync::Arc; use dyn_clone::DynClone; use mydi::{erase, Component, InjectionBinder}; use mydi_macros::ComponentExpander; #[test] fn resolve_simple_values() { #[derive(Component, Clone)] struct A { x: u32, } #[derive(Component, Clone)] struct B { a: A, } #[derive(Component, Clone)] struct C { b: B, } let inject = InjectionBinder::new() .instance(1u32) .inject::() .inject::() .inject::() .build() .unwrap(); let x = inject.get::().unwrap().b.a.x; assert_eq!(x, 1) } #[test] fn default_value() { #[derive(Component, Clone)] struct A { #[component(default)] x: u32, } #[derive(Component, Clone)] struct B { a: A, } #[derive(Component, Clone)] struct C { b: B, } let inject = InjectionBinder::new() .inject::() .inject::() .inject::() .build() .unwrap(); let x = inject.get::().unwrap().b.a.x; assert_eq!(x, 0) } #[test] fn default_value_func() { fn func() -> u32 { 2 } #[derive(Component, Clone)] struct A { #[component(default = func)] x: u32, } #[derive(Component, Clone)] struct B { a: A, } #[derive(Component, Clone)] struct C { b: B, } let inject = InjectionBinder::new() .inject::() .inject::() .inject::() .build() .unwrap(); let x = inject.get::().unwrap().b.a.x; assert_eq!(x, 2) } #[test] fn resolve_empty_structs() { #[derive(Component, Clone)] struct A { x: u32, } #[derive(Component, Clone)] struct B {} #[derive(Component, Clone)] struct C; let inject = InjectionBinder::new() .instance(1u32) .inject::() .inject::() .inject::() .build() .unwrap(); let x = inject.get::().unwrap().x; assert_eq!(x, 1); inject.get::().unwrap(); inject.get::().unwrap(); } #[test] fn resolve_simple_generic_values() { #[derive(Component, Clone)] struct A { x: T, } let inject = InjectionBinder::new() .instance(1u32) .instance(2u64) .inject::>() .inject::>() .build() .unwrap(); let x = inject.get::>().unwrap().x; assert_eq!(x, 1); let x = inject.get::>().unwrap().x; assert_eq!(x, 2); } #[test] fn resolve_simple_value_reverse_order() { #[derive(Component, Clone)] struct A { x: u32, } #[derive(Component, Clone)] struct B { a: A, } #[derive(Component, Clone)] struct C { b: B, } let inject = InjectionBinder::new() .inject::() .inject::() .inject::() .instance(1u32) .build() .unwrap(); let x = inject.get::().unwrap().b.a.x; assert_eq!(x, 1) } #[test] fn resolve_values_with_multiple_deps() { #[derive(Component, Clone)] struct A { x: u32, } #[derive(Component, Clone)] struct B { _a: A, x: u32, } #[derive(Component, Clone)] struct C { _b: B, _a: A, x: u64, } let inject = InjectionBinder::new() .inject::() .inject::() .inject::() .instance(1u32) .instance(2u64) .build() .unwrap(); let x = inject.get::().unwrap(); assert_eq!(x._b._a.x, 1); assert_eq!(x._b.x, 1); assert_eq!(x.x, 2); } #[test] fn resolve_auto_boxing() { #[derive(Component, Clone)] struct A { x: u32, } #[derive(Component, Clone)] struct B { a: Box, } #[derive(Component, Clone)] struct C { b: B, } let inject = InjectionBinder::new() .instance(1u32) .inject::().auto_box() .inject::() .inject::() .build() .unwrap(); let x = inject.get::().unwrap().b.a.x; assert_eq!(x, 1) } #[test] fn resolve_cyclic_dependencies() { #[derive(Component, Clone)] struct A { x: u32, c: mydi::Lazy, } #[derive(Component, Clone)] struct B { a: A, x: u32, } #[derive(Component, Clone)] struct C { b: B, _a: A, x: u64, } let binder1 = InjectionBinder::new() .inject::() .inject::>() .inject::(); let binder2 = InjectionBinder::new() .inject::() .instance(1u32) .instance(2u64); let inject = (binder1.merge(binder2)) .build() .unwrap(); let x = inject.get::().unwrap(); assert_eq!(x.b.a.x, 1); assert_eq!(x.b.x, 1); assert_eq!(x.x, 2); assert_eq!(x.b.a.c.x, 2); } #[test] fn resolve_values_with_multiple_binders() { #[derive(Component, Clone)] struct A { x: u32, } #[derive(Component, Clone)] struct B { _a: A, x: u32, } #[derive(Component, Clone)] struct C { _b: B, _a: A, x: u64, } let binder1 = InjectionBinder::new() .inject::() .inject::(); let binder2 = InjectionBinder::new() .inject::() .instance(1u32) .instance(2u64); let inject = (binder1.merge(binder2)) .build() .unwrap(); let x = inject.get::().unwrap(); assert_eq!(x._b._a.x, 1); assert_eq!(x._b.x, 1); assert_eq!(x.x, 2); } #[test] fn read_tuples() { #[derive(Component, Clone)] struct A { x: u32, } #[derive(Component, Clone)] struct B { _a: A, x: u32, } #[derive(Component, Clone)] struct C { _b: B, _a: A, x: u64, } let binder1 = InjectionBinder::new() .inject::() .inject::(); let binder2 = InjectionBinder::new() .inject::() .instance(1u32) .instance(2u64); let inject = (binder1.merge(binder2)) .build() .unwrap(); let (_, _, x) = inject.get_tuple::<(A, B, C)>().unwrap(); assert_eq!(x._b._a.x, 1); assert_eq!(x._b.x, 1); assert_eq!(x.x, 2); } #[test] fn resolve_values_with_multiple_deps_tuple_init() { #[derive(Component, Clone)] struct A { _x: u32, } #[derive(Component, Clone)] struct B { _a: A, _x: u32, } #[derive(Component, Clone)] struct C { _b: B, _a: A, _x: u64, } let inject = InjectionBinder::new() .inject_fn(|(_b, _a, _x)| C { _b, _a, _x }) .inject::() .inject::() .instance(1u32) .instance(2u64) .build() .unwrap(); let x = inject.get::().unwrap(); assert_eq!(x._b._a._x, 1); assert_eq!(x._b._x, 1); assert_eq!(x._x, 2); } #[test] fn fail_on_duplicate_values() { #[derive(Component, Clone)] struct A { _x: u32, } #[derive(Component, Clone)] struct B { _a: A, _x: u32, } #[derive(Component, Clone)] struct DuplicateStruct { _b: B, _a: A, _x: u64, } let inject_res = InjectionBinder::new() .inject::() .inject::() .inject::() .inject::() .instance(1u32) .instance(2u64) .build(); assert!(inject_res.is_err()); let err_string = inject_res.err().unwrap().to_string(); assert!(err_string.contains("Dependencies duplications found")); assert!(err_string.contains("DuplicateStruct")); } #[test] fn fail_on_duplicate_missing_values() { #[derive(Component, Clone)] struct A { _x: u32, } #[derive(Component, Clone)] struct B { _a: A, _x: u32, } #[derive(Clone)] struct MissingDep {} #[derive(Component, Clone)] struct StructWithoutDep { _b: B, _a: A, _x: u64, _missing: MissingDep, } let inject_res = InjectionBinder::new() .inject::() .inject::() .inject::() .instance(1u32) .instance(2u64) .build(); assert!(inject_res.is_err()); let err_string = inject_res.err().unwrap().to_string(); assert!(err_string.contains("Missing injection values")); assert!(err_string.contains("StructWithoutDep")); assert!(err_string.contains("MissingDep")); } #[test] fn fail_on_missing_lazy_values() { #[derive(Component, Clone)] struct MissingStruct { _x: u32, } let inject_res = InjectionBinder::new() .inject::>() .instance(1u32) .build(); assert!(inject_res.is_err()); let err_string = inject_res.err().unwrap().to_string(); assert!(err_string.contains("Missing injection values")); assert!(err_string.contains("MissingStruct")); } #[test] fn fail_on_nested_lazy_values() { #[derive(Component, Clone)] struct MissingStruct { _x: u32, } let inject_res = InjectionBinder::new() .inject::>() .inject::>>() .inject::() .instance(1u32) .build(); assert!(inject_res.is_err()); let err_string = inject_res.err().unwrap().to_string(); assert!(err_string.contains("Nested lazy dependencies")); assert!(err_string.contains("MissingStruct")); } #[test] fn work_with_arc_dyn_traits() { #[derive(Component, Clone)] pub struct A { x: u32, } trait Test { fn x(&self) -> u32; } impl Test for A { fn x(&self) -> u32 { self.x } } let inject_res = InjectionBinder::new() .inject::().auto(erase!(Arc)) .instance(1u32) .build() .unwrap(); let dyn_type = inject_res.get::>().unwrap(); assert_eq!(dyn_type.x(), 1u32) } #[test] fn work_with_box_dyn_traits() { #[derive(Component, Clone)] pub struct A { x: u32, } trait Test: DynClone { fn x(&self) -> u32; } dyn_clone::clone_trait_object!(Test); impl Test for A { fn x(&self) -> u32 { self.x } } let inject_res = InjectionBinder::new() .inject::().auto(erase!(Box)) .instance(1u32) .build() .unwrap(); let dyn_type = inject_res.get::>().unwrap(); assert_eq!(dyn_type.x(), 1u32) } #[test] fn fail_on_duplicate_missing_values_with_tuple_init() { #[derive(Component, Clone)] struct A { _x: u32, } #[derive(Component, Clone)] struct B { _a: A, _x: u32, } #[derive(Clone)] struct MissingDep {} #[derive(Component, Clone)] struct StructWithoutDep { _b: B, _a: A, _x: u64, _missing: MissingDep, } let inject_res = InjectionBinder::new() .inject_fn(|(_b, _a, _x, _missing)| StructWithoutDep { _b, _a, _x, _missing }) .inject::() .inject::() .instance(1u32) .instance(2u64) .build(); assert!(inject_res.is_err()); let err_string = inject_res.err().unwrap().to_string(); assert!(err_string.contains("Missing injection values")); assert!(err_string.contains("StructWithoutDep")); assert!(err_string.contains("MissingDep")); } #[test] fn fail_on_cyclic_dep() { #[derive(Component, Clone)] struct A { _x: u32, _cycle: Box, } #[derive(Component, Clone)] struct B { _a: A, _x: u32, } #[derive(Component, Clone)] struct ShouldNotBeInErr { _x: u32, } #[derive(Component, Clone)] struct CycleStart { _b: B, _a: A, _x: u64, _d: ShouldNotBeInErr, } let inject_res = InjectionBinder::new() .inject::>() .inject::() .inject::() .inject::() .instance(1u32) .instance(2u64) .build(); assert!(inject_res.is_err()); let err_string = inject_res.err().unwrap().to_string(); assert!(err_string.contains("Dependencies cycle (one or more) found")); assert!(err_string.contains("CycleStart")); assert!(err_string.contains("A")); assert!(!err_string.contains("ShouldNotBeInErr")); } #[test] fn should_work_with_expansion() { #[derive(ComponentExpander)] struct A { x: u32, } let inject = InjectionBinder::new() .expand(A { x: 1 }) .build() .unwrap(); let x = inject.get::().unwrap(); assert_eq!(x, 1); } #[test] fn should_work_with_expansion_with_multiple_fields() { #[derive(ComponentExpander)] struct A { x: u32, y: u64, } let inject = InjectionBinder::new() .expand(A { x: 1, y: 2 }) .build() .unwrap(); let x = inject.get::().unwrap(); assert_eq!(x, 1); let y = inject.get::().unwrap(); assert_eq!(y, 2); } #[test] fn should_work_with_expansion_with_box() { #[derive(ComponentExpander)] struct A { x: u32, y: u64, } let inject = InjectionBinder::new() .expand(Box::new(A { x: 1, y: 2 })) .build() .unwrap(); let x = inject.get::().unwrap(); assert_eq!(x, 1); let y = inject.get::().unwrap(); assert_eq!(y, 2); } #[test] fn should_work_with_expansion_with_arc() { #[derive(ComponentExpander, Clone)] struct A { x: u32, y: u64, } let inject = InjectionBinder::new() .expand(Arc::new(A { x: 1, y: 2 })) .build() .unwrap(); let x = inject.get::().unwrap(); assert_eq!(x, 1); let y = inject.get::().unwrap(); assert_eq!(y, 2); } #[test] fn should_work_with_expansion_with_ignore() { #[derive(ComponentExpander)] struct A { x: u32, #[ignore_expand] _y: u64, } let inject = InjectionBinder::new() .expand(A { x: 1, _y: 2 }) .build() .unwrap(); let x = inject.get::().unwrap(); assert_eq!(x, 1); let y = inject.get::(); assert_eq!(y.is_err(), true); } #[test] fn should_work_with_generics() { #[derive(ComponentExpander)] struct A { x: u32, #[ignore_expand] _p: PhantomData, } let inject = InjectionBinder::new() .expand(A::<()> { x: 1, _p: PhantomData }) .build() .unwrap(); let x = inject.get::().unwrap(); assert_eq!(x, 1); let y = inject.get::>(); assert_eq!(y.is_err(), true); } #[test] fn should_work_for_nested_expand() { #[derive(ComponentExpander, Clone)] struct InnerStruct { x: u32, y: u64, } #[derive(ComponentExpander, Clone)] struct Nested { #[nested_expand] x: InnerStruct, } let inject = InjectionBinder::new() .expand(Nested { x: InnerStruct { x: 1, y: 2 } }) .build() .unwrap(); let x = inject.get::().unwrap(); assert_eq!(x, 1); let y = inject.get::().unwrap(); assert_eq!(y, 2); let y = inject.get::(); assert_eq!(y.is_err(), true); } #[test] fn should_work_for_nested_expand_forced() { #[derive(ComponentExpander, Clone)] struct InnerStruct { x: u32, y: u64, } #[derive(ComponentExpander, Clone)] struct Nested { #[force_expand] #[nested_expand] x: InnerStruct, } let inject = InjectionBinder::new() .expand(Nested { x: InnerStruct { x: 1, y: 2 } }) .build() .unwrap(); let x = inject.get::().unwrap(); assert_eq!(x, 1); let x = inject.get::().unwrap(); assert_eq!(x.x, 1); assert_eq!(x.y, 2); }