public void ExecutionContextScopeDispose_TwoScopedRegistationsForTheSameServiceType_DisposesBothInstances() { // Arrange var disposedInstances = new HashSet <object>(); var lifestyle = new ExecutionContextScopeLifestyle(); var container = new Container(); var reg1 = lifestyle.CreateRegistration <ICommand, DisposableCommand>(container); var reg2 = lifestyle.CreateRegistration <ICommand, DisposableCommand>(container); container.AppendToCollection(typeof(ICommand), reg1); container.AppendToCollection(typeof(ICommand), reg2); using (container.BeginExecutionContextScope()) { var commands = container.GetAllInstances <ICommand>().Cast <DisposableCommand>().ToArray(); Assert.AreNotSame(commands[0], commands[1], "Test setup failed."); commands[0].Disposing += sender => disposedInstances.Add(sender); commands[1].Disposing += sender => disposedInstances.Add(sender); // Act } // Assert Assert.AreEqual(2, disposedInstances.Count, "Two instances were expected to be disposed."); }
public void ExecutionContextScopeDispose_WithTransientRegisteredForDisposal_DisposesThatInstance() { // Arrange DisposableCommand transientInstanceToDispose = null; var container = new Container(); var lifestyle = new ExecutionContextScopeLifestyle(); container.RegisterInitializer <DisposableCommand>(command => { lifestyle.RegisterForDisposal(container, command); }); var scope = container.BeginExecutionContextScope(); try { transientInstanceToDispose = container.GetInstance <DisposableCommand>(); } finally { // Act scope.Dispose(); } // Assert Assert.IsTrue(transientInstanceToDispose.HasBeenDisposed); }
public void ExecutionContextScopeDispose_WithWhenScopeEndsRegistration_CallsTheRegisteredAction() { // Arrange int actionCallCount = 0; var container = new Container(); var lifestyle = new ExecutionContextScopeLifestyle(); container.Register <DisposableCommand, DisposableCommand>(lifestyle); container.RegisterInitializer <DisposableCommand>(command => { lifestyle.WhenScopeEnds(container, () => { actionCallCount++; }); }); var scope = container.BeginExecutionContextScope(); try { container.GetInstance <DisposableCommand>(); } finally { // Act scope.Dispose(); } // Assert Assert.AreEqual(1, actionCallCount, "Delegate is expected to be called exactly once."); }
public void GetInstance_ResolveMultipleExecutionContextScopedServicesWithStrangeEqualsImplementations_CorrectlyDisposesAllInstances() { // Arrange var container = new Container(); var lifestyle = new ExecutionContextScopeLifestyle(); container.Register <DisposableCommandWithOverriddenEquality1>(lifestyle); container.Register <DisposableCommandWithOverriddenEquality2>(lifestyle); // Act DisposableCommandWithOverriddenEquality1 command1; DisposableCommandWithOverriddenEquality2 command2; // Act using (container.BeginExecutionContextScope()) { command1 = container.GetInstance <DisposableCommandWithOverriddenEquality1>(); command2 = container.GetInstance <DisposableCommandWithOverriddenEquality2>(); // Give both instances the same hash code. Both have an equals implementation that compared // using the hash code, which make them look like they're the same instance. command1.HashCode = 1; command2.HashCode = 1; } // Assert string assertMessage = "Dispose is expected to be called on this command, even when it contains a GetHashCode and " + "Equals implementation that is totally screwed up, since storing disposable objects, " + "should be completely independant to this implementation. "; Assert.AreEqual(1, command1.DisposeCount, assertMessage + "command1"); Assert.AreEqual(1, command2.DisposeCount, assertMessage + "command2"); }
public void WhenScopeEnds_WithMultipleDisposableComponentsAndPropertyDependencyDependingOnEachOther_DependsComponentsInExpectedOrder() { // Arrange var expectedOrderOfDisposal = new List <Type> { typeof(Middle), typeof(Inner), typeof(PropertyDependency), }; var actualOrderOfDisposal = new List <Type>(); var container = new Container(); // Allow PropertyDependency to be injected as property on Inner container.Options.PropertySelectionBehavior = new InjectProperties <ImportAttribute>(); // PropertyDependency, Middle and Inner all depend on Func<object> and call it when disposed. // This way we can check in which order the instances are disposed. container.RegisterSingleton <Action <object> >(instance => actualOrderOfDisposal.Add(instance.GetType())); // Middle depends on Inner that depends on property PropertyDependency. // Registration is deliberately made in a different order to prevent that the order of // registration might influence the order of disposing. var lifestyle = new ExecutionContextScopeLifestyle(); container.Register <PropertyDependency>(lifestyle); container.Register <Middle>(lifestyle); container.Register <Inner>(lifestyle); // Act var scope = container.BeginExecutionContextScope(); try { // Resolve the outer most object. container.GetInstance <Middle>(); } finally { // Act scope.Dispose(); } // Assert Assert.IsTrue( expectedOrderOfDisposal.SequenceEqual(actualOrderOfDisposal), "Types were expected to be disposed in the following order: {0}, " + "but they actually were disposed in the order: {1}. " + "Since PropertyDependency is injected as property into Inner, it is important that " + "PropertyDependency is disposed after Inner.", string.Join(", ", expectedOrderOfDisposal.Select(type => type.Name)), string.Join(", ", actualOrderOfDisposal.Select(type => type.Name))); }
public void WhenScopeEnds_NullActionArgument_ThrowsException() { // Arrange Action invalidArgument = null; var lifestyle = new ExecutionContextScopeLifestyle(); // Act Action action = () => lifestyle.WhenScopeEnds(new Container(), invalidArgument); // Assert AssertThat.Throws <ArgumentNullException>(action); }
public void WhenScopeEnds_WithMultipleDisposableComponentsDependingOnEachOther_DependsComponentsInExpectedOrder() { // Arrange var expectedOrderOfDisposal = new List <Type> { typeof(Outer), typeof(Middle), typeof(Inner), }; var actualOrderOfDisposal = new List <Type>(); var container = new Container(); // Outer, Middle and Inner all depend on Func<object> and call it when disposed. // This way we can check in which order the instances are disposed. container.RegisterSingleton <Action <object> >(instance => actualOrderOfDisposal.Add(instance.GetType())); // Outer depends on Middle that depends on Inner. // Registration is deliberately made in a different order to prevent that the order of // registration might influence the order of disposing. var lifestyle = new ExecutionContextScopeLifestyle(); container.Register <Middle>(lifestyle); container.Register <Inner>(lifestyle); container.Register <Outer>(lifestyle); var scope = container.BeginExecutionContextScope(); try { // Resolve the outer most object. container.GetInstance <Outer>(); } finally { // Act scope.Dispose(); } // Assert Assert.IsTrue( expectedOrderOfDisposal.SequenceEqual(actualOrderOfDisposal), "Types were expected to be disposed in the following order: {0}, " + "but they actually were disposed in the order: {1}. " + "This order is important, because when a components gets disposed, it might still want to " + "call the components it depends on, but at that time those components are already disposed.", string.Join(", ", expectedOrderOfDisposal.Select(type => type.Name)), string.Join(", ", actualOrderOfDisposal.Select(type => type.Name))); }
public void ContainerVerify_WithWhenScopeEndsRegistration_Succeeds() { // Arrange var container = new Container(); var lifestyle = new ExecutionContextScopeLifestyle(); container.Register <ICommand, DisposableCommand>(lifestyle); container.RegisterInitializer <DisposableCommand>(command => { lifestyle.WhenScopeEnds(container, () => { }); }); // Act container.Verify(); }
public void ExecutionContextScope_TwoScopedRegistationsForTheSameServiceType_CreatesTwoInstances() { // Arrange var lifestyle = new ExecutionContextScopeLifestyle(); var container = new Container(); var reg1 = lifestyle.CreateRegistration <ICommand, DisposableCommand>(container); var reg2 = lifestyle.CreateRegistration <ICommand, DisposableCommand>(container); container.AppendToCollection(typeof(ICommand), reg1); container.AppendToCollection(typeof(ICommand), reg2); using (container.BeginExecutionContextScope()) { // Act var commands = container.GetAllInstances <ICommand>().Cast <DisposableCommand>().ToArray(); // Assert Assert.AreNotSame(commands[0], commands[1], "Two instances were expected."); } }
public void ExecutionContextScopeDispose_WithWhenScopeEndsRegistration_CallsTheRegisteredActionBeforeCallingDispose() { // Arrange bool delegateHasBeenCalled = false; DisposableCommand instanceToDispose = null; var container = new Container(); var lifestyle = new ExecutionContextScopeLifestyle(); container.Register <DisposableCommand, DisposableCommand>(lifestyle); container.RegisterInitializer <DisposableCommand>(command => { lifestyle.WhenScopeEnds(container, () => { Assert.IsFalse(command.HasBeenDisposed, "The action should be called before disposing the instance, because users are " + "to use those instances."); delegateHasBeenCalled = true; }); }); var scope = container.BeginExecutionContextScope(); try { instanceToDispose = container.GetInstance <DisposableCommand>(); } finally { // Act scope.Dispose(); } // Assert Assert.IsTrue(delegateHasBeenCalled, "Delegate is expected to be called."); }
public void WhenScopeEnds_CalledOutOfTheContextOfAExecutionContextScope_ThrowsException() { // Arrange var lifestyle = new ExecutionContextScopeLifestyle(); var container = new Container(); container.Register <ConcreteCommand>(new ExecutionContextScopeLifestyle()); try { // Act lifestyle.WhenScopeEnds(container, () => { }); // Assert Assert.Fail("Exception expected."); } catch (InvalidOperationException ex) { Assert.IsTrue(ex.Message.Contains( "This method can only be called within the context of an active Execution Context Scope."), "Actual: " + ex.Message); } }