From 63cd706c0e8548a2d0d60b4b796a5d42cf8457f3 Mon Sep 17 00:00:00 2001 From: Steven Ryland Date: Mon, 3 Feb 2025 06:35:45 -0700 Subject: [PATCH] Update behavior of `ObjectContainer.IsRegistered()` to check base container for registrations (#367) * Adding IsRegisteredAtAnyLevel() to ObjectContainer * Update CHANGELOG * Update registration method summaries in IObjectContainer * PR feedback: Change behavior of IsRegistered() * Update changelog --------- Co-authored-by: Steven Ryland --- CHANGELOG.md | 1 + Reqnroll/BoDi/IObjectContainer.cs | 6 +- Reqnroll/BoDi/ObjectContainer.cs | 15 +++- .../BoDi/IsRegisteredTests.cs | 74 +++++++++++++++++++ 4 files changed, 92 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbe01042c..bfa272675 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Improve code-behind feature file compilation speed (#336) * Improve parameter type naming for generic types (#343) * Reduced MsBuild log output and consistent use of [Reqnroll] prefix (#381) +* Update behavior of `ObjectContainer.IsRegistered()` to check base container for registrations, to match `Resolve()` behavior (#367) ## Bug fixes: * MsTest: Only use TestContext for output and not Console.WriteLine (#368) diff --git a/Reqnroll/BoDi/IObjectContainer.cs b/Reqnroll/BoDi/IObjectContainer.cs index 578ea2cf1..a9651afc0 100644 --- a/Reqnroll/BoDi/IObjectContainer.cs +++ b/Reqnroll/BoDi/IObjectContainer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; namespace Reqnroll.BoDi; @@ -109,7 +109,7 @@ public interface IObjectContainer : IDisposable IEnumerable ResolveAll() where T : class; /// - /// Determines whether the interface or type is registered optionally with the specified name. + /// Determines whether the interface or type is registered in the container, optionally with the specified name. /// /// The interface or type. /// The name or null. @@ -117,7 +117,7 @@ public interface IObjectContainer : IDisposable bool IsRegistered(string name = null); /// - /// Determines whether the interface or type is registered with the specified name. + /// Determines whether the interface or type is registered in the container, optionally with the specified name. /// /// The interface or type. /// The name. diff --git a/Reqnroll/BoDi/ObjectContainer.cs b/Reqnroll/BoDi/ObjectContainer.cs index 4b14d39b8..2db9a25f0 100644 --- a/Reqnroll/BoDi/ObjectContainer.cs +++ b/Reqnroll/BoDi/ObjectContainer.cs @@ -487,13 +487,26 @@ public IStrategyRegistration RegisterFactoryAs(Delegate factoryDelegate, Type in return factoryRegistration; } + /// public bool IsRegistered(string name = null) => IsRegistered(typeof(T), name); + /// public bool IsRegistered(Type type, string name = null) { var keyToResolve = new RegistrationKey(type, name); - return _registrations.ContainsKey(keyToResolve); + if (_registrations.ContainsKey(keyToResolve)) + { + return true; + } + else if (BaseContainer != null) + { + // Recursively check the base container + return BaseContainer.IsRegistered(type, name); + } + + // We are at the top of the container hierarchy and the registration is not found + return false; } // ReSharper disable once UnusedParameter.Local diff --git a/Tests/Reqnroll.RuntimeTests/BoDi/IsRegisteredTests.cs b/Tests/Reqnroll.RuntimeTests/BoDi/IsRegisteredTests.cs index fab47c20e..8e83286c6 100644 --- a/Tests/Reqnroll.RuntimeTests/BoDi/IsRegisteredTests.cs +++ b/Tests/Reqnroll.RuntimeTests/BoDi/IsRegisteredTests.cs @@ -30,6 +30,18 @@ public void ShouldReturnFalseIfTypeNotRegistered() isRegistered.Should().BeFalse(); } + [Fact] + public void ShouldReturnFalseIfTypeNotRegisteredWithParent() + { + // given + var parentContainer = new ObjectContainer(); + var container = new ObjectContainer(parentContainer); + + // then + bool isRegistered = container.IsRegistered(); + isRegistered.Should().BeFalse(); + } + [Fact] public void ShouldReturnTrueIfInterfaceRegistered() { @@ -59,5 +71,67 @@ public void ShouldReturnTrueIfTypeRegistered() isRegistered.Should().BeTrue(); } + + [Fact] + public void ShouldReturnTrueIfTypeRegisteredInParent() + { + // given + var grandparentContainer = new ObjectContainer(); + var parentContainer = new ObjectContainer(grandparentContainer); + var container = new ObjectContainer(parentContainer); + + // when + parentContainer.RegisterInstanceAs(new SimpleClassWithDefaultCtor()); + + // then + bool isRegistered = container.IsRegistered(); + isRegistered.Should().BeTrue(); + + isRegistered = parentContainer.IsRegistered(); + isRegistered.Should().BeTrue(); + + isRegistered = grandparentContainer.IsRegistered(); + isRegistered.Should().BeFalse(); + } + + [Fact] + public void ShouldReturnTrueIfTypeRegisteredInGrandparent() + { + // given + var grandparentContainer = new ObjectContainer(); + var parentContainer = new ObjectContainer(grandparentContainer); + var container = new ObjectContainer(parentContainer); + + // when + grandparentContainer.RegisterInstanceAs(new SimpleClassWithDefaultCtor()); + + // then + bool isRegistered = container.IsRegistered(); + isRegistered.Should().BeTrue(); + + isRegistered = parentContainer.IsRegistered(); + isRegistered.Should().BeTrue(); + + isRegistered = grandparentContainer.IsRegistered(); + isRegistered.Should().BeTrue(); + } + + [Fact] + public void ShouldReturnTrueIfRegisteredInSelfButFalseInParent() + { + // given + var parentContainer = new ObjectContainer(); + var container = new ObjectContainer(parentContainer); + + // when + container.RegisterInstanceAs(new SimpleClassWithDefaultCtor()); + + // then + bool isRegistered = container.IsRegistered(); + isRegistered.Should().BeTrue(); + + isRegistered = parentContainer.IsRegistered(); + isRegistered.Should().BeFalse(); + } } }