context: using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Runtime.Serialization;
  using LinFu.IoC;
  using LinFu.IoC.Configuration;
  using LinFu.IoC.Interfaces;
  using LinFu.Proxy;
  using LinFu.Proxy.Interfaces;
  using Moq;
  using NUnit.Framework;
  using SampleLibrary;
  using SampleLibrary.IOC;
  using SampleLibrary.IOC.BugFixes;
  
  namespace LinFu.UnitTests.IOC
  {
      [TestFixture]
      public class InversionOfControlTests
      {
          private static void VerifyInitializeCall(ServiceContainer container, Mock<IInitialize> mockService)
          {
              container.LoadFrom(AppDomain.CurrentDomain.BaseDirectory, "*.dll");
              container.AddService(mockService.Object);
  
  
              mockService.Expect(i => i.Initialize(container)).AtMostOnce();
  
              // The container should return the same instance
              var firstResult = container.GetService<IInitialize>();
              var secondResult = container.GetService<IInitialize>();
              Assert.AreSame(firstResult, secondResult);
  
              // The Initialize() method should only be called once
              mockService.Verify();
          }
  
          [Test]
          public void AroundInvokeClassesMarkedWithInterceptorAttributeMustGetActualTargetInstance()
          {
              var container = new ServiceContainer();
              container.LoadFrom(AppDomain.CurrentDomain.BaseDirectory, "*.dll");
              var mockService = new Mock<ISampleWrappedInterface>();
              mockService.Expect(mock => mock.DoSomething());
  
              // Add the target instance
              container.AddService(mockService.Object);
  
              // The service must return a proxy
              var service = container.GetService<ISampleWrappedInterface>();
              Assert.AreNotSame(service, mockService.Object);
  
              // Execute the method and 'catch' the target instance once the method call is made
              service.DoSomething();
  
              var holder = container.GetService<ITargetHolder>("SampleAroundInvokeInterceptorClass");
              Assert.AreSame(holder.Target, mockService.Object);
          }
  
          [Test]
          public void ContainerMustAllowInjectingCustomFactoriesForNamedOpenGenericTypeDefinitions()
          {
              var container = new ServiceContainer();
              var factory = new SampleOpenGenericFactory();
              string serviceName = "MyService";
  
              container.AddFactory(serviceName, typeof (ISampleGenericService<>), factory);
  
              // The container must report that it *can* create
              // the generic service type 
              Assert.IsTrue(container.Contains(serviceName, typeof (ISampleGenericService<int>)));
  
              var result = container.GetService<ISampleGenericService<int>>(serviceName);
  
              Assert.IsNotNull(result);
              Assert.IsTrue(result.GetType() == typeof (SampleGenericImplementation<int>));
          }
  
          [Test]
          public void ContainerMustAllowInjectingCustomFactoriesForOpenGenericTypeDefinitions()
          {
              var container = new ServiceContainer();
              var factory = new SampleOpenGenericFactory();
  
              container.AddFactory(typeof (ISampleGenericService<>), factory);
  
              // The container must report that it *can* create
              // the generic service type 
              Assert.IsTrue(container.Contains(typeof (ISampleGenericService<int>)));
  
              var result = container.GetService<ISampleGenericService<int>>();
  
              Assert.IsNotNull(result);
              Assert.IsTrue(result.GetType() == typeof (SampleGenericImplementation<int>));
          }
  
          [Test]
          public void ContainerMustAllowServicesToBeIntercepted()
          {
              var container = new ServiceContainer();
              container.LoadFrom(AppDomain.CurrentDomain.BaseDirectory, "*.dll");
  
              var mock = new Mock<ISampleInterceptedInterface>();
              ISampleInterceptedInterface mockInstance = mock.Object;
              container.AddService(mockInstance);
  
              // The container must automatically load the interceptor
              // from the sample assembly
              var result = container.GetService<ISampleInterceptedInterface>();
              Assert.AreNotSame(mockInstance, result);
  
              var proxy = (IProxy) result;
              Assert.IsNotNull(proxy.Interceptor);
          }
  
          [Test]
          public void ContainerMustAllowServicesToBeInterceptedWithAnAroundInvokeInterceptor()
          {
              var container = new ServiceContainer();
              container.LoadFrom(AppDomain.CurrentDomain.BaseDirectory, "*.dll");
  
              var mock = new Mock<ISampleWrappedInterface>();
              ISampleWrappedInterface mockInstance = mock.Object;
              container.AddService(mockInstance);
  
              // The container must automatically load the IAroundInvoke
              // from the sample assembly
              var result = container.GetService<ISampleWrappedInterface>();
              Assert.AreNotSame(mockInstance, result);
  
              var proxy = (IProxy) result;
              Assert.IsNotNull(proxy.Interceptor);
          }
  
          [Test]
          public void ContainerMustAllowSurrogatesForNonExistentServiceInstances()
          {
              var container = new ServiceContainer();
              var mockService = new Mock<ISampleService>();
              ISampleService surrogate = mockService.Object;
              container.Inject<ISampleService>().Using((f, arguments) => surrogate).OncePerRequest();
  
              var result = container.GetService<ISampleService>();
              Assert.IsNotNull(result);
              Assert.AreSame(surrogate, result);
          }
  
          [Test]
          public void ContainerMustAllowUntypedOpenGenericTypeRegistration()
          {
              Type serviceType = typeof (ISampleGenericService<>);
              Type implementingType = typeof (SampleGenericImplementation<>);
  
              var container = new ServiceContainer();
              container.AddService(serviceType, implementingType);
  
              var result = container.GetService<ISampleGenericService<long>>();
              Assert.IsNotNull(result);
          }
  
          [Test]
          public void ContainerMustAllowUntypedServiceRegistration()
          {
              var container = new ServiceContainer();
              container.AddService(typeof (ISampleService), typeof (SampleClass));
  
              var service = container.GetService<ISampleService>();
              Assert.IsNotNull(service);
          }
  
          [Test]
          public void ContainerMustBeAbleToAddExistingServiceInstances()
          {
              var container = new ServiceContainer();
              var mockService = new Mock<ISerializable>();
              container.AddService(mockService.Object);
  
              var result = container.GetService<ISerializable>();
              Assert.AreSame(result, mockService.Object);
          }
  
          [Test]
          public void ContainerMustBeAbleToReturnAListOfServices()
          {
              var mockSampleService = new Mock<ISampleService>();
              var container = new ServiceContainer();
  
              // Add a bunch of dummy services
              for (int i = 0; i < 10; i++)
              {
                  string serviceName = string.Format("Service{0}", i + 1);
                  container.AddService(serviceName, mockSampleService.Object);
              }
  
              IEnumerable<ISampleService> services = container.GetServices<ISampleService>();
              Assert.IsTrue(services.Count() == 10);
  
              // The resulting set of services
              // must match the given service instance
              foreach (ISampleService service in services)
              {
                  Assert.AreSame(mockSampleService.Object, service);
              }
          }
  
          [Test]
          [ExpectedException(typeof (NamedServiceNotFoundException))]
          public void ContainerMustBeAbleToSuppressNamedServiceNotFoundErrors()
          {
              var container = new ServiceContainer();
              object instance = container.GetService("MyService", typeof (ISerializable));
              Assert.IsNull(instance, "The container is supposed to return a null instance");
          }
  
          [Test]
          public void ContainerMustBeAbleToSupressServiceNotFoundErrors()
          {
              var container = new ServiceContainer();
              container.SuppressErrors = true;
  
              object instance = container.GetService(typeof (ISerializable));
              Assert.IsNull(instance, "The container is supposed to return a null instance");
          }
  
          [Test]
          public void ContainerMustCallIInitializeOnServicesCreatedFromCustomFactory()
          {
              var mockFactory = new Mock<IFactory>();
              var mockInitialize = new Mock<IInitialize>();
  
              mockFactory.Expect(f => f.CreateInstance(It.IsAny<IFactoryRequest>()))
                  .Returns(mockInitialize.Object);
  
              // The IInitialize instance must be called once it
              // leaves the custom factory
              mockInitialize.Expect(i => i.Initialize(It.IsAny<IServiceContainer>()));
  
              var container = new ServiceContainer();
              container.LoadFrom(AppDomain.CurrentDomain.BaseDirectory, "LinFu*.dll");
              container.AddFactory(typeof (IInitialize), mockFactory.Object);
  
              var result = container.GetService<IInitialize>();
  
              mockFactory.VerifyAll();
              mockInitialize.VerifyAll();
          }
  
          [Test]
          public void ContainerMustCallPostProcessorDuringARequest()
          {
              var mockPostProcessor = new Mock<IPostProcessor>();
              var container = new ServiceContainer();
              container.PostProcessors.Add(mockPostProcessor.Object);
  
              mockPostProcessor.Expect(p =>
                                       p.PostProcess(It.Is<IServiceRequestResult>(result => result != null)));
  
              container.SuppressErrors = true;
              container.GetService<ISerializable>();
  
              mockPostProcessor.VerifyAll();
          }
  
          [Test]
          public void ContainerMustGetMultipleServicesOfTheSameTypeInOneCall()
          {
              var container = new ServiceContainer();
              int mockServiceCount = 10;
  
              // Add a set of dummy services
              for (int i = 0; i < mockServiceCount; i++)
              {
                  var mockService = new Mock<ISampleService>();
                  container.AddService(string.Format("Service{0}", i + 1), mockService.Object);
              }
  
              IEnumerable<ISampleService> instances = container.GetServices<ISampleService>();
              foreach (ISampleService serviceInstance in instances)
              {
                  Assert.IsInstanceOfType(typeof (ISampleService), serviceInstance);
                  Assert.IsNotNull(serviceInstance);
              }
          }
  
          [Test]
          public void ContainerMustGracefullyHandleRecursiveServiceDependencies()
          {
              var container = new ServiceContainer();
              container.LoadFrom(AppDomain.CurrentDomain.BaseDirectory, "LinFu*.dll");
  
              container.AddService(typeof (SampleRecursiveTestComponent1), typeof (SampleRecursiveTestComponent1));
              container.AddService(typeof (SampleRecursiveTestComponent2), typeof (SampleRecursiveTestComponent2));
  
              try
              {
                  var result = container.GetService<SampleRecursiveTestComponent1>();
              }
              catch (Exception ex)
              {
                  Assert.IsNotInstanceOfType(typeof (StackOverflowException), ex);
              }
          }
  
          [Test]
          public void ContainerMustHoldAnonymousFactoryInstance()
          {
              var mockFactory = new Mock<IFactory>();
              var container = new ServiceContainer();
  
              // Give it a random service interface type
              Type serviceType = typeof (IDisposable);
  
              // Manually add the factory instance
              container.AddFactory(serviceType, mockFactory.Object);
              Assert.IsTrue(container.Contains(serviceType),
                            "The container needs to have a factory for service type '{0}'", serviceType);
          }
  
          [Test]
          public void ContainerMustHoldNamedFactoryInstance()
          {
              var mockFactory = new Mock<IFactory>();
              var container = new ServiceContainer();
  
              // Randomly assign an interface type
              // NOTE: The actual interface type doesn't matter
              Type serviceType = typeof (ISerializable);
  
              container.AddFactory("MyService", serviceType, mockFactory.Object);
              Assert.IsTrue(container.Contains("MyService", serviceType),
                            "The container is supposed to contain a service named 'MyService'");
  
              var instance = new object();
              mockFactory.Expect(f => f.CreateInstance(
                  It.Is<IFactoryRequest>(
                      request => request.ServiceName == "MyService" && request.ServiceType == serviceType)))
                  .Returns(instance);
  
              Assert.AreSame(instance, container.GetService("MyService", serviceType));
          }
  
          [Test]
          public void ContainerMustInjectFactoryInstances()
          {
  
gt:             var mockFactory = new Mock<IFactory<ISampleService>>();