aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml4
-rw-r--r--examples/prevent-circular/main.rs52
-rw-r--r--tests/prevent_circular.rs94
3 files changed, 94 insertions, 56 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 77b73c2..d33742b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -35,10 +35,6 @@ required-features = ["async", "factory"]
name = "async-factory"
required-features = ["async", "factory"]
-[[example]]
-name = "prevent-circular"
-required-features = ["prevent-circular"]
-
[dependencies]
syrette_macros = { path = "./macros", version = "0.4.2" }
linkme = "0.3.0"
diff --git a/examples/prevent-circular/main.rs b/examples/prevent-circular/main.rs
deleted file mode 100644
index c690a9c..0000000
--- a/examples/prevent-circular/main.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-//! Example demonstrating the prevention of circular dependencies.
-//!
-//! Having circular dependencies is generally bad practice and is detected by Syrette when
-//! the `prevent-circular` feature is enabled.
-#![deny(clippy::all)]
-#![deny(clippy::pedantic)]
-#![allow(clippy::disallowed_names)]
-
-use syrette::di_container::blocking::prelude::*;
-use syrette::injectable;
-use syrette::ptr::TransientPtr;
-
-struct Foo
-{
- _bar: TransientPtr<Bar>,
-}
-
-#[injectable]
-impl Foo
-{
- fn new(bar: TransientPtr<Bar>) -> Self
- {
- Self { _bar: bar }
- }
-}
-
-struct Bar
-{
- _foo: TransientPtr<Foo>,
-}
-
-#[injectable]
-impl Bar
-{
- fn new(foo: TransientPtr<Foo>) -> Self
- {
- Self { _foo: foo }
- }
-}
-
-fn main() -> Result<(), anyhow::Error>
-{
- let mut di_container = DIContainer::new();
-
- di_container.bind::<Foo>().to::<Foo>()?;
- di_container.bind::<Bar>().to::<Bar>()?;
-
- // The following won't work. Err will be returned.
- let _foo = di_container.get::<Foo>()?.transient()?;
-
- Ok(())
-}
diff --git a/tests/prevent_circular.rs b/tests/prevent_circular.rs
new file mode 100644
index 0000000..4b95dea
--- /dev/null
+++ b/tests/prevent_circular.rs
@@ -0,0 +1,94 @@
+#![deny(clippy::all, clippy::pedantic)]
+#![allow(clippy::disallowed_names)]
+
+use syrette::di_container::blocking::prelude::*;
+use syrette::errors::di_container::DIContainerError;
+use syrette::errors::injectable::InjectableError;
+use syrette::injectable;
+use syrette::ptr::TransientPtr;
+
+#[derive(Debug)]
+struct Foo
+{
+ _bar: TransientPtr<Bar>,
+}
+
+#[injectable]
+impl Foo
+{
+ fn new(bar: TransientPtr<Bar>) -> Self
+ {
+ Self { _bar: bar }
+ }
+}
+
+#[derive(Debug)]
+struct Bar
+{
+ _foo: TransientPtr<Foo>,
+}
+
+#[injectable]
+impl Bar
+{
+ fn new(foo: TransientPtr<Foo>) -> Self
+ {
+ Self { _foo: foo }
+ }
+}
+
+macro_rules! assert_match {
+ ($target: expr, $pattern: pat => $expr: expr) => {{
+ let target = $target;
+
+ // Not all pattern variables will be used here
+ #[allow(unused_variables)]
+ {
+ assert!(matches!(&target, $pattern));
+ }
+
+ match target {
+ $pattern => $expr,
+ _ => {
+ unreachable!();
+ }
+ }
+ }};
+}
+
+#[test]
+fn prevent_circular_works()
+{
+ let mut di_container = DIContainer::new();
+
+ di_container.bind::<Foo>().to::<Foo>().expect("Expected Ok");
+ di_container.bind::<Bar>().to::<Bar>().expect("Expected Ok");
+
+ let err = di_container.get::<Foo>().expect_err("Expected Err");
+
+ let container_err_a = assert_match!(
+ err,
+ DIContainerError::BindingResolveFailed {
+ reason: InjectableError::ResolveFailed { reason, affected: _ },
+ interface: _
+ } => *reason
+ );
+
+ let container_err_b = assert_match!(
+ container_err_a,
+ DIContainerError::BindingResolveFailed {
+ reason: InjectableError::ResolveFailed { reason, affected: _ },
+ interface: _
+ } => *reason
+ );
+
+ assert!(matches!(
+ container_err_b,
+ DIContainerError::BindingResolveFailed {
+ reason: InjectableError::DetectedCircular {
+ dependency_history: _
+ },
+ interface: _
+ }
+ ));
+}