diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs new file mode 100644 index 00000000000000..d653a671f1ce91 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs @@ -0,0 +1,399 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection.Specification.Fakes; +using Xunit; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public abstract partial class DependencyInjectionSpecificationTests + { + public delegate object CreateInstanceFunc(IServiceProvider provider, Type type, object[] args); + + private static object CreateInstanceDirectly(IServiceProvider provider, Type type, object[] args) + { + return ActivatorUtilities.CreateInstance(provider, type, args); + } + + private static object CreateInstanceFromFactory(IServiceProvider provider, Type type, object[] args) + { + var factory = ActivatorUtilities.CreateFactory(type, args.Select(a => a.GetType()).ToArray()); + return factory(provider, args); + } + + private static T CreateInstance(CreateInstanceFunc func, IServiceProvider provider, params object[] args) + { + return (T)func(provider, typeof(T), args); + } + + public static IEnumerable CreateInstanceFuncs + { + get + { + yield return new[] { (CreateInstanceFunc)CreateInstanceDirectly }; + yield return new[] { (CreateInstanceFunc)CreateInstanceFromFactory }; + } + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorEnablesYouToCreateAnyTypeWithServicesEvenWhenNotInIocContainer(CreateInstanceFunc createFunc) + { + // Arrange + var serviceCollection = new TestServiceCollection() + .AddTransient(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + var anotherClass = CreateInstance(createFunc, serviceProvider); + + Assert.NotNull(anotherClass.FakeService); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorAcceptsAnyNumberOfAdditionalConstructorParametersToProvide(CreateInstanceFunc createFunc) + { + // Arrange + var serviceCollection = new TestServiceCollection() + .AddTransient(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + // Act + var anotherClass = CreateInstance(createFunc, serviceProvider, "1", "2"); + + // Assert + Assert.NotNull(anotherClass.FakeService); + Assert.Equal("1", anotherClass.One); + Assert.Equal("2", anotherClass.Two); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorWorksWithStaticCtor(CreateInstanceFunc createFunc) + { + // Act + var anotherClass = CreateInstance(createFunc, provider: null); + + // Assert + Assert.NotNull(anotherClass); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorWorksWithCtorWithOptionalArgs(CreateInstanceFunc createFunc) + { + // Arrange + var provider = new TestServiceCollection(); + var serviceProvider = CreateServiceProvider(provider); + + // Act + var anotherClass = CreateInstance(createFunc, serviceProvider); + + // Assert + Assert.NotNull(anotherClass); + Assert.Equal("BLARGH", anotherClass.Whatever); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorWorksWithCtorWithOptionalArgs_WithStructDefaults(CreateInstanceFunc createFunc) + { + // Arrange + var provider = new TestServiceCollection(); + var serviceProvider = CreateServiceProvider(provider); + + // Act + var anotherClass = CreateInstance(createFunc, serviceProvider); + + // Assert + Assert.NotNull(anotherClass); + Assert.Equal(ConsoleColor.DarkGreen, anotherClass.Color); + Assert.Null(anotherClass.ColorNull); + Assert.Equal(12, anotherClass.Integer); + Assert.Null(anotherClass.IntegerNull); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorCanDisambiguateConstructorsWithUniqueArguments(CreateInstanceFunc createFunc) + { + // Arrange + var serviceCollection = new TestServiceCollection() + .AddTransient(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + // Act + var instance = CreateInstance(createFunc, serviceProvider, "1", 2); + + // Assert + Assert.NotNull(instance); + Assert.NotNull(instance.FakeService); + Assert.Equal("1", instance.Data1); + Assert.Equal(2, instance.Data2); + } + + public static IEnumerable TypesWithNonPublicConstructorData => + CreateInstanceFuncs.Zip( + new[] { typeof(ClassWithPrivateCtor), typeof(ClassWithInternalConstructor), typeof(ClassWithProtectedConstructor) }, + (a, b) => new object[] { a[0], b }); + + [Theory] + [MemberData(nameof(TypesWithNonPublicConstructorData))] + public void TypeActivatorRequiresPublicConstructor(CreateInstanceFunc createFunc, Type type) + { + // Arrange + var expectedMessage = $"A suitable constructor for type '{type}' could not be located. " + + "Ensure the type is concrete and services are registered for all parameters of a public constructor."; + + // Act and Assert + var ex = Assert.Throws(() => + createFunc(provider: null, type: type, args: new object[0])); + + Assert.Equal(expectedMessage, ex.Message); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorRequiresAllArgumentsCanBeAccepted(CreateInstanceFunc createFunc) + { + // Arrange + var expectedMessage = $"A suitable constructor for type '{typeof(AnotherClassAcceptingData).FullName}' could not be located. " + + "Ensure the type is concrete and services are registered for all parameters of a public constructor."; + var serviceCollection = new TestServiceCollection() + .AddTransient(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + var ex1 = Assert.Throws(() => + CreateInstance(createFunc, serviceProvider, "1", "2", "3")); + var ex2 = Assert.Throws(() => + CreateInstance(createFunc, serviceProvider, 1, 2)); + + Assert.Equal(expectedMessage, ex1.Message); + Assert.Equal(expectedMessage, ex2.Message); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorRethrowsOriginalExceptionFromConstructor(CreateInstanceFunc createFunc) + { + // Act + var ex1 = Assert.Throws(() => + CreateInstance(createFunc, provider: null)); + + var ex2 = Assert.Throws(() => + CreateInstance(createFunc, provider: null, args: new[] { new FakeService() })); + + // Assert + Assert.Equal(nameof(ClassWithThrowingEmptyCtor), ex1.Message); + Assert.Equal(nameof(ClassWithThrowingCtor), ex2.Message); + } + + [Theory] + [InlineData(typeof(string))] + [InlineData(typeof(int))] + public void TypeActivatorCreateFactoryDoesNotAllowForAmbiguousConstructorMatches(Type paramType) + { + // Arrange + var type = typeof(ClassWithAmbiguousCtors); + var expectedMessage = $"Multiple constructors accepting all given argument types have been found in type '{type}'. " + + "There should only be one applicable constructor."; + + // Act + var ex = Assert.Throws(() => + ActivatorUtilities.CreateFactory(type, new[] { paramType })); + + // Assert + Assert.Equal(expectedMessage, ex.Message); + } + + [Theory] + [InlineData("", "string")] + [InlineData(5, "IFakeService, int")] + public void TypeActivatorCreateInstanceUsesFirstMathchedConstructor(object value, string ctor) + { + // Arrange + var serviceCollection = new TestServiceCollection(); + serviceCollection.AddSingleton(); + var serviceProvider = CreateServiceProvider(serviceCollection); + var type = typeof(ClassWithAmbiguousCtors); + + // Act + var instance = ActivatorUtilities.CreateInstance(serviceProvider, type, value); + + // Assert + Assert.Equal(ctor, ((ClassWithAmbiguousCtors)instance).CtorUsed); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorUsesMarkedConstructor(CreateInstanceFunc createFunc) + { + // Arrange + var serviceCollection = new TestServiceCollection(); + serviceCollection.AddSingleton(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + // Act + var instance = CreateInstance(createFunc, serviceProvider, "hello"); + + // Assert + Assert.Equal("IFakeService, string", instance.CtorUsed); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorThrowsOnMultipleMarkedCtors(CreateInstanceFunc createFunc) + { + // Act + var exception = Assert.Throws(() => CreateInstance(createFunc, null, "hello")); + + // Assert + Assert.Equal("Multiple constructors were marked with ActivatorUtilitiesConstructorAttribute.", exception.Message); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorThrowsWhenMarkedCtorDoesntAcceptArguments(CreateInstanceFunc createFunc) + { + // Act + var exception = Assert.Throws(() => CreateInstance(createFunc, null, 0, "hello")); + + // Assert + Assert.Equal("Constructor marked with ActivatorUtilitiesConstructorAttribute does not accept all given argument types.", exception.Message); + } + + [Fact] + public void GetServiceOrCreateInstanceRegisteredServiceTransient() + { + // Reset the count because test order is not guaranteed + lock (CreationCountFakeService.InstanceLock) + { + CreationCountFakeService.InstanceCount = 0; + + var serviceCollection = new TestServiceCollection() + .AddTransient() + .AddTransient(); + + var serviceProvider = CreateServiceProvider(serviceCollection); + + var service = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider); + Assert.NotNull(service); + Assert.Equal(1, service.InstanceId); + Assert.Equal(1, CreationCountFakeService.InstanceCount); + + service = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider); + Assert.NotNull(service); + Assert.Equal(2, service.InstanceId); + Assert.Equal(2, CreationCountFakeService.InstanceCount); + } + } + + [Fact] + public void GetServiceOrCreateInstanceRegisteredServiceSingleton() + { + lock (CreationCountFakeService.InstanceLock) + { + // Arrange + // Reset the count because test order is not guaranteed + CreationCountFakeService.InstanceCount = 0; + + var serviceCollection = new TestServiceCollection() + .AddTransient() + .AddSingleton(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + // Act and Assert + var service = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider); + Assert.NotNull(service); + Assert.Equal(1, service.InstanceId); + Assert.Equal(1, CreationCountFakeService.InstanceCount); + + service = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider); + Assert.NotNull(service); + Assert.Equal(1, service.InstanceId); + Assert.Equal(1, CreationCountFakeService.InstanceCount); + } + } + + [Fact] + public void GetServiceOrCreateInstanceUnregisteredService() + { + lock (CreationCountFakeService.InstanceLock) + { + // Arrange + // Reset the count because test order is not guaranteed + CreationCountFakeService.InstanceCount = 0; + + var serviceCollection = new TestServiceCollection() + .AddTransient(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + // Act and Assert + var service = (CreationCountFakeService)ActivatorUtilities.GetServiceOrCreateInstance( + serviceProvider, + typeof(CreationCountFakeService)); + Assert.NotNull(service); + Assert.Equal(1, service.InstanceId); + Assert.Equal(1, CreationCountFakeService.InstanceCount); + + service = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider); + Assert.NotNull(service); + Assert.Equal(2, service.InstanceId); + Assert.Equal(2, CreationCountFakeService.InstanceCount); + } + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void UnRegisteredServiceAsConstructorParameterThrowsException(CreateInstanceFunc createFunc) + { + var serviceCollection = new TestServiceCollection() + .AddSingleton(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + var ex = Assert.Throws(() => + CreateInstance(createFunc, serviceProvider)); + Assert.Equal($"Unable to resolve service for type '{typeof(IFakeService)}' while attempting" + + $" to activate '{typeof(CreationCountFakeService)}'.", + ex.Message); + } + + [Fact] + public void CreateInstance_WithAbstractTypeAndPublicConstructor_ThrowsCorrectException() + { + // Act & Assert + var ex = Assert.Throws(() => ActivatorUtilities.CreateInstance(default(IServiceProvider), typeof(AbstractFoo))); + var msg = "A suitable constructor for type 'Microsoft.Extensions.DependencyInjection.Specification.DependencyInjectionSpecificationTests+AbstractFoo' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor."; + Assert.Equal(msg, ex.Message); + } + + [Fact] + public void CreateInstance_CapturesInnerException_OfTargetInvocationException() + { + // Act & Assert + var ex = Assert.Throws(() => ActivatorUtilities.CreateInstance(default(IServiceProvider), typeof(Bar))); + var msg = "some error"; + Assert.Equal(msg, ex.Message); + } + + abstract class AbstractFoo + { + // The constructor should be public, since that is checked as well. + public AbstractFoo() + { + } + } + + class Bar + { + public Bar() + { + throw new InvalidOperationException("some error"); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs new file mode 100644 index 00000000000000..beed0c8661e4b8 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs @@ -0,0 +1,779 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection.Specification.Fakes; +using Xunit; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public abstract partial class DependencyInjectionSpecificationTests + { + protected abstract IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection); + + [Fact] + public void ServicesRegisteredWithImplementationTypeCanBeResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeService), typeof(FakeService)); + var provider = CreateServiceProvider(collection); + + // Act + var service = provider.GetService(); + + // Assert + Assert.NotNull(service); + Assert.IsType(service); + } + + [Fact] + public void ServicesRegisteredWithImplementationType_ReturnDifferentInstancesPerResolution_ForTransientServices() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeService), typeof(FakeService)); + var provider = CreateServiceProvider(collection); + + // Act + var service1 = provider.GetService(); + var service2 = provider.GetService(); + + // Assert + Assert.IsType(service1); + Assert.IsType(service2); + Assert.NotSame(service1, service2); + } + + [Fact] + public void ServicesRegisteredWithImplementationType_ReturnSameInstancesPerResolution_ForSingletons() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddSingleton(typeof(IFakeService), typeof(FakeService)); + var provider = CreateServiceProvider(collection); + + // Act + var service1 = provider.GetService(); + var service2 = provider.GetService(); + + // Assert + Assert.IsType(service1); + Assert.IsType(service2); + Assert.Same(service1, service2); + } + + [Fact] + public void ServiceInstanceCanBeResolved() + { + // Arrange + var collection = new TestServiceCollection(); + var instance = new FakeService(); + collection.AddSingleton(typeof(IFakeServiceInstance), instance); + var provider = CreateServiceProvider(collection); + + // Act + var service = provider.GetService(); + + // Assert + Assert.Same(instance, service); + } + + [Fact] + public void TransientServiceCanBeResolvedFromProvider() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeService), typeof(FakeService)); + var provider = CreateServiceProvider(collection); + + // Act + var service1 = provider.GetService(); + var service2 = provider.GetService(); + + // Assert + Assert.NotNull(service1); + Assert.NotSame(service1, service2); + } + + [Fact] + public void TransientServiceCanBeResolvedFromScope() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeService), typeof(FakeService)); + var provider = CreateServiceProvider(collection); + + // Act + var service1 = provider.GetService(); + + using (var scope = provider.CreateScope()) + { + var scopedService1 = scope.ServiceProvider.GetService(); + var scopedService2 = scope.ServiceProvider.GetService(); + + // Assert + Assert.NotSame(service1, scopedService1); + Assert.NotSame(service1, scopedService2); + Assert.NotSame(scopedService1, scopedService2); + } + } + + [Fact] + public void SingletonServiceCanBeResolvedFromScope() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddSingleton(); + var provider = CreateServiceProvider(collection); + + // Act + IServiceProvider scopedSp1 = null; + IServiceProvider scopedSp2 = null; + ClassWithServiceProvider instance1 = null; + ClassWithServiceProvider instance2 = null; + + using (var scope1 = provider.CreateScope()) + { + scopedSp1 = scope1.ServiceProvider; + instance1 = scope1.ServiceProvider.GetRequiredService(); + } + + using (var scope2 = provider.CreateScope()) + { + scopedSp2 = scope2.ServiceProvider; + instance2 = scope2.ServiceProvider.GetRequiredService(); + } + + // Assert + Assert.Same(instance1.ServiceProvider, instance2.ServiceProvider); + Assert.NotSame(instance1.ServiceProvider, scopedSp1); + Assert.NotSame(instance2.ServiceProvider, scopedSp2); + } + + [Fact] + public void SingleServiceCanBeIEnumerableResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeService), typeof(FakeService)); + var provider = CreateServiceProvider(collection); + + // Act + var services = provider.GetService>(); + + // Assert + Assert.NotNull(services); + var service = Assert.Single(services); + Assert.IsType(service); + } + + [Fact] + public void MultipleServiceCanBeIEnumerableResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeMultipleService), typeof(FakeOneMultipleService)); + collection.AddTransient(typeof(IFakeMultipleService), typeof(FakeTwoMultipleService)); + var provider = CreateServiceProvider(collection); + + // Act + var services = provider.GetService>(); + + // Assert + Assert.Collection(services.OrderBy(s => s.GetType().FullName), + service => Assert.IsType(service), + service => Assert.IsType(service)); + } + + [Fact] + public void RegistrationOrderIsPreservedWhenServicesAreIEnumerableResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeMultipleService), typeof(FakeOneMultipleService)); + collection.AddTransient(typeof(IFakeMultipleService), typeof(FakeTwoMultipleService)); + + var provider = CreateServiceProvider(collection); + + collection.Reverse(); + var providerReversed = CreateServiceProvider(collection); + + // Act + var services = provider.GetService>(); + var servicesReversed = providerReversed.GetService>(); + + // Assert + Assert.Collection(services, + service => Assert.IsType(service), + service => Assert.IsType(service)); + + Assert.Collection(servicesReversed, + service => Assert.IsType(service), + service => Assert.IsType(service)); + } + + [Fact] + public void OuterServiceCanHaveOtherServicesInjected() + { + // Arrange + var collection = new TestServiceCollection(); + var fakeService = new FakeService(); + collection.AddTransient(); + collection.AddSingleton(fakeService); + collection.AddTransient(); + collection.AddTransient(); + var provider = CreateServiceProvider(collection); + + // Act + var services = provider.GetService(); + + // Assert + Assert.Same(fakeService, services.SingleService); + Assert.Collection(services.MultipleServices.OrderBy(s => s.GetType().FullName), + service => Assert.IsType(service), + service => Assert.IsType(service)); + } + + [Fact] + public void FactoryServicesCanBeCreatedByGetService() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(); + collection.AddTransient(p => + { + var fakeService = p.GetRequiredService(); + return new TransientFactoryService + { + FakeService = fakeService, + Value = 42 + }; + }); + var provider = CreateServiceProvider(collection); + + // Act + var service = provider.GetService(); + + // Assert + Assert.NotNull(service); + Assert.Equal(42, service.Value); + Assert.NotNull(service.FakeService); + Assert.IsType(service.FakeService); + } + + [Fact] + public void FactoryServicesAreCreatedAsPartOfCreatingObjectGraph() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(); + collection.AddTransient(p => + { + var fakeService = p.GetService(); + return new TransientFactoryService + { + FakeService = fakeService, + Value = 42 + }; + }); + collection.AddScoped(p => + { + var fakeService = p.GetService(); + return new ScopedFactoryService + { + FakeService = fakeService, + }; + }); + collection.AddTransient(); + var provider = CreateServiceProvider(collection); + + // Act + var service1 = provider.GetService(); + var service2 = provider.GetService(); + + // Assert + Assert.Equal(42, service1.TransientService.Value); + Assert.NotNull(service1.TransientService.FakeService); + + Assert.Equal(42, service2.TransientService.Value); + Assert.NotNull(service2.TransientService.FakeService); + + Assert.NotNull(service1.ScopedService.FakeService); + + // Verify scoping works + Assert.NotSame(service1.TransientService, service2.TransientService); + Assert.Same(service1.ScopedService, service2.ScopedService); + } + + [Fact] + public void LastServiceReplacesPreviousServices() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(); + collection.AddTransient(); + var provider = CreateServiceProvider(collection); + + // Act + var service = provider.GetService(); + + // Assert + Assert.IsType(service); + } + + [Fact] + public void SingletonServiceCanBeResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddSingleton(); + var provider = CreateServiceProvider(collection); + + // Act + var service1 = provider.GetService(); + var service2 = provider.GetService(); + + // Assert + Assert.NotNull(service1); + Assert.Same(service1, service2); + } + + [Fact] + public void ServiceProviderRegistersServiceScopeFactory() + { + // Arrange + var collection = new TestServiceCollection(); + var provider = CreateServiceProvider(collection); + + // Act + var scopeFactory = provider.GetService(); + + // Assert + Assert.NotNull(scopeFactory); + } + + [Fact] + public void ScopedServiceCanBeResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddScoped(); + var provider = CreateServiceProvider(collection); + + // Act + using (var scope = provider.CreateScope()) + { + var providerScopedService = provider.GetService(); + var scopedService1 = scope.ServiceProvider.GetService(); + var scopedService2 = scope.ServiceProvider.GetService(); + + // Assert + Assert.NotSame(providerScopedService, scopedService1); + Assert.Same(scopedService1, scopedService2); + } + } + + [Fact] + public void NestedScopedServiceCanBeResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddScoped(); + var provider = CreateServiceProvider(collection); + + // Act + using (var outerScope = provider.CreateScope()) + using (var innerScope = outerScope.ServiceProvider.CreateScope()) + { + var outerScopedService = outerScope.ServiceProvider.GetService(); + var innerScopedService = innerScope.ServiceProvider.GetService(); + + // Assert + Assert.NotNull(outerScopedService); + Assert.NotNull(innerScopedService); + Assert.NotSame(outerScopedService, innerScopedService); + } + } + + [Fact] + public void ScopedServices_FromCachedScopeFactory_CanBeResolvedAndDisposed() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddScoped(); + var provider = CreateServiceProvider(collection); + var cachedScopeFactory = provider.GetService(); + + // Act + for (var i = 0; i < 3; i++) + { + FakeService outerScopedService; + using (var outerScope = cachedScopeFactory.CreateScope()) + { + FakeService innerScopedService; + using (var innerScope = outerScope.ServiceProvider.CreateScope()) + { + outerScopedService = outerScope.ServiceProvider.GetService() as FakeService; + innerScopedService = innerScope.ServiceProvider.GetService() as FakeService; + + // Assert + Assert.NotNull(outerScopedService); + Assert.NotNull(innerScopedService); + Assert.NotSame(outerScopedService, innerScopedService); + } + + Assert.False(outerScopedService.Disposed); + Assert.True(innerScopedService.Disposed); + } + + Assert.True(outerScopedService.Disposed); + } + } + + [Fact] + public void DisposingScopeDisposesService() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddSingleton(); + collection.AddScoped(); + collection.AddTransient(); + + var provider = CreateServiceProvider(collection); + FakeService disposableService; + FakeService transient1; + FakeService transient2; + FakeService singleton; + + // Act and Assert + var transient3 = Assert.IsType(provider.GetService()); + using (var scope = provider.CreateScope()) + { + disposableService = (FakeService)scope.ServiceProvider.GetService(); + transient1 = (FakeService)scope.ServiceProvider.GetService(); + transient2 = (FakeService)scope.ServiceProvider.GetService(); + singleton = (FakeService)scope.ServiceProvider.GetService(); + + Assert.False(disposableService.Disposed); + Assert.False(transient1.Disposed); + Assert.False(transient2.Disposed); + Assert.False(singleton.Disposed); + } + + Assert.True(disposableService.Disposed); + Assert.True(transient1.Disposed); + Assert.True(transient2.Disposed); + Assert.False(singleton.Disposed); + + var disposableProvider = provider as IDisposable; + if (disposableProvider != null) + { + disposableProvider.Dispose(); + Assert.True(singleton.Disposed); + Assert.True(transient3.Disposed); + } + } + + [Fact] + public void SelfResolveThenDispose() + { + // Arrange + var collection = new TestServiceCollection(); + var provider = CreateServiceProvider(collection); + + // Act + var serviceProvider = provider.GetService(); + + // Assert + Assert.NotNull(serviceProvider); + (provider as IDisposable)?.Dispose(); + } + + [Fact] + public void SafelyDisposeNestedProviderReferences() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(); + var provider = CreateServiceProvider(collection); + + // Act + var nester = provider.GetService(); + + // Assert + Assert.NotNull(nester); + nester.Dispose(); + } + + [Fact] + public void SingletonServicesComeFromRootProvider() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddSingleton(); + var provider = CreateServiceProvider(collection); + FakeService disposableService1; + FakeService disposableService2; + + // Act and Assert + using (var scope = provider.CreateScope()) + { + var service = scope.ServiceProvider.GetService(); + disposableService1 = Assert.IsType(service); + Assert.False(disposableService1.Disposed); + } + + Assert.False(disposableService1.Disposed); + + using (var scope = provider.CreateScope()) + { + var service = scope.ServiceProvider.GetService(); + disposableService2 = Assert.IsType(service); + Assert.False(disposableService2.Disposed); + } + + Assert.False(disposableService2.Disposed); + Assert.Same(disposableService1, disposableService2); + } + + [Fact] + public void NestedScopedServiceCanBeResolvedWithNoFallbackProvider() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddScoped(); + var provider = CreateServiceProvider(collection); + + // Act + using (var outerScope = provider.CreateScope()) + using (var innerScope = outerScope.ServiceProvider.CreateScope()) + { + var outerScopedService = outerScope.ServiceProvider.GetService(); + var innerScopedService = innerScope.ServiceProvider.GetService(); + + // Assert + Assert.NotSame(outerScopedService, innerScopedService); + } + } + + [Fact] + public void OpenGenericServicesCanBeResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>)); + collection.AddSingleton(); + var provider = CreateServiceProvider(collection); + + // Act + var genericService = provider.GetService>(); + var singletonService = provider.GetService(); + + // Assert + Assert.Same(singletonService, genericService.Value); + } + + [Fact] + public void ClosedServicesPreferredOverOpenGenericServices() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeOpenGenericService), typeof(FakeService)); + collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>)); + collection.AddSingleton(); + var provider = CreateServiceProvider(collection); + + // Act + var service = provider.GetService>(); + + // Assert + Assert.IsType(service); + } + + [Fact] + public void AttemptingToResolveNonexistentServiceReturnsNull() + { + // Arrange + var collection = new TestServiceCollection(); + var provider = CreateServiceProvider(collection); + + // Act + var service = provider.GetService(); + + // Assert + Assert.Null(service); + } + + [Fact] + public void NonexistentServiceCanBeIEnumerableResolved() + { + // Arrange + var collection = new TestServiceCollection(); + var provider = CreateServiceProvider(collection); + + // Act + var services = provider.GetService>(); + + // Assert + Assert.Empty(services); + } + + public static TheoryData ServiceContainerPicksConstructorWithLongestMatchesData + { + get + { + var fakeService = new FakeService(); + var multipleService = new FakeService(); + var factoryService = new TransientFactoryService(); + var scopedService = new FakeService(); + + return new TheoryData + { + { + new TestServiceCollection() + .AddSingleton(fakeService), + new TypeWithSupersetConstructors(fakeService) + }, + { + new TestServiceCollection() + .AddSingleton(factoryService), + new TypeWithSupersetConstructors(factoryService) + }, + { + new TestServiceCollection() + .AddSingleton(fakeService) + .AddSingleton(factoryService), + new TypeWithSupersetConstructors(fakeService, factoryService) + }, + { + new TestServiceCollection() + .AddSingleton(fakeService) + .AddSingleton(multipleService) + .AddSingleton(factoryService), + new TypeWithSupersetConstructors(fakeService, multipleService, factoryService) + }, + { + new TestServiceCollection() + .AddSingleton(fakeService) + .AddSingleton(multipleService) + .AddSingleton(scopedService) + .AddSingleton(factoryService), + new TypeWithSupersetConstructors(multipleService, factoryService, fakeService, scopedService) + } + }; + } + } + + [Theory] + [MemberData(nameof(ServiceContainerPicksConstructorWithLongestMatchesData))] + public void ServiceContainerPicksConstructorWithLongestMatches( + IServiceCollection serviceCollection, + TypeWithSupersetConstructors expected) + { + // Arrange + serviceCollection.AddTransient(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + // Act + var actual = serviceProvider.GetService(); + + // Assert + Assert.NotNull(actual); + Assert.Same(expected.Service, actual.Service); + Assert.Same(expected.FactoryService, actual.FactoryService); + Assert.Same(expected.MultipleService, actual.MultipleService); + Assert.Same(expected.ScopedService, actual.ScopedService); + } + + [Fact] + public void DisposesInReverseOrderOfCreation() + { + // Arrange + var serviceCollection = new TestServiceCollection(); + serviceCollection.AddSingleton(); + serviceCollection.AddTransient(); + serviceCollection.AddSingleton(); + serviceCollection.AddScoped(); + serviceCollection.AddTransient(); + serviceCollection.AddSingleton(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + var callback = serviceProvider.GetService(); + var outer = serviceProvider.GetService(); + var multipleServices = outer.MultipleServices.ToArray(); + + // Act + ((IDisposable)serviceProvider).Dispose(); + + // Assert + Assert.Equal(outer, callback.Disposed[0]); + Assert.Equal(multipleServices.Reverse(), callback.Disposed.Skip(1).Take(3).OfType()); + Assert.Equal(outer.SingleService, callback.Disposed[4]); + } + + [Fact] + public void ResolvesMixedOpenClosedGenericsAsEnumerable() + { + // Arrange + var serviceCollection = new TestServiceCollection(); + var instance = new FakeOpenGenericService(null); + + serviceCollection.AddTransient(); + serviceCollection.AddSingleton(typeof(IFakeOpenGenericService), typeof(FakeService)); + serviceCollection.AddSingleton(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>)); + serviceCollection.AddSingleton>(instance); + + var serviceProvider = CreateServiceProvider(serviceCollection); + + var enumerable = serviceProvider.GetService>>().ToArray(); + + // Assert + Assert.Equal(3, enumerable.Length); + Assert.NotNull(enumerable[0]); + Assert.NotNull(enumerable[1]); + Assert.NotNull(enumerable[2]); + + Assert.Equal(instance, enumerable[2]); + Assert.IsType(enumerable[0]); + } + + [Theory] + [InlineData(typeof(IFakeService), typeof(FakeService), typeof(IFakeService), ServiceLifetime.Scoped)] + [InlineData(typeof(IFakeService), typeof(FakeService), typeof(IFakeService), ServiceLifetime.Singleton)] + [InlineData(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>), typeof(IFakeOpenGenericService), ServiceLifetime.Scoped)] + [InlineData(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>), typeof(IFakeOpenGenericService), ServiceLifetime.Singleton)] + public void ResolvesDifferentInstancesForServiceWhenResolvingEnumerable(Type serviceType, Type implementation, Type resolve, ServiceLifetime lifetime) + { + // Arrange + var serviceCollection = new TestServiceCollection + { + ServiceDescriptor.Describe(serviceType, implementation, lifetime), + ServiceDescriptor.Describe(serviceType, implementation, lifetime), + ServiceDescriptor.Describe(serviceType, implementation, lifetime) + }; + + var serviceProvider = CreateServiceProvider(serviceCollection); + using (var scope = serviceProvider.CreateScope()) + { + var enumerable = (scope.ServiceProvider.GetService(typeof(IEnumerable<>).MakeGenericType(resolve)) as IEnumerable) + .OfType().ToArray(); + var service = scope.ServiceProvider.GetService(resolve); + + // Assert + Assert.Equal(3, enumerable.Length); + Assert.NotNull(enumerable[0]); + Assert.NotNull(enumerable[1]); + Assert.NotNull(enumerable[2]); + + Assert.NotEqual(enumerable[0], enumerable[1]); + Assert.NotEqual(enumerable[1], enumerable[2]); + Assert.Equal(service, enumerable[2]); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AnotherClass.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AnotherClass.cs new file mode 100644 index 00000000000000..40a92237bfbe6f --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AnotherClass.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class AnotherClass + { + public AnotherClass(IFakeService fakeService) + { + FakeService = fakeService; + } + + public IFakeService FakeService { get; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AnotherClassAcceptingData.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AnotherClassAcceptingData.cs new file mode 100644 index 00000000000000..4f9dcda0ae303a --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AnotherClassAcceptingData.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class AnotherClassAcceptingData + { + public AnotherClassAcceptingData(IFakeService fakeService, string one, string two) + { + FakeService = fakeService; + One = one; + Two = two; + } + + public IFakeService FakeService { get; } + + public string One { get; } + + public string Two { get; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAmbiguousCtors.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAmbiguousCtors.cs new file mode 100644 index 00000000000000..55ec934be20b42 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAmbiguousCtors.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithAmbiguousCtors + { + public ClassWithAmbiguousCtors(string data) + { + CtorUsed = "string"; + } + + public ClassWithAmbiguousCtors(IFakeService service, string data) + { + CtorUsed = "IFakeService, string"; + } + + public ClassWithAmbiguousCtors(IFakeService service, int data) + { + CtorUsed = "IFakeService, int"; + } + + public ClassWithAmbiguousCtors(IFakeService service, string data1, int data2) + { + FakeService = service; + Data1 = data1; + Data2 = data2; + + CtorUsed = "IFakeService, string, string"; + } + + public IFakeService FakeService { get; } + + public string Data1 { get; } + + public int Data2 { get; } + public string CtorUsed { get; set; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAmbiguousCtorsAndAttribute.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAmbiguousCtorsAndAttribute.cs new file mode 100644 index 00000000000000..b0e7d2284cdedf --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAmbiguousCtorsAndAttribute.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithAmbiguousCtorsAndAttribute + { + public ClassWithAmbiguousCtorsAndAttribute(string data) + { + CtorUsed = "string"; + } + + [ActivatorUtilitiesConstructor] + public ClassWithAmbiguousCtorsAndAttribute(IFakeService service, string data) + { + CtorUsed = "IFakeService, string"; + } + + public ClassWithAmbiguousCtorsAndAttribute(IFakeService service, IFakeOuterService service2, string data) + { + CtorUsed = "IFakeService, IFakeService, string"; + } + + public string CtorUsed { get; set; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithInternalConstructor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithInternalConstructor.cs new file mode 100644 index 00000000000000..220d3e86d39b20 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithInternalConstructor.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection +{ + public class ClassWithInternalConstructor + { + internal ClassWithInternalConstructor() + { + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithMultipleMarkedCtors.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithMultipleMarkedCtors.cs new file mode 100644 index 00000000000000..9cb04aafd63a6f --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithMultipleMarkedCtors.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithMultipleMarkedCtors + { + [ActivatorUtilitiesConstructor] + public ClassWithMultipleMarkedCtors(string data) + { + } + + [ActivatorUtilitiesConstructor] + public ClassWithMultipleMarkedCtors(IFakeService service, string data) + { + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNestedReferencesToProvider.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNestedReferencesToProvider.cs new file mode 100644 index 00000000000000..1813db134fa962 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNestedReferencesToProvider.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithNestedReferencesToProvider : IDisposable + { + private IServiceProvider _serviceProvider; + private ClassWithNestedReferencesToProvider _nested; + + public ClassWithNestedReferencesToProvider(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + _nested = new ClassWithNestedReferencesToProvider(_serviceProvider, 0); + } + + private ClassWithNestedReferencesToProvider(IServiceProvider serviceProvider, int level) + { + _serviceProvider = serviceProvider; + if (level > 1) + { + _nested = new ClassWithNestedReferencesToProvider(_serviceProvider, level + 1); + } + } + + public void Dispose() + { + _nested?.Dispose(); + (_serviceProvider as IDisposable)?.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtor.cs new file mode 100644 index 00000000000000..810804bafccc76 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtor.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public class ClassWithOptionalArgsCtor + { + public ClassWithOptionalArgsCtor(string whatever = "BLARGH") + { + Whatever = whatever; + } + + public string Whatever { get; set; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs new file mode 100644 index 00000000000000..d0b2588211e461 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public class ClassWithOptionalArgsCtorWithStructs + { + public ConsoleColor? Color { get; } + public ConsoleColor? ColorNull { get; } + + public int? Integer { get; } + public int? IntegerNull { get; } + + public ClassWithOptionalArgsCtorWithStructs( + DateTime dateTime = new DateTime(), + DateTime dateTimeDefault = default(DateTime), + TimeSpan timeSpan = new TimeSpan(), + TimeSpan timeSpanDefault = default(TimeSpan), + DateTimeOffset dateTimeOffset = new DateTimeOffset(), + DateTimeOffset dateTimeOffsetDefault = default(DateTimeOffset), + Guid guid = new Guid(), + Guid guidDefault = default(Guid), + CustomStruct customStruct = new CustomStruct(), + CustomStruct customStructDefault = default(CustomStruct), + ConsoleColor? color = ConsoleColor.DarkGreen, + ConsoleColor? colorNull = null, + int? integer = 12, + int? integerNull = null + ) + { + Color = color; + ColorNull = colorNull; + Integer = integer; + IntegerNull = integerNull; + } + + public struct CustomStruct { } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithPrivateCtor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithPrivateCtor.cs new file mode 100644 index 00000000000000..f0ef2a678c7377 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithPrivateCtor.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithPrivateCtor + { + private ClassWithPrivateCtor() + { + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithProtectedConstructor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithProtectedConstructor.cs new file mode 100644 index 00000000000000..d3098dcd09b6c5 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithProtectedConstructor.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithProtectedConstructor + { + internal ClassWithProtectedConstructor() + { + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithServiceProvider.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithServiceProvider.cs new file mode 100644 index 00000000000000..1003e9976580ae --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithServiceProvider.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithServiceProvider + { + public ClassWithServiceProvider(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + public IServiceProvider ServiceProvider { get; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithStaticCtor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithStaticCtor.cs new file mode 100644 index 00000000000000..ebd631b17e9ddb --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithStaticCtor.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithStaticCtor + { + static ClassWithStaticCtor() + { + + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithThrowingCtor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithThrowingCtor.cs new file mode 100644 index 00000000000000..575d18117113b9 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithThrowingCtor.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithThrowingCtor + { + public ClassWithThrowingCtor(IFakeService service) + { + throw new Exception(nameof(ClassWithThrowingCtor)); + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithThrowingEmptyCtor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithThrowingEmptyCtor.cs new file mode 100644 index 00000000000000..9ecc4b233244bb --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithThrowingEmptyCtor.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithThrowingEmptyCtor + { + public ClassWithThrowingEmptyCtor() + { + throw new Exception(nameof(ClassWithThrowingEmptyCtor)); + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/CreationCountFakeService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/CreationCountFakeService.cs new file mode 100644 index 00000000000000..8c9a21912b051e --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/CreationCountFakeService.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class CreationCountFakeService + { + public static readonly object InstanceLock = new object(); + + public CreationCountFakeService(IFakeService dependency) + { + InstanceCount++; + InstanceId = InstanceCount; + } + + public static int InstanceCount { get; set; } + + public int InstanceId { get; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackInnerService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackInnerService.cs new file mode 100644 index 00000000000000..2acc2204591536 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackInnerService.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeDisposableCallbackInnerService : FakeDisposableCallbackService, IFakeMultipleService + { + public FakeDisposableCallbackInnerService(FakeDisposeCallback callback) : base(callback) + { + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackOuterService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackOuterService.cs new file mode 100644 index 00000000000000..7ef95a854b051b --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackOuterService.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Linq; +using System.Collections.Generic; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeDisposableCallbackOuterService : FakeDisposableCallbackService, IFakeOuterService + { + public FakeDisposableCallbackOuterService( + IFakeService singleService, + IEnumerable multipleServices, + FakeDisposeCallback callback) : base(callback) + { + SingleService = singleService; + MultipleServices = multipleServices.ToArray(); + } + + public IFakeService SingleService { get; } + public IEnumerable MultipleServices { get; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackService.cs new file mode 100644 index 00000000000000..5f29aa01ed1c15 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackService.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeDisposableCallbackService: IDisposable + { + private static int _globalId; + private readonly int _id; + private readonly FakeDisposeCallback _callback; + + public FakeDisposableCallbackService(FakeDisposeCallback callback) + { + _id = _globalId++; + _callback = callback; + } + + public void Dispose() + { + _callback.Disposed.Add(this); + } + + public override string ToString() + { + return _id.ToString(); + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposeCallback.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposeCallback.cs new file mode 100644 index 00000000000000..8d0ca9f446f605 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposeCallback.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeDisposeCallback + { + public List Disposed { get; } = new List(); + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOneMultipleService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOneMultipleService.cs new file mode 100644 index 00000000000000..a5d3cd1451c224 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOneMultipleService.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeOneMultipleService : IFakeMultipleService + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOpenGenericService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOpenGenericService.cs new file mode 100644 index 00000000000000..c2be6bc4c1b43b --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOpenGenericService.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeOpenGenericService : IFakeOpenGenericService + { + public FakeOpenGenericService(TVal value) + { + Value = value; + } + + public TVal Value { get; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOuterService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOuterService.cs new file mode 100644 index 00000000000000..667f911557e8b1 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOuterService.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeOuterService : IFakeOuterService + { + public FakeOuterService( + IFakeService singleService, + IEnumerable multipleServices) + { + SingleService = singleService; + MultipleServices = multipleServices; + } + + public IFakeService SingleService { get; } + + public IEnumerable MultipleServices { get; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeService.cs new file mode 100644 index 00000000000000..3fccf3de00b37d --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeService.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeService : IFakeEveryService, IDisposable + { + public PocoClass Value { get; set; } + + public bool Disposed { get; private set; } + + public void Dispose() + { + if (Disposed) + { + throw new ObjectDisposedException(nameof(FakeService)); + } + + Disposed = true; + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeTwoMultipleService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeTwoMultipleService.cs new file mode 100644 index 00000000000000..89fcab70108407 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeTwoMultipleService.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeTwoMultipleService : IFakeMultipleService + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFactoryService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFactoryService.cs new file mode 100644 index 00000000000000..ddbc44f20fb79e --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFactoryService.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFactoryService + { + IFakeService FakeService { get; } + + int Value { get; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeEveryService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeEveryService.cs new file mode 100644 index 00000000000000..9e24521a65ab5a --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeEveryService.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeEveryService : + IFakeService, + IFakeMultipleService, + IFakeScopedService, + IFakeServiceInstance, + IFakeSingletonService, + IFakeOpenGenericService + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeMultipleService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeMultipleService.cs new file mode 100644 index 00000000000000..a38394c665f870 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeMultipleService.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeMultipleService : IFakeService + { + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOpenGenericService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOpenGenericService.cs new file mode 100644 index 00000000000000..12dc7142557384 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOpenGenericService.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeOpenGenericService + { + TValue Value { get; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOuterService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOuterService.cs new file mode 100644 index 00000000000000..f4bd3e3a2dae27 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOuterService.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeOuterService + { + IFakeService SingleService { get; } + + IEnumerable MultipleServices { get; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeScopedService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeScopedService.cs new file mode 100644 index 00000000000000..9f3f4f000df1aa --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeScopedService.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeScopedService : IFakeService + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeService.cs new file mode 100644 index 00000000000000..391bf2edf3d4a7 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeService.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeService + { + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeServiceInstance.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeServiceInstance.cs new file mode 100644 index 00000000000000..e6ed4019e37bbd --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeServiceInstance.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeServiceInstance : IFakeService + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeSingletonService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeSingletonService.cs new file mode 100644 index 00000000000000..3f341ce204de4e --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeSingletonService.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeSingletonService : IFakeService + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/INonexistentService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/INonexistentService.cs new file mode 100644 index 00000000000000..54661e3cd970cd --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/INonexistentService.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface INonexistentService + { + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/PocoClass.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/PocoClass.cs new file mode 100644 index 00000000000000..75bd28ae9f745c --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/PocoClass.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class PocoClass + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ScopedFactoryService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ScopedFactoryService.cs new file mode 100644 index 00000000000000..298ad076c1adb1 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ScopedFactoryService.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ScopedFactoryService + { + public IFakeService FakeService { get; set; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ServiceAcceptingFactoryService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ServiceAcceptingFactoryService.cs new file mode 100644 index 00000000000000..c016eaeeca7cfe --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ServiceAcceptingFactoryService.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ServiceAcceptingFactoryService + { + public ServiceAcceptingFactoryService( + ScopedFactoryService scopedService, + IFactoryService transientService) + { + ScopedService = scopedService; + TransientService = transientService; + } + + public ScopedFactoryService ScopedService { get; private set; } + + public IFactoryService TransientService { get; private set; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/TransientFactoryService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/TransientFactoryService.cs new file mode 100644 index 00000000000000..1915f3fda0a385 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/TransientFactoryService.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class TransientFactoryService : IFactoryService + { + public IFakeService FakeService { get; set; } + + public int Value { get; set; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/TypeWithSupersetConstructors.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/TypeWithSupersetConstructors.cs new file mode 100644 index 00000000000000..c378883701547b --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/TypeWithSupersetConstructors.cs @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class TypeWithSupersetConstructors + { + public TypeWithSupersetConstructors(IFactoryService factoryService) + : this( + fakeService: null, + factoryService: factoryService) + { + } + + public TypeWithSupersetConstructors(IFakeService fakeService) + : this( + fakeService, + factoryService: null) + { + } + + public TypeWithSupersetConstructors( + IFakeService fakeService, + IFactoryService factoryService) + : this( + fakeService, + multipleService: null, + factoryService: factoryService) + { + } + + public TypeWithSupersetConstructors( + IFakeService fakeService, + IFakeMultipleService multipleService, + IFactoryService factoryService) + : this( + multipleService, + factoryService, + fakeService, + scopedService: null) + { + } + + public TypeWithSupersetConstructors( + IFakeMultipleService multipleService, + IFactoryService factoryService, + IFakeService fakeService, + IFakeScopedService scopedService) + { + MultipleService = multipleService; + FactoryService = factoryService; + Service = fakeService; + ScopedService = scopedService; + } + + public IFakeService Service { get; } + + public IFactoryService FactoryService { get; } + + public IFakeMultipleService MultipleService { get; } + + public IFakeScopedService ScopedService { get; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ServiceCollection.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ServiceCollection.cs new file mode 100644 index 00000000000000..b4501e76319e92 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ServiceCollection.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + internal class TestServiceCollection : List, IServiceCollection + { + } +}