diff --git a/OpenIddict.sln b/OpenIddict.sln index fc61b4c9..bfaef2b9 100644 --- a/OpenIddict.sln +++ b/OpenIddict.sln @@ -59,6 +59,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIddict.MongoDb", "src\O EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIddict.MongoDb.Models", "src\OpenIddict.MongoDb.Models\OpenIddict.MongoDb.Models.csproj", "{14C55FB6-9626-4BDE-8961-3BE91DDD6418}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIddict.Abstractions.Tests", "test\OpenIddict.Abstractions.Tests\OpenIddict.Abstractions.Tests.csproj", "{8FACE85E-EF8F-4AB1-85DD-4010D5E2165D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenIddict.MongoDb.Tests", "test\OpenIddict.MongoDb.Tests\OpenIddict.MongoDb.Tests.csproj", "{27F603EF-D335-445B-9443-6B5A6CA3C110}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -145,6 +149,14 @@ Global {14C55FB6-9626-4BDE-8961-3BE91DDD6418}.Debug|Any CPU.Build.0 = Debug|Any CPU {14C55FB6-9626-4BDE-8961-3BE91DDD6418}.Release|Any CPU.ActiveCfg = Release|Any CPU {14C55FB6-9626-4BDE-8961-3BE91DDD6418}.Release|Any CPU.Build.0 = Release|Any CPU + {8FACE85E-EF8F-4AB1-85DD-4010D5E2165D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8FACE85E-EF8F-4AB1-85DD-4010D5E2165D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8FACE85E-EF8F-4AB1-85DD-4010D5E2165D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8FACE85E-EF8F-4AB1-85DD-4010D5E2165D}.Release|Any CPU.Build.0 = Release|Any CPU + {27F603EF-D335-445B-9443-6B5A6CA3C110}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {27F603EF-D335-445B-9443-6B5A6CA3C110}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27F603EF-D335-445B-9443-6B5A6CA3C110}.Release|Any CPU.ActiveCfg = Release|Any CPU + {27F603EF-D335-445B-9443-6B5A6CA3C110}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -170,6 +182,8 @@ Global {B5371534-4C33-41FA-B3D3-7D70D632DB15} = {D544447C-D701-46BB-9A5B-C76C612A596B} {BACF1DD4-8390-48D4-BD9B-DA1EC00C1F98} = {D544447C-D701-46BB-9A5B-C76C612A596B} {14C55FB6-9626-4BDE-8961-3BE91DDD6418} = {D544447C-D701-46BB-9A5B-C76C612A596B} + {8FACE85E-EF8F-4AB1-85DD-4010D5E2165D} = {5FC71D6A-A994-4F62-977F-88A7D25379D7} + {27F603EF-D335-445B-9443-6B5A6CA3C110} = {5FC71D6A-A994-4F62-977F-88A7D25379D7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A710059F-0466-4D48-9B3A-0EF4F840B616} diff --git a/src/OpenIddict.Core/OpenIddict.Core.csproj b/src/OpenIddict.Core/OpenIddict.Core.csproj index ada5a726..cc6d4cc3 100644 --- a/src/OpenIddict.Core/OpenIddict.Core.csproj +++ b/src/OpenIddict.Core/OpenIddict.Core.csproj @@ -19,7 +19,7 @@ - + diff --git a/src/OpenIddict.Core/OpenIddictCoreExtensions.cs b/src/OpenIddict.Core/OpenIddictCoreExtensions.cs index 8b72b5af..6665822a 100644 --- a/src/OpenIddict.Core/OpenIddictCoreExtensions.cs +++ b/src/OpenIddict.Core/OpenIddictCoreExtensions.cs @@ -29,6 +29,7 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentNullException(nameof(builder)); } + builder.Services.AddLogging(); builder.Services.AddOptions(); builder.Services.TryAddScoped(typeof(OpenIddictApplicationManager<>)); diff --git a/src/OpenIddict.Core/Resolvers/OpenIddictTokenStoreResolver.cs b/src/OpenIddict.Core/Resolvers/OpenIddictTokenStoreResolver.cs index 48f7a11b..a7ed6b6f 100644 --- a/src/OpenIddict.Core/Resolvers/OpenIddictTokenStoreResolver.cs +++ b/src/OpenIddict.Core/Resolvers/OpenIddictTokenStoreResolver.cs @@ -30,7 +30,7 @@ namespace OpenIddict.Core if (store == null) { throw new InvalidOperationException(new StringBuilder() - .AppendLine("No token store factory has been registered in the dependency injection container.") + .AppendLine("No token store has been registered in the dependency injection container.") .Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ") .AppendLine("package and call 'services.AddOpenIddict().AddCore().UseEntityFrameworkCore()'.") .Append("To register a custom store, create an implementation of 'IOpenIddictTokenStore' and ") diff --git a/src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkBuilder.cs b/src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkBuilder.cs index 363231c3..a950716e 100644 --- a/src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkBuilder.cs +++ b/src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkBuilder.cs @@ -58,13 +58,37 @@ namespace Microsoft.Extensions.DependencyInjection return this; } + /// + /// Configures OpenIddict to use the specified entities, derived + /// from the default OpenIddict Entity Framework 6.x entities. + /// + /// The . + public OpenIddictEntityFrameworkBuilder ReplaceDefaultEntities() + where TApplication : OpenIddictApplication + where TAuthorization : OpenIddictAuthorization + where TScope : OpenIddictScope + where TToken : OpenIddictToken + where TKey : IEquatable + { + Services.Configure(options => + { + options.DefaultApplicationType = typeof(TApplication); + options.DefaultAuthorizationType = typeof(TAuthorization); + options.DefaultScopeType = typeof(TScope); + options.DefaultTokenType = typeof(TToken); + }); + + return this; + } + /// /// Configures the OpenIddict Entity Framework 6.x stores to use the specified database context type. /// /// The type of the used by OpenIddict. /// The . public OpenIddictEntityFrameworkBuilder UseDbContext() - where TContext : DbContext => UseDbContext(typeof(TContext)); + where TContext : DbContext + => UseDbContext(typeof(TContext)); /// /// Configures the OpenIddict Entity Framework 6.x stores to use the specified database context type. @@ -87,28 +111,5 @@ namespace Microsoft.Extensions.DependencyInjection return Configure(options => options.DbContextType = type); } - - /// - /// Configures OpenIddict to use the specified entities, derived - /// from the default OpenIddict Entity Framework 6.x entities. - /// - /// The . - public OpenIddictEntityFrameworkBuilder ReplaceDefaultEntities() - where TApplication : OpenIddictApplication - where TAuthorization : OpenIddictAuthorization - where TScope : OpenIddictScope - where TToken : OpenIddictToken - where TKey : IEquatable - { - Services.Configure(options => - { - options.DefaultApplicationType = typeof(TApplication); - options.DefaultAuthorizationType = typeof(TAuthorization); - options.DefaultScopeType = typeof(TScope); - options.DefaultTokenType = typeof(TToken); - }); - - return this; - } } } diff --git a/src/OpenIddict.EntityFramework/Resolvers/OpenIddictScopeStoreResolver.cs b/src/OpenIddict.EntityFramework/Resolvers/OpenIddictScopeStoreResolver.cs index 33e4e5c9..e435d37a 100644 --- a/src/OpenIddict.EntityFramework/Resolvers/OpenIddictScopeStoreResolver.cs +++ b/src/OpenIddict.EntityFramework/Resolvers/OpenIddictScopeStoreResolver.cs @@ -55,7 +55,7 @@ namespace OpenIddict.EntityFramework throw new InvalidOperationException(new StringBuilder() .AppendLine("The specified scope type is not compatible with the Entity Framework 6.x stores.") .Append("When enabling the Entity Framework 6.x stores, make sure you use the built-in ") - .Append("'OpenIdScope' entity (from the 'OpenIddict.EntityFramework.Models' package) ") + .Append("'OpenIddictScope' entity (from the 'OpenIddict.EntityFramework.Models' package) ") .Append("or a custom entity that inherits from the generic 'OpenIddictScope' entity.") .ToString()); } diff --git a/src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreBuilder.cs b/src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreBuilder.cs index 051e0ef8..21fb685e 100644 --- a/src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreBuilder.cs +++ b/src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreBuilder.cs @@ -57,34 +57,6 @@ namespace Microsoft.Extensions.DependencyInjection return this; } - /// - /// Configures the OpenIddict Entity Framework Core stores to use the specified database context type. - /// - /// The type of the used by OpenIddict. - /// The . - public OpenIddictEntityFrameworkCoreBuilder UseDbContext() - where TContext : DbContext => UseDbContext(typeof(TContext)); - - /// - /// Configures the OpenIddict Entity Framework Core stores to use the specified database context type. - /// - /// The type of the used by OpenIddict. - /// The . - public OpenIddictEntityFrameworkCoreBuilder UseDbContext([NotNull] Type type) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (!typeof(DbContext).IsAssignableFrom(type)) - { - throw new ArgumentException("The specified type is invalid.", nameof(type)); - } - - return Configure(options => options.DbContextType = type); - } - /// /// Configures OpenIddict to use the default OpenIddict /// Entity Framework Core entities, with the specified key type. @@ -119,5 +91,34 @@ namespace Microsoft.Extensions.DependencyInjection return this; } + + /// + /// Configures the OpenIddict Entity Framework Core stores to use the specified database context type. + /// + /// The type of the used by OpenIddict. + /// The . + public OpenIddictEntityFrameworkCoreBuilder UseDbContext() + where TContext : DbContext + => UseDbContext(typeof(TContext)); + + /// + /// Configures the OpenIddict Entity Framework Core stores to use the specified database context type. + /// + /// The type of the used by OpenIddict. + /// The . + public OpenIddictEntityFrameworkCoreBuilder UseDbContext([NotNull] Type type) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (!typeof(DbContext).IsAssignableFrom(type)) + { + throw new ArgumentException("The specified type is invalid.", nameof(type)); + } + + return Configure(options => options.DbContextType = type); + } } } diff --git a/src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictScopeStoreResolver.cs b/src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictScopeStoreResolver.cs index f847ea29..ef419e8a 100644 --- a/src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictScopeStoreResolver.cs +++ b/src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictScopeStoreResolver.cs @@ -55,7 +55,7 @@ namespace OpenIddict.EntityFrameworkCore throw new InvalidOperationException(new StringBuilder() .AppendLine("The specified scope type is not compatible with the Entity Framework Core stores.") .Append("When enabling the Entity Framework Core stores, make sure you use the built-in ") - .Append("'OpenIdScope' entity (from the 'OpenIddict.EntityFrameworkCore.Models' package) ") + .Append("'OpenIddictScope' entity (from the 'OpenIddict.EntityFrameworkCore.Models' package) ") .Append("or a custom entity that inherits from the generic 'OpenIddictScope' entity.") .ToString()); } diff --git a/src/OpenIddict.MongoDb/OpenIddictMongoDbBuilder.cs b/src/OpenIddict.MongoDb/OpenIddictMongoDbBuilder.cs index a5834add..22899343 100644 --- a/src/OpenIddict.MongoDb/OpenIddictMongoDbBuilder.cs +++ b/src/OpenIddict.MongoDb/OpenIddictMongoDbBuilder.cs @@ -57,22 +57,6 @@ namespace Microsoft.Extensions.DependencyInjection return this; } - /// - /// Configures the MongoDB stores to use the specified database - /// instead of retrieving it from the dependency injection container. - /// - /// The . - /// The . - public OpenIddictMongoDbBuilder UseDatabase([NotNull] IMongoDatabase database) - { - if (database == null) - { - throw new ArgumentNullException(nameof(database)); - } - - return Configure(options => options.Database = database); - } - /// /// Configures OpenIddict to use the specified entity as the default application entity. /// @@ -180,5 +164,21 @@ namespace Microsoft.Extensions.DependencyInjection return Configure(options => options.TokensCollectionName = name); } + + /// + /// Configures the MongoDB stores to use the specified database + /// instead of retrieving it from the dependency injection container. + /// + /// The . + /// The . + public OpenIddictMongoDbBuilder UseDatabase([NotNull] IMongoDatabase database) + { + if (database == null) + { + throw new ArgumentNullException(nameof(database)); + } + + return Configure(options => options.Database = database); + } } } diff --git a/src/OpenIddict.Mvc/OpenIddictMvcExtensions.cs b/src/OpenIddict.Mvc/OpenIddictMvcExtensions.cs index 26c62623..6a6ade16 100644 --- a/src/OpenIddict.Mvc/OpenIddictMvcExtensions.cs +++ b/src/OpenIddict.Mvc/OpenIddictMvcExtensions.cs @@ -60,6 +60,11 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentNullException(nameof(builder)); } + if (configuration == null) + { + throw new ArgumentNullException(nameof(configuration)); + } + configuration(builder.UseMvc()); return builder; diff --git a/src/OpenIddict.Server/OpenIddict.Server.csproj b/src/OpenIddict.Server/OpenIddict.Server.csproj index ce02ae8b..4decf8eb 100644 --- a/src/OpenIddict.Server/OpenIddict.Server.csproj +++ b/src/OpenIddict.Server/OpenIddict.Server.csproj @@ -1,4 +1,4 @@ - + @@ -21,6 +21,7 @@ + diff --git a/src/OpenIddict.Server/OpenIddictServerExtensions.cs b/src/OpenIddict.Server/OpenIddictServerExtensions.cs index e2541fd7..5c515731 100644 --- a/src/OpenIddict.Server/OpenIddictServerExtensions.cs +++ b/src/OpenIddict.Server/OpenIddictServerExtensions.cs @@ -34,6 +34,7 @@ namespace Microsoft.Extensions.DependencyInjection builder.Services.AddAuthentication(); builder.Services.AddDistributedMemoryCache(); + builder.Services.AddLogging(); builder.Services.AddMemoryCache(); builder.Services.AddOptions(); diff --git a/src/OpenIddict.Validation/OpenIddict.Validation.csproj b/src/OpenIddict.Validation/OpenIddict.Validation.csproj index 5628ec8b..2a061224 100644 --- a/src/OpenIddict.Validation/OpenIddict.Validation.csproj +++ b/src/OpenIddict.Validation/OpenIddict.Validation.csproj @@ -19,6 +19,7 @@ + diff --git a/src/OpenIddict.Validation/OpenIddictValidationExtensions.cs b/src/OpenIddict.Validation/OpenIddictValidationExtensions.cs index cac9a165..8c74f88e 100644 --- a/src/OpenIddict.Validation/OpenIddictValidationExtensions.cs +++ b/src/OpenIddict.Validation/OpenIddictValidationExtensions.cs @@ -33,6 +33,7 @@ namespace Microsoft.Extensions.DependencyInjection } builder.Services.AddAuthentication(); + builder.Services.AddLogging(); builder.Services.AddOptions(); builder.Services.TryAddScoped(); diff --git a/test/OpenIddict.Abstractions.Tests/OpenIddict.Abstractions.Tests.csproj b/test/OpenIddict.Abstractions.Tests/OpenIddict.Abstractions.Tests.csproj new file mode 100644 index 00000000..0b7b3c1a --- /dev/null +++ b/test/OpenIddict.Abstractions.Tests/OpenIddict.Abstractions.Tests.csproj @@ -0,0 +1,26 @@ + + + + + + netcoreapp2.0;net461 + netcoreapp2.0 + + + + + + + + + + + + + + + + + + + diff --git a/test/OpenIddict.Abstractions.Tests/OpenIddictBuilderTests.cs b/test/OpenIddict.Abstractions.Tests/OpenIddictBuilderTests.cs new file mode 100644 index 00000000..747aabf5 --- /dev/null +++ b/test/OpenIddict.Abstractions.Tests/OpenIddictBuilderTests.cs @@ -0,0 +1,27 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace OpenIddict.Abstractions.Tests +{ + public class OpenIddictBuilderTests + { + [Fact] + public void Constructor_ThrowsAnExceptionForNullServices() + { + // Arrange + var services = (IServiceCollection) null; + + // Act and assert + var exception = Assert.Throws(() => new OpenIddictBuilder(services)); + + Assert.Equal("services", exception.ParamName); + } + } +} diff --git a/test/OpenIddict.Abstractions.Tests/OpenIddictExtensionsTests.cs b/test/OpenIddict.Abstractions.Tests/OpenIddictExtensionsTests.cs new file mode 100644 index 00000000..a45524c8 --- /dev/null +++ b/test/OpenIddict.Abstractions.Tests/OpenIddictExtensionsTests.cs @@ -0,0 +1,39 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace OpenIddict.Abstractions.Tests +{ + public class OpenIddictExtensionsTests + { + [Fact] + public void AddOpenIddict_ThrowsAnExceptionForNullServices() + { + // Arrange + var services = (IServiceCollection) null; + + // Act and assert + var exception = Assert.Throws(() => services.AddOpenIddict()); + + Assert.Equal("services", exception.ParamName); + } + + [Fact] + public void AddOpenIddict_ThrowsAnExceptionForNullConfigurationDelegate() + { + // Arrange + var services = new ServiceCollection(); + + // Act and assert + var exception = Assert.Throws(() => services.AddOpenIddict(configuration: null)); + + Assert.Equal("configuration", exception.ParamName); + } + } +} diff --git a/test/OpenIddict.Core.Tests/OpenIddictCoreBuilderTests.cs b/test/OpenIddict.Core.Tests/OpenIddictCoreBuilderTests.cs index d436f5fb..bf45cc62 100644 --- a/test/OpenIddict.Core.Tests/OpenIddictCoreBuilderTests.cs +++ b/test/OpenIddict.Core.Tests/OpenIddictCoreBuilderTests.cs @@ -16,6 +16,18 @@ namespace OpenIddict.Core.Tests { public class OpenIddictCoreBuilderTests { + [Fact] + public void Constructor_ThrowsAnExceptionForNullServices() + { + // Arrange + var services = (IServiceCollection) null; + + // Act and assert + var exception = Assert.Throws(() => new OpenIddictCoreBuilder(services)); + + Assert.Equal("services", exception.ParamName); + } + [Fact] public void ReplaceApplicationManager_ThrowsAnExceptionForInvalidManager() { diff --git a/test/OpenIddict.Core.Tests/OpenIddictCoreExtensionsTests.cs b/test/OpenIddict.Core.Tests/OpenIddictCoreExtensionsTests.cs new file mode 100644 index 00000000..520c7d70 --- /dev/null +++ b/test/OpenIddict.Core.Tests/OpenIddictCoreExtensionsTests.cs @@ -0,0 +1,321 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Moq; +using OpenIddict.Abstractions; +using Xunit; + +namespace OpenIddict.Core.Tests +{ + public class OpenIddictCoreExtensionsTests + { + [Fact] + public void AddCore_ThrowsAnExceptionForNullBuilder() + { + // Arrange + var builder = (OpenIddictBuilder) null; + + // Act and assert + var exception = Assert.Throws(() => builder.AddCore()); + + Assert.Equal("builder", exception.ParamName); + } + + [Fact] + public void AddCore_ThrowsAnExceptionForNullConfiguration() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.AddCore(configuration: null)); + + Assert.Equal("configuration", exception.ParamName); + } + + [Fact] + public void AddCore_RegistersLoggingServices() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddCore(); + + // Assert + Assert.Contains(services, service => service.ServiceType == typeof(ILogger<>)); + } + + [Fact] + public void AddCore_RegistersOptionsServices() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddCore(); + + // Assert + Assert.Contains(services, service => service.ServiceType == typeof(IOptions<>)); + } + + [Theory] + [InlineData(typeof(OpenIddictApplicationManager<>))] + [InlineData(typeof(OpenIddictAuthorizationManager<>))] + [InlineData(typeof(OpenIddictScopeManager<>))] + [InlineData(typeof(OpenIddictTokenManager<>))] + public void AddCore_RegistersDefaultManagers(Type type) + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddCore(); + + // Assert + Assert.Contains(services, service => service.ServiceType == type && service.ImplementationType == type); + } + + [Theory] + [InlineData(typeof(IOpenIddictApplicationStoreResolver), typeof(OpenIddictApplicationStoreResolver))] + [InlineData(typeof(IOpenIddictAuthorizationStoreResolver), typeof(OpenIddictAuthorizationStoreResolver))] + [InlineData(typeof(IOpenIddictScopeStoreResolver), typeof(OpenIddictScopeStoreResolver))] + [InlineData(typeof(IOpenIddictTokenStoreResolver), typeof(OpenIddictTokenStoreResolver))] + public void AddCore_RegistersDefaultResolvers(Type serviceType, Type implementationType) + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddCore(); + + // Assert + Assert.Contains(services, service => service.ServiceType == serviceType && + service.ImplementationType == implementationType); + } + + [Theory] + [InlineData(typeof(IOpenIddictApplicationManager))] + [InlineData(typeof(IOpenIddictAuthorizationManager))] + [InlineData(typeof(IOpenIddictScopeManager))] + [InlineData(typeof(IOpenIddictTokenManager))] + public void AddCore_RegistersUntypedProxies(Type type) + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddCore(); + + // Assert + Assert.Contains(services, service => service.ServiceType == type && service.ImplementationFactory != null); + } + + [Fact] + public void AddCore_ResolvingUntypedApplicationManagerThrowsAnExceptionWhenDefaultEntityIsNotSet() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddCore(); + + // Assert + var provider = services.BuildServiceProvider(); + + var exception = Assert.Throws(delegate + { + return provider.GetRequiredService(); + }); + + Assert.Equal(new StringBuilder() + .Append("No default application entity type was configured in the OpenIddict core options, ") + .AppendLine("which generally indicates that no application store was registered in the DI container.") + .Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ") + .Append("package and call 'services.AddOpenIddict().AddCore().UseEntityFrameworkCore()'.") + .ToString(), exception.Message); + } + + [Fact] + public void AddCore_ResolvingUntypedAuthorizationManagerThrowsAnExceptionWhenDefaultEntityIsNotSet() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddCore(); + + // Assert + var provider = services.BuildServiceProvider(); + + var exception = Assert.Throws(delegate + { + return provider.GetRequiredService(); + }); + + Assert.Equal(new StringBuilder() + .Append("No default authorization entity type was configured in the OpenIddict core options, ") + .AppendLine("which generally indicates that no authorization store was registered in the DI container.") + .Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ") + .Append("package and call 'services.AddOpenIddict().AddCore().UseEntityFrameworkCore()'.") + .ToString(), exception.Message); + } + + [Fact] + public void AddCore_ResolvingUntypedScopeManagerThrowsAnExceptionWhenDefaultEntityIsNotSet() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddCore(); + + // Assert + var provider = services.BuildServiceProvider(); + + var exception = Assert.Throws(delegate + { + return provider.GetRequiredService(); + }); + + Assert.Equal(new StringBuilder() + .Append("No default scope entity type was configured in the OpenIddict core options, ") + .AppendLine("which generally indicates that no scope store was registered in the DI container.") + .Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ") + .Append("package and call 'services.AddOpenIddict().AddCore().UseEntityFrameworkCore()'.") + .ToString(), exception.Message); + } + + [Fact] + public void AddCore_ResolvingUntypedTokenManagerThrowsAnExceptionWhenDefaultEntityIsNotSet() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddCore(); + + // Assert + var provider = services.BuildServiceProvider(); + + var exception = Assert.Throws(delegate + { + return provider.GetRequiredService(); + }); + + Assert.Equal(new StringBuilder() + .Append("No default token entity type was configured in the OpenIddict core options, ") + .AppendLine("which generally indicates that no token store was registered in the DI container.") + .Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ") + .Append("package and call 'services.AddOpenIddict().AddCore().UseEntityFrameworkCore()'.") + .ToString(), exception.Message); + } + + [Fact] + public void AddCore_ResolvingUntypedApplicationManagerReturnsGenericManager() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddCore(options => + { + options.SetDefaultApplicationEntity(); + options.Services.AddSingleton(Mock.Of>()); + }); + + var provider = services.BuildServiceProvider(); + var manager = provider.GetRequiredService(); + + // Assert + Assert.IsType>(manager); + } + + [Fact] + public void AddCore_ResolvingUntypedAuthorizationManagerReturnsGenericManager() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddCore(options => + { + options.SetDefaultAuthorizationEntity(); + options.Services.AddSingleton(Mock.Of>()); + }); + + var provider = services.BuildServiceProvider(); + var manager = provider.GetRequiredService(); + + // Assert + Assert.IsType>(manager); + } + + [Fact] + public void AddCore_ResolvingUntypedScopeManagerReturnsGenericManager() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddCore(options => + { + options.SetDefaultScopeEntity(); + options.Services.AddSingleton(Mock.Of>()); + }); + + var provider = services.BuildServiceProvider(); + var manager = provider.GetRequiredService(); + + // Assert + Assert.IsType>(manager); + } + + [Fact] + public void AddCore_ResolvingUntypedTokenManagerReturnsGenericManager() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddCore(options => + { + options.SetDefaultTokenEntity(); + options.Services.AddSingleton(Mock.Of>()); + }); + + var provider = services.BuildServiceProvider(); + var manager = provider.GetRequiredService(); + + // Assert + Assert.IsType>(manager); + } + + public class OpenIddictApplication { } + public class OpenIddictAuthorization { } + public class OpenIddictScope { } + public class OpenIddictToken { } + } +} diff --git a/test/OpenIddict.Core.Tests/Resolvers/OpenIddictApplicationStoreResolverTests.cs b/test/OpenIddict.Core.Tests/Resolvers/OpenIddictApplicationStoreResolverTests.cs new file mode 100644 index 00000000..a5182113 --- /dev/null +++ b/test/OpenIddict.Core.Tests/Resolvers/OpenIddictApplicationStoreResolverTests.cs @@ -0,0 +1,54 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using OpenIddict.Abstractions; +using Xunit; + +namespace OpenIddict.Core.Tests +{ + public class OpenIddictApplicationStoreResolverTests + { + [Fact] + public void Get_ThrowsAnExceptionWhenStoreCannotBeFound() + { + // Arrange + var services = new ServiceCollection(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictApplicationStoreResolver(provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("No application store has been registered in the dependency injection container.") + .Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ") + .AppendLine("package and call 'services.AddOpenIddict().AddCore().UseEntityFrameworkCore()'.") + .Append("To register a custom store, create an implementation of 'IOpenIddictApplicationStore' and ") + .Append("use 'services.AddOpenIddict().AddCore().AddApplicationStore()' to add it to the DI container.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedType() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictApplicationStoreResolver(provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + public class OpenIddictApplication { } + } +} diff --git a/test/OpenIddict.Core.Tests/Resolvers/OpenIddictAuthorizationStoreResolverTests.cs b/test/OpenIddict.Core.Tests/Resolvers/OpenIddictAuthorizationStoreResolverTests.cs new file mode 100644 index 00000000..687665da --- /dev/null +++ b/test/OpenIddict.Core.Tests/Resolvers/OpenIddictAuthorizationStoreResolverTests.cs @@ -0,0 +1,54 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using OpenIddict.Abstractions; +using Xunit; + +namespace OpenIddict.Core.Tests +{ + public class OpenIddictAuthorizationStoreResolverTests + { + [Fact] + public void Get_ThrowsAnExceptionWhenStoreCannotBeFound() + { + // Arrange + var services = new ServiceCollection(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictAuthorizationStoreResolver(provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("No authorization store has been registered in the dependency injection container.") + .Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ") + .AppendLine("package and call 'services.AddOpenIddict().AddCore().UseEntityFrameworkCore()'.") + .Append("To register a custom store, create an implementation of 'IOpenIddictAuthorizationStore' and ") + .Append("use 'services.AddOpenIddict().AddCore().AddAuthorizationStore()' to add it to the DI container.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedType() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictAuthorizationStoreResolver(provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + public class OpenIddictAuthorization { } + } +} diff --git a/test/OpenIddict.Core.Tests/Resolvers/OpenIddictScopeStoreResolverTests.cs b/test/OpenIddict.Core.Tests/Resolvers/OpenIddictScopeStoreResolverTests.cs new file mode 100644 index 00000000..ab759c2b --- /dev/null +++ b/test/OpenIddict.Core.Tests/Resolvers/OpenIddictScopeStoreResolverTests.cs @@ -0,0 +1,54 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using OpenIddict.Abstractions; +using Xunit; + +namespace OpenIddict.Core.Tests +{ + public class OpenIddictScopeStoreResolverTests + { + [Fact] + public void Get_ThrowsAnExceptionWhenStoreCannotBeFound() + { + // Arrange + var services = new ServiceCollection(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictScopeStoreResolver(provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("No scope store has been registered in the dependency injection container.") + .Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ") + .AppendLine("package and call 'services.AddOpenIddict().AddCore().UseEntityFrameworkCore()'.") + .Append("To register a custom store, create an implementation of 'IOpenIddictScopeStore' and ") + .Append("use 'services.AddOpenIddict().AddCore().AddScopeStore()' to add it to the DI container.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedType() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictScopeStoreResolver(provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + public class OpenIddictScope { } + } +} diff --git a/test/OpenIddict.Core.Tests/Resolvers/OpenIddictTokenStoreResolverTests.cs b/test/OpenIddict.Core.Tests/Resolvers/OpenIddictTokenStoreResolverTests.cs new file mode 100644 index 00000000..77183483 --- /dev/null +++ b/test/OpenIddict.Core.Tests/Resolvers/OpenIddictTokenStoreResolverTests.cs @@ -0,0 +1,54 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using OpenIddict.Abstractions; +using Xunit; + +namespace OpenIddict.Core.Tests +{ + public class OpenIddictTokenStoreResolverTests + { + [Fact] + public void Get_ThrowsAnExceptionWhenStoreCannotBeFound() + { + // Arrange + var services = new ServiceCollection(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictTokenStoreResolver(provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("No token store has been registered in the dependency injection container.") + .Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ") + .AppendLine("package and call 'services.AddOpenIddict().AddCore().UseEntityFrameworkCore()'.") + .Append("To register a custom store, create an implementation of 'IOpenIddictTokenStore' and ") + .Append("use 'services.AddOpenIddict().AddCore().AddTokenStore()' to add it to the DI container.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedType() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictTokenStoreResolver(provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + public class OpenIddictToken { } + } +} diff --git a/test/OpenIddict.EntityFramework.Tests/OpenIddictEntityFrameworkBuilderTests.cs b/test/OpenIddict.EntityFramework.Tests/OpenIddictEntityFrameworkBuilderTests.cs new file mode 100644 index 00000000..254ff436 --- /dev/null +++ b/test/OpenIddict.EntityFramework.Tests/OpenIddictEntityFrameworkBuilderTests.cs @@ -0,0 +1,141 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Data.Entity; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using OpenIddict.Core; +using OpenIddict.EntityFramework.Models; +using Xunit; + +namespace OpenIddict.EntityFramework.Tests +{ + public class OpenIddictEntityFrameworkBuilderTests + { + [Fact] + public void Constructor_ThrowsAnExceptionForNullServices() + { + // Arrange + var services = (IServiceCollection) null; + + // Act and assert + var exception = Assert.Throws(() => new OpenIddictEntityFrameworkBuilder(services)); + + Assert.Equal("services", exception.ParamName); + } + + [Fact] + public void ReplaceDefaultEntities_EntitiesAreCorrectlyReplaced() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.ReplaceDefaultEntities(); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal(typeof(CustomApplication), options.DefaultApplicationType); + Assert.Equal(typeof(CustomAuthorization), options.DefaultAuthorizationType); + Assert.Equal(typeof(CustomScope), options.DefaultScopeType); + Assert.Equal(typeof(CustomToken), options.DefaultTokenType); + } + + [Fact] + public void UseDbContext_ThrowsAnExceptionForNullType() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(delegate + { + return builder.UseDbContext(type: null); + }); + + Assert.Equal("type", exception.ParamName); + } + + [Fact] + public void UseDbContext_ThrowsAnExceptionForInvalidType() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(delegate + { + return builder.UseDbContext(typeof(object)); + }); + + Assert.Equal("type", exception.ParamName); + Assert.StartsWith("The specified type is invalid.", exception.Message); + } + + [Fact] + public void UseDbContext_RegistersDbContextAsScopedService() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.UseDbContext(); + + // Assert + Assert.Contains(services, service => service.Lifetime == ServiceLifetime.Scoped && + service.ServiceType == typeof(CustomDbContext) && + service.ImplementationType == typeof(CustomDbContext)); + } + + [Fact] + public void UseDbContext_SetsDbContextTypeInOptions() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.UseDbContext(); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal(typeof(CustomDbContext), options.DbContextType); + } + + private static OpenIddictEntityFrameworkBuilder CreateBuilder(IServiceCollection services) + => services.AddOpenIddict().AddCore().UseEntityFramework(); + + private static IServiceCollection CreateServices() + { + var services = new ServiceCollection(); + services.AddOptions(); + + return services; + } + + public class CustomApplication : OpenIddictApplication { } + public class CustomAuthorization : OpenIddictAuthorization { } + public class CustomScope : OpenIddictScope { } + public class CustomToken : OpenIddictToken { } + + public class CustomDbContext : DbContext + { + public CustomDbContext(string nameOrConnectionString) + : base(nameOrConnectionString) + { + } + } + } +} diff --git a/test/OpenIddict.EntityFramework.Tests/OpenIddictEntityFrameworkExtensionsTests.cs b/test/OpenIddict.EntityFramework.Tests/OpenIddictEntityFrameworkExtensionsTests.cs index 536b0ea3..2cce2c78 100644 --- a/test/OpenIddict.EntityFramework.Tests/OpenIddictEntityFrameworkExtensionsTests.cs +++ b/test/OpenIddict.EntityFramework.Tests/OpenIddictEntityFrameworkExtensionsTests.cs @@ -5,8 +5,10 @@ */ using System; +using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using OpenIddict.Abstractions; using OpenIddict.Core; using OpenIddict.EntityFramework.Models; using Xunit; @@ -15,26 +17,47 @@ namespace OpenIddict.EntityFramework.Tests { public class OpenIddictEntityFrameworkExtensionsTests { - [Theory] - [InlineData(typeof(OpenIddictApplicationStoreResolver))] - [InlineData(typeof(OpenIddictAuthorizationStoreResolver))] - [InlineData(typeof(OpenIddictScopeStoreResolver))] - [InlineData(typeof(OpenIddictTokenStoreResolver))] - public void AddEntityFrameworkStores_RegistersEntityFrameworkStoreFactories(Type type) + [Fact] + public void UseEntityFramework_ThrowsAnExceptionForNullBuilder() { // Arrange - var services = new ServiceCollection().AddOptions(); + var builder = (OpenIddictCoreBuilder) null; + + // Act and assert + var exception = Assert.Throws(() => builder.UseEntityFramework()); + + Assert.Equal("builder", exception.ParamName); + } + + [Fact] + public void UseEntityFramework_ThrowsAnExceptionForNullConfiguration() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictCoreBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.UseEntityFramework(configuration: null)); + + Assert.Equal("configuration", exception.ParamName); + } + + [Fact] + public void UseEntityFramework_RegistersCachingServices() + { + // Arrange + var services = new ServiceCollection(); var builder = new OpenIddictCoreBuilder(services); // Act builder.UseEntityFramework(); // Assert - Assert.Contains(services, service => service.ImplementationType == type); + Assert.Contains(services, service => service.ServiceType == typeof(IMemoryCache)); } [Fact] - public void UseEntityFrameworkModels_KeyTypeDefaultsToString() + public void UseEntityFramework_RegistersDefaultEntities() { // Arrange var services = new ServiceCollection().AddOptions(); @@ -52,5 +75,42 @@ namespace OpenIddict.EntityFramework.Tests Assert.Equal(typeof(OpenIddictScope), options.DefaultScopeType); Assert.Equal(typeof(OpenIddictToken), options.DefaultTokenType); } + + [Theory] + [InlineData(typeof(IOpenIddictApplicationStoreResolver), typeof(OpenIddictApplicationStoreResolver))] + [InlineData(typeof(IOpenIddictAuthorizationStoreResolver), typeof(OpenIddictAuthorizationStoreResolver))] + [InlineData(typeof(IOpenIddictScopeStoreResolver), typeof(OpenIddictScopeStoreResolver))] + [InlineData(typeof(IOpenIddictTokenStoreResolver), typeof(OpenIddictTokenStoreResolver))] + public void UseEntityFramework_RegistersEntityFrameworkStoreResolvers(Type serviceType, Type implementationType) + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictCoreBuilder(services); + + // Act + builder.UseEntityFramework(); + + // Assert + Assert.Contains(services, service => service.ServiceType == serviceType && + service.ImplementationType == implementationType); + } + + [Theory] + [InlineData(typeof(OpenIddictApplicationStore<,,,,>))] + [InlineData(typeof(OpenIddictAuthorizationStore<,,,,>))] + [InlineData(typeof(OpenIddictScopeStore<,,>))] + [InlineData(typeof(OpenIddictTokenStore<,,,,>))] + public void UseEntityFramework_RegistersEntityFrameworkStore(Type type) + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictCoreBuilder(services); + + // Act + builder.UseEntityFramework(); + + // Assert + Assert.Contains(services, service => service.ServiceType == type && service.ImplementationType == type); + } } } diff --git a/test/OpenIddict.EntityFramework.Tests/Resolvers/OpenIddictApplicationStoreResolverTests.cs b/test/OpenIddict.EntityFramework.Tests/Resolvers/OpenIddictApplicationStoreResolverTests.cs new file mode 100644 index 00000000..4ee59a3b --- /dev/null +++ b/test/OpenIddict.EntityFramework.Tests/Resolvers/OpenIddictApplicationStoreResolverTests.cs @@ -0,0 +1,117 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Data.Entity; +using System.Text; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Moq; +using OpenIddict.Abstractions; +using OpenIddict.EntityFramework.Models; +using Xunit; + +namespace OpenIddict.EntityFramework.Tests +{ + public class OpenIddictApplicationStoreResolverTests + { + [Fact] + public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictApplicationStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + [Fact] + public void Get_ThrowsAnExceptionForInvalidEntityType() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictApplicationStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("The specified application type is not compatible with the Entity Framework 6.x stores.") + .Append("When enabling the Entity Framework 6.x stores, make sure you use the built-in ") + .Append("'OpenIddictApplication' entity (from the 'OpenIddict.EntityFramework.Models' package) ") + .Append("or a custom entity that inherits from the generic 'OpenIddictApplication' entity.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ThrowsAnExceptionWhenDbContextTypeIsNotAvailable() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkOptions + { + DbContextType = null + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictApplicationStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("No Entity Framework 6.x context was specified in the OpenIddict options.") + .Append("To configure the OpenIddict Entity Framework 6.x stores to use a specific 'DbContext', ") + .Append("use 'options.UseEntityFramework().UseDbContext()'.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ReturnsDefaultStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + services.AddSingleton(CreateStore()); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkOptions + { + DbContextType = typeof(DbContext) + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictApplicationStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + private static OpenIddictApplicationStore CreateStore() + => new Mock>( + Mock.Of(), + Mock.Of(), + Mock.Of>()).Object; + + public class CustomApplication { } + + public class MyApplication : OpenIddictApplication { } + public class MyAuthorization : OpenIddictAuthorization { } + public class MyScope : OpenIddictScope { } + public class MyToken : OpenIddictToken { } + } +} diff --git a/test/OpenIddict.EntityFramework.Tests/Resolvers/OpenIddictAuthorizationStoreResolverTests.cs b/test/OpenIddict.EntityFramework.Tests/Resolvers/OpenIddictAuthorizationStoreResolverTests.cs new file mode 100644 index 00000000..d6a37585 --- /dev/null +++ b/test/OpenIddict.EntityFramework.Tests/Resolvers/OpenIddictAuthorizationStoreResolverTests.cs @@ -0,0 +1,117 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Data.Entity; +using System.Text; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Moq; +using OpenIddict.Abstractions; +using OpenIddict.EntityFramework.Models; +using Xunit; + +namespace OpenIddict.EntityFramework.Tests +{ + public class OpenIddictAuthorizationStoreResolverTests + { + [Fact] + public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictAuthorizationStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + [Fact] + public void Get_ThrowsAnExceptionForInvalidEntityType() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictAuthorizationStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("The specified authorization type is not compatible with the Entity Framework 6.x stores.") + .Append("When enabling the Entity Framework 6.x stores, make sure you use the built-in ") + .Append("'OpenIddictAuthorization' entity (from the 'OpenIddict.EntityFramework.Models' package) ") + .Append("or a custom entity that inherits from the generic 'OpenIddictAuthorization' entity.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ThrowsAnExceptionWhenDbContextTypeIsNotAvailable() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkOptions + { + DbContextType = null + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictAuthorizationStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("No Entity Framework 6.x context was specified in the OpenIddict options.") + .Append("To configure the OpenIddict Entity Framework 6.x stores to use a specific 'DbContext', ") + .Append("use 'options.UseEntityFramework().UseDbContext()'.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ReturnsDefaultStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + services.AddSingleton(CreateStore()); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkOptions + { + DbContextType = typeof(DbContext) + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictAuthorizationStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + private static OpenIddictAuthorizationStore CreateStore() + => new Mock>( + Mock.Of(), + Mock.Of(), + Mock.Of>()).Object; + + public class CustomAuthorization { } + + public class MyApplication : OpenIddictApplication { } + public class MyAuthorization : OpenIddictAuthorization { } + public class MyScope : OpenIddictScope { } + public class MyToken : OpenIddictToken { } + } +} diff --git a/test/OpenIddict.EntityFramework.Tests/Resolvers/OpenIddictScopeStoreResolverTests.cs b/test/OpenIddict.EntityFramework.Tests/Resolvers/OpenIddictScopeStoreResolverTests.cs new file mode 100644 index 00000000..2e158a0c --- /dev/null +++ b/test/OpenIddict.EntityFramework.Tests/Resolvers/OpenIddictScopeStoreResolverTests.cs @@ -0,0 +1,117 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Data.Entity; +using System.Text; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Moq; +using OpenIddict.Abstractions; +using OpenIddict.EntityFramework.Models; +using Xunit; + +namespace OpenIddict.EntityFramework.Tests +{ + public class OpenIddictScopeStoreResolverTests + { + [Fact] + public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictScopeStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + [Fact] + public void Get_ThrowsAnExceptionForInvalidEntityType() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictScopeStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("The specified scope type is not compatible with the Entity Framework 6.x stores.") + .Append("When enabling the Entity Framework 6.x stores, make sure you use the built-in ") + .Append("'OpenIddictScope' entity (from the 'OpenIddict.EntityFramework.Models' package) ") + .Append("or a custom entity that inherits from the generic 'OpenIddictScope' entity.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ThrowsAnExceptionWhenDbContextTypeIsNotAvailable() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkOptions + { + DbContextType = null + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictScopeStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("No Entity Framework 6.x context was specified in the OpenIddict options.") + .Append("To configure the OpenIddict Entity Framework 6.x stores to use a specific 'DbContext', ") + .Append("use 'options.UseEntityFramework().UseDbContext()'.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ReturnsDefaultStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + services.AddSingleton(CreateStore()); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkOptions + { + DbContextType = typeof(DbContext) + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictScopeStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + private static OpenIddictScopeStore CreateStore() + => new Mock>( + Mock.Of(), + Mock.Of(), + Mock.Of>()).Object; + + public class CustomScope { } + + public class MyApplication : OpenIddictApplication { } + public class MyAuthorization : OpenIddictAuthorization { } + public class MyScope : OpenIddictScope { } + public class MyToken : OpenIddictToken { } + } +} diff --git a/test/OpenIddict.EntityFramework.Tests/Resolvers/OpenIddictTokenStoreResolverTests.cs b/test/OpenIddict.EntityFramework.Tests/Resolvers/OpenIddictTokenStoreResolverTests.cs new file mode 100644 index 00000000..c4c7d884 --- /dev/null +++ b/test/OpenIddict.EntityFramework.Tests/Resolvers/OpenIddictTokenStoreResolverTests.cs @@ -0,0 +1,117 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Data.Entity; +using System.Text; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Moq; +using OpenIddict.Abstractions; +using OpenIddict.EntityFramework.Models; +using Xunit; + +namespace OpenIddict.EntityFramework.Tests +{ + public class OpenIddictTokenStoreResolverTests + { + [Fact] + public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictTokenStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + [Fact] + public void Get_ThrowsAnExceptionForInvalidEntityType() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictTokenStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("The specified token type is not compatible with the Entity Framework 6.x stores.") + .Append("When enabling the Entity Framework 6.x stores, make sure you use the built-in ") + .Append("'OpenIddictToken' entity (from the 'OpenIddict.EntityFramework.Models' package) ") + .Append("or a custom entity that inherits from the generic 'OpenIddictToken' entity.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ThrowsAnExceptionWhenDbContextTypeIsNotAvailable() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkOptions + { + DbContextType = null + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictTokenStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("No Entity Framework 6.x context was specified in the OpenIddict options.") + .Append("To configure the OpenIddict Entity Framework 6.x stores to use a specific 'DbContext', ") + .Append("use 'options.UseEntityFramework().UseDbContext()'.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ReturnsDefaultStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + services.AddSingleton(CreateStore()); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkOptions + { + DbContextType = typeof(DbContext) + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictTokenStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + private static OpenIddictTokenStore CreateStore() + => new Mock>( + Mock.Of(), + Mock.Of(), + Mock.Of>()).Object; + + public class CustomToken { } + + public class MyApplication : OpenIddictApplication { } + public class MyAuthorization : OpenIddictAuthorization { } + public class MyScope : OpenIddictScope { } + public class MyToken : OpenIddictToken { } + } +} diff --git a/test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictEntityFrameworkCoreBuilderTests.cs b/test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictEntityFrameworkCoreBuilderTests.cs new file mode 100644 index 00000000..e14cbb39 --- /dev/null +++ b/test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictEntityFrameworkCoreBuilderTests.cs @@ -0,0 +1,145 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using OpenIddict.Core; +using OpenIddict.EntityFrameworkCore.Models; +using Xunit; + +namespace OpenIddict.EntityFrameworkCore.Tests +{ + public class OpenIddictEntityFrameworkCoreBuilderTests + { + [Fact] + public void Constructor_ThrowsAnExceptionForNullServices() + { + // Arrange + var services = (IServiceCollection) null; + + // Act and assert + var exception = Assert.Throws(() => new OpenIddictEntityFrameworkCoreBuilder(services)); + + Assert.Equal("services", exception.ParamName); + } + + [Fact] + public void ReplaceDefaultEntities_EntitiesAreCorrectlyReplaced() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.ReplaceDefaultEntities(); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal(typeof(CustomApplication), options.DefaultApplicationType); + Assert.Equal(typeof(CustomAuthorization), options.DefaultAuthorizationType); + Assert.Equal(typeof(CustomScope), options.DefaultScopeType); + Assert.Equal(typeof(CustomToken), options.DefaultTokenType); + } + + [Fact] + public void ReplaceDefaultEntities_AllowsSpecifyingCustomKeyType() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.ReplaceDefaultEntities(); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal(typeof(OpenIddictApplication), options.DefaultApplicationType); + Assert.Equal(typeof(OpenIddictAuthorization), options.DefaultAuthorizationType); + Assert.Equal(typeof(OpenIddictScope), options.DefaultScopeType); + Assert.Equal(typeof(OpenIddictToken), options.DefaultTokenType); + } + + [Fact] + public void UseDbContext_ThrowsAnExceptionForNullType() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(delegate + { + return builder.UseDbContext(type: null); + }); + + Assert.Equal("type", exception.ParamName); + } + + [Fact] + public void UseDbContext_ThrowsAnExceptionForInvalidType() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(delegate + { + return builder.UseDbContext(typeof(object)); + }); + + Assert.Equal("type", exception.ParamName); + Assert.StartsWith("The specified type is invalid.", exception.Message); + } + + [Fact] + public void UseDbContext_SetsDbContextTypeInOptions() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.UseDbContext(); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal(typeof(CustomDbContext), options.DbContextType); + } + + private static OpenIddictEntityFrameworkCoreBuilder CreateBuilder(IServiceCollection services) + => services.AddOpenIddict().AddCore().UseEntityFrameworkCore(); + + private static IServiceCollection CreateServices() + { + var services = new ServiceCollection(); + services.AddOptions(); + + return services; + } + + public class CustomApplication : OpenIddictApplication { } + public class CustomAuthorization : OpenIddictAuthorization { } + public class CustomScope : OpenIddictScope { } + public class CustomToken : OpenIddictToken { } + + public class CustomDbContext : DbContext + { + public CustomDbContext(DbContextOptions options) + : base(options) + { + } + } + } +} diff --git a/test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictEntityFrameworkCoreExtensionsTests.cs b/test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictEntityFrameworkCoreExtensionsTests.cs index 36d548ad..1ce3e2e0 100644 --- a/test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictEntityFrameworkCoreExtensionsTests.cs +++ b/test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictEntityFrameworkCoreExtensionsTests.cs @@ -5,8 +5,10 @@ */ using System; +using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using OpenIddict.Abstractions; using OpenIddict.Core; using OpenIddict.EntityFrameworkCore.Models; using Xunit; @@ -15,26 +17,47 @@ namespace OpenIddict.EntityFrameworkCore.Tests { public class OpenIddictEntityFrameworkCoreExtensionsTests { - [Theory] - [InlineData(typeof(OpenIddictApplicationStoreResolver))] - [InlineData(typeof(OpenIddictAuthorizationStoreResolver))] - [InlineData(typeof(OpenIddictScopeStoreResolver))] - [InlineData(typeof(OpenIddictTokenStoreResolver))] - public void UseEntityFrameworkCore_RegistersEntityFrameworkCoreStoreFactories(Type type) + [Fact] + public void UseEntityFrameworkCore_ThrowsAnExceptionForNullBuilder() { // Arrange - var services = new ServiceCollection().AddOptions(); + var builder = (OpenIddictCoreBuilder) null; + + // Act and assert + var exception = Assert.Throws(() => builder.UseEntityFrameworkCore()); + + Assert.Equal("builder", exception.ParamName); + } + + [Fact] + public void UseEntityFrameworkCore_ThrowsAnExceptionForNullConfiguration() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictCoreBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.UseEntityFrameworkCore(configuration: null)); + + Assert.Equal("configuration", exception.ParamName); + } + + [Fact] + public void UseEntityFrameworkCore_RegistersCachingServices() + { + // Arrange + var services = new ServiceCollection(); var builder = new OpenIddictCoreBuilder(services); // Act builder.UseEntityFrameworkCore(); // Assert - Assert.Contains(services, service => service.ImplementationType == type); + Assert.Contains(services, service => service.ServiceType == typeof(IMemoryCache)); } [Fact] - public void UseEntityFrameworkCore_KeyTypeDefaultsToString() + public void UseEntityFrameworkCore_RegistersDefaultEntities() { // Arrange var services = new ServiceCollection().AddOptions(); @@ -53,24 +76,41 @@ namespace OpenIddict.EntityFrameworkCore.Tests Assert.Equal(typeof(OpenIddictToken), options.DefaultTokenType); } - [Fact] - public void UseEntityFrameworkCore_KeyTypeCanBeOverriden() + [Theory] + [InlineData(typeof(IOpenIddictApplicationStoreResolver), typeof(OpenIddictApplicationStoreResolver))] + [InlineData(typeof(IOpenIddictAuthorizationStoreResolver), typeof(OpenIddictAuthorizationStoreResolver))] + [InlineData(typeof(IOpenIddictScopeStoreResolver), typeof(OpenIddictScopeStoreResolver))] + [InlineData(typeof(IOpenIddictTokenStoreResolver), typeof(OpenIddictTokenStoreResolver))] + public void UseEntityFrameworkCore_RegistersEntityFrameworkCoreStoreResolvers(Type serviceType, Type implementationType) { // Arrange - var services = new ServiceCollection().AddOptions(); + var services = new ServiceCollection(); var builder = new OpenIddictCoreBuilder(services); // Act - builder.UseEntityFrameworkCore().ReplaceDefaultEntities(); + builder.UseEntityFrameworkCore(); // Assert - var provider = services.BuildServiceProvider(); - var options = provider.GetRequiredService>().CurrentValue; + Assert.Contains(services, service => service.ServiceType == serviceType && + service.ImplementationType == implementationType); + } - Assert.Equal(typeof(OpenIddictApplication), options.DefaultApplicationType); - Assert.Equal(typeof(OpenIddictAuthorization), options.DefaultAuthorizationType); - Assert.Equal(typeof(OpenIddictScope), options.DefaultScopeType); - Assert.Equal(typeof(OpenIddictToken), options.DefaultTokenType); + [Theory] + [InlineData(typeof(OpenIddictApplicationStore<,,,,>))] + [InlineData(typeof(OpenIddictAuthorizationStore<,,,,>))] + [InlineData(typeof(OpenIddictScopeStore<,,>))] + [InlineData(typeof(OpenIddictTokenStore<,,,,>))] + public void UseEntityFrameworkCore_RegistersEntityFrameworkCoreStore(Type type) + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictCoreBuilder(services); + + // Act + builder.UseEntityFrameworkCore(); + + // Assert + Assert.Contains(services, service => service.ServiceType == type && service.ImplementationType == type); } } } diff --git a/test/OpenIddict.EntityFrameworkCore.Tests/Resolvers/OpenIddictApplicationStoreResolverTests.cs b/test/OpenIddict.EntityFrameworkCore.Tests/Resolvers/OpenIddictApplicationStoreResolverTests.cs new file mode 100644 index 00000000..87c84b7d --- /dev/null +++ b/test/OpenIddict.EntityFrameworkCore.Tests/Resolvers/OpenIddictApplicationStoreResolverTests.cs @@ -0,0 +1,117 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Text; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Moq; +using OpenIddict.Abstractions; +using OpenIddict.EntityFrameworkCore.Models; +using Xunit; + +namespace OpenIddict.EntityFrameworkCore.Tests +{ + public class OpenIddictApplicationStoreResolverTests + { + [Fact] + public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictApplicationStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + [Fact] + public void Get_ThrowsAnExceptionForInvalidEntityType() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictApplicationStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("The specified application type is not compatible with the Entity Framework Core stores.") + .Append("When enabling the Entity Framework Core stores, make sure you use the built-in ") + .Append("'OpenIddictApplication' entity (from the 'OpenIddict.EntityFrameworkCore.Models' package) ") + .Append("or a custom entity that inherits from the generic 'OpenIddictApplication' entity.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ThrowsAnExceptionWhenDbContextTypeIsNotAvailable() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkCoreOptions + { + DbContextType = null + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictApplicationStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("No Entity Framework Core context was specified in the OpenIddict options.") + .Append("To configure the OpenIddict Entity Framework Core stores to use a specific 'DbContext', ") + .Append("use 'options.UseEntityFrameworkCore().UseDbContext()'.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ReturnsDefaultStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + services.AddSingleton(CreateStore()); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkCoreOptions + { + DbContextType = typeof(DbContext) + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictApplicationStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + private static OpenIddictApplicationStore CreateStore() + => new Mock>( + Mock.Of(), + Mock.Of(), + Mock.Of>()).Object; + + public class CustomApplication { } + + public class MyApplication : OpenIddictApplication { } + public class MyAuthorization : OpenIddictAuthorization { } + public class MyScope : OpenIddictScope { } + public class MyToken : OpenIddictToken { } + } +} diff --git a/test/OpenIddict.EntityFrameworkCore.Tests/Resolvers/OpenIddictAuthorizationStoreResolverTests.cs b/test/OpenIddict.EntityFrameworkCore.Tests/Resolvers/OpenIddictAuthorizationStoreResolverTests.cs new file mode 100644 index 00000000..376c91f8 --- /dev/null +++ b/test/OpenIddict.EntityFrameworkCore.Tests/Resolvers/OpenIddictAuthorizationStoreResolverTests.cs @@ -0,0 +1,117 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Text; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Moq; +using OpenIddict.Abstractions; +using OpenIddict.EntityFrameworkCore.Models; +using Xunit; + +namespace OpenIddict.EntityFrameworkCore.Tests +{ + public class OpenIddictAuthorizationStoreResolverTests + { + [Fact] + public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictAuthorizationStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + [Fact] + public void Get_ThrowsAnExceptionForInvalidEntityType() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictAuthorizationStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("The specified authorization type is not compatible with the Entity Framework Core stores.") + .Append("When enabling the Entity Framework Core stores, make sure you use the built-in ") + .Append("'OpenIddictAuthorization' entity (from the 'OpenIddict.EntityFrameworkCore.Models' package) ") + .Append("or a custom entity that inherits from the generic 'OpenIddictAuthorization' entity.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ThrowsAnExceptionWhenDbContextTypeIsNotAvailable() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkCoreOptions + { + DbContextType = null + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictAuthorizationStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("No Entity Framework Core context was specified in the OpenIddict options.") + .Append("To configure the OpenIddict Entity Framework Core stores to use a specific 'DbContext', ") + .Append("use 'options.UseEntityFrameworkCore().UseDbContext()'.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ReturnsDefaultStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + services.AddSingleton(CreateStore()); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkCoreOptions + { + DbContextType = typeof(DbContext) + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictAuthorizationStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + private static OpenIddictAuthorizationStore CreateStore() + => new Mock>( + Mock.Of(), + Mock.Of(), + Mock.Of>()).Object; + + public class CustomAuthorization { } + + public class MyApplication : OpenIddictApplication { } + public class MyAuthorization : OpenIddictAuthorization { } + public class MyScope : OpenIddictScope { } + public class MyToken : OpenIddictToken { } + } +} diff --git a/test/OpenIddict.EntityFrameworkCore.Tests/Resolvers/OpenIddictScopeStoreResolverTests.cs b/test/OpenIddict.EntityFrameworkCore.Tests/Resolvers/OpenIddictScopeStoreResolverTests.cs new file mode 100644 index 00000000..dde22e58 --- /dev/null +++ b/test/OpenIddict.EntityFrameworkCore.Tests/Resolvers/OpenIddictScopeStoreResolverTests.cs @@ -0,0 +1,117 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Text; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Moq; +using OpenIddict.Abstractions; +using OpenIddict.EntityFrameworkCore.Models; +using Xunit; + +namespace OpenIddict.EntityFrameworkCore.Tests +{ + public class OpenIddictScopeStoreResolverTests + { + [Fact] + public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictScopeStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + [Fact] + public void Get_ThrowsAnExceptionForInvalidEntityType() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictScopeStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("The specified scope type is not compatible with the Entity Framework Core stores.") + .Append("When enabling the Entity Framework Core stores, make sure you use the built-in ") + .Append("'OpenIddictScope' entity (from the 'OpenIddict.EntityFrameworkCore.Models' package) ") + .Append("or a custom entity that inherits from the generic 'OpenIddictScope' entity.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ThrowsAnExceptionWhenDbContextTypeIsNotAvailable() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkCoreOptions + { + DbContextType = null + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictScopeStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("No Entity Framework Core context was specified in the OpenIddict options.") + .Append("To configure the OpenIddict Entity Framework Core stores to use a specific 'DbContext', ") + .Append("use 'options.UseEntityFrameworkCore().UseDbContext()'.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ReturnsDefaultStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + services.AddSingleton(CreateStore()); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkCoreOptions + { + DbContextType = typeof(DbContext) + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictScopeStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + private static OpenIddictScopeStore CreateStore() + => new Mock>( + Mock.Of(), + Mock.Of(), + Mock.Of>()).Object; + + public class CustomScope { } + + public class MyApplication : OpenIddictApplication { } + public class MyAuthorization : OpenIddictAuthorization { } + public class MyScope : OpenIddictScope { } + public class MyToken : OpenIddictToken { } + } +} diff --git a/test/OpenIddict.EntityFrameworkCore.Tests/Resolvers/OpenIddictTokenStoreResolverTests.cs b/test/OpenIddict.EntityFrameworkCore.Tests/Resolvers/OpenIddictTokenStoreResolverTests.cs new file mode 100644 index 00000000..baf0ffba --- /dev/null +++ b/test/OpenIddict.EntityFrameworkCore.Tests/Resolvers/OpenIddictTokenStoreResolverTests.cs @@ -0,0 +1,117 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Text; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Moq; +using OpenIddict.Abstractions; +using OpenIddict.EntityFrameworkCore.Models; +using Xunit; + +namespace OpenIddict.EntityFrameworkCore.Tests +{ + public class OpenIddictTokenStoreResolverTests + { + [Fact] + public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictTokenStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + [Fact] + public void Get_ThrowsAnExceptionForInvalidEntityType() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>(); + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictTokenStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("The specified token type is not compatible with the Entity Framework Core stores.") + .Append("When enabling the Entity Framework Core stores, make sure you use the built-in ") + .Append("'OpenIddictToken' entity (from the 'OpenIddict.EntityFrameworkCore.Models' package) ") + .Append("or a custom entity that inherits from the generic 'OpenIddictToken' entity.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ThrowsAnExceptionWhenDbContextTypeIsNotAvailable() + { + // Arrange + var services = new ServiceCollection(); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkCoreOptions + { + DbContextType = null + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictTokenStoreResolver(monitor, provider); + + // Act and assert + var exception = Assert.Throws(() => resolver.Get()); + + Assert.Equal(new StringBuilder() + .AppendLine("No Entity Framework Core context was specified in the OpenIddict options.") + .Append("To configure the OpenIddict Entity Framework Core stores to use a specific 'DbContext', ") + .Append("use 'options.UseEntityFrameworkCore().UseDbContext()'.") + .ToString(), exception.Message); + } + + [Fact] + public void Get_ReturnsDefaultStoreCorrespondingToTheSpecifiedTypeWhenAvailable() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(Mock.Of>()); + services.AddSingleton(CreateStore()); + + var monitor = Mock.Of>( + mock => mock.CurrentValue == new OpenIddictEntityFrameworkCoreOptions + { + DbContextType = typeof(DbContext) + }); + + var provider = services.BuildServiceProvider(); + var resolver = new OpenIddictTokenStoreResolver(monitor, provider); + + // Act and assert + Assert.NotNull(resolver.Get()); + } + + private static OpenIddictTokenStore CreateStore() + => new Mock>( + Mock.Of(), + Mock.Of(), + Mock.Of>()).Object; + + public class CustomToken { } + + public class MyApplication : OpenIddictApplication { } + public class MyAuthorization : OpenIddictAuthorization { } + public class MyScope : OpenIddictScope { } + public class MyToken : OpenIddictToken { } + } +} diff --git a/test/OpenIddict.MongoDb.Tests/OpenIddict.MongoDb.Tests.csproj b/test/OpenIddict.MongoDb.Tests/OpenIddict.MongoDb.Tests.csproj new file mode 100644 index 00000000..dbf18a60 --- /dev/null +++ b/test/OpenIddict.MongoDb.Tests/OpenIddict.MongoDb.Tests.csproj @@ -0,0 +1,26 @@ + + + + + + netcoreapp2.0;net461 + netcoreapp2.0 + + + + + + + + + + + + + + + + + + + diff --git a/test/OpenIddict.MongoDb.Tests/OpenIddictMongoDbBuilderTests.cs b/test/OpenIddict.MongoDb.Tests/OpenIddictMongoDbBuilderTests.cs new file mode 100644 index 00000000..ac84a99d --- /dev/null +++ b/test/OpenIddict.MongoDb.Tests/OpenIddictMongoDbBuilderTests.cs @@ -0,0 +1,282 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using MongoDB.Driver; +using Moq; +using OpenIddict.Core; +using OpenIddict.MongoDb.Models; +using Xunit; + +namespace OpenIddict.MongoDb.Tests +{ + public class OpenIddictMongoDbBuilderTests + { + [Fact] + public void Constructor_ThrowsAnExceptionForNullServices() + { + // Arrange + var services = (IServiceCollection) null; + + // Act and assert + var exception = Assert.Throws(() => new OpenIddictMongoDbBuilder(services)); + + Assert.Equal("services", exception.ParamName); + } + + [Fact] + public void ReplaceDefaultApplicationEntity_EntityIsCorrectlySet() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.ReplaceDefaultApplicationEntity(); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal(typeof(CustomApplication), options.DefaultApplicationType); + } + + [Fact] + public void ReplaceDefaultAuthorizationEntity_EntityIsCorrectlySet() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.ReplaceDefaultAuthorizationEntity(); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal(typeof(CustomAuthorization), options.DefaultAuthorizationType); + } + + [Fact] + public void ReplaceDefaultScopeEntity_EntityIsCorrectlySet() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.ReplaceDefaultScopeEntity(); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal(typeof(CustomScope), options.DefaultScopeType); + } + + [Fact] + public void ReplaceDefaultTokenEntity_EntityIsCorrectlySet() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.ReplaceDefaultTokenEntity(); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal(typeof(CustomToken), options.DefaultTokenType); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + public void SetApplicationsCollectionName_ThrowsAnExceptionForNullOrEmptyCollectionName(string name) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.SetApplicationsCollectionName(name)); + + Assert.Equal("name", exception.ParamName); + Assert.StartsWith("The collection name cannot be null or empty.", exception.Message); + } + + [Fact] + public void SetApplicationsCollectionName_CollectionNameIsCorrectlySet() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.SetApplicationsCollectionName("custom_collection"); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal("custom_collection", options.ApplicationsCollectionName); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + public void SetAuthorizationsCollectionName_ThrowsAnExceptionForNullOrEmptyCollectionName(string name) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.SetAuthorizationsCollectionName(name)); + + Assert.Equal("name", exception.ParamName); + Assert.StartsWith("The collection name cannot be null or empty.", exception.Message); + } + + [Fact] + public void SetAuthorizationsCollectionName_CollectionNameIsCorrectlySet() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.SetAuthorizationsCollectionName("custom_collection"); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal("custom_collection", options.AuthorizationsCollectionName); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + public void SetScopesCollectionName_ThrowsAnExceptionForNullOrEmptyCollectionName(string name) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.SetScopesCollectionName(name)); + + Assert.Equal("name", exception.ParamName); + Assert.StartsWith("The collection name cannot be null or empty.", exception.Message); + } + + [Fact] + public void SetScopesCollectionName_CollectionNameIsCorrectlySet() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.SetScopesCollectionName("custom_collection"); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal("custom_collection", options.ScopesCollectionName); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + public void SetTokensCollectionName_ThrowsAnExceptionForNullOrEmptyCollectionName(string name) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.SetTokensCollectionName(name)); + + Assert.Equal("name", exception.ParamName); + Assert.StartsWith("The collection name cannot be null or empty.", exception.Message); + } + + [Fact] + public void SetTokensCollectionName_CollectionNameIsCorrectlySet() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act + builder.SetTokensCollectionName("custom_collection"); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal("custom_collection", options.TokensCollectionName); + } + + [Fact] + public void UseDatabase_ThrowsAnExceptionForNullDatabase() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(delegate + { + return builder.UseDatabase(database: null); + }); + + Assert.Equal("database", exception.ParamName); + } + + [Fact] + public void UseDatabase_SetsDatabaseInOptions() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + var database = Mock.Of(); + + // Act + builder.UseDatabase(database); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal(database, options.Database); + } + + private static OpenIddictMongoDbBuilder CreateBuilder(IServiceCollection services) + => services.AddOpenIddict().AddCore().UseMongoDb(); + + private static IServiceCollection CreateServices() + { + var services = new ServiceCollection(); + services.AddOptions(); + + return services; + } + + public class CustomApplication : OpenIddictApplication { } + public class CustomAuthorization : OpenIddictAuthorization { } + public class CustomScope : OpenIddictScope { } + public class CustomToken : OpenIddictToken { } + } +} diff --git a/test/OpenIddict.MongoDb.Tests/OpenIddictMongoDbExtensionsTests.cs b/test/OpenIddict.MongoDb.Tests/OpenIddictMongoDbExtensionsTests.cs new file mode 100644 index 00000000..fa7bc1fd --- /dev/null +++ b/test/OpenIddict.MongoDb.Tests/OpenIddictMongoDbExtensionsTests.cs @@ -0,0 +1,132 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using OpenIddict.Abstractions; +using OpenIddict.Core; +using OpenIddict.MongoDb.Models; +using Xunit; + +namespace OpenIddict.MongoDb.Tests +{ + public class OpenIddictMongoDbExtensionsTests + { + [Fact] + public void UseMongoDb_ThrowsAnExceptionForNullBuilder() + { + // Arrange + var builder = (OpenIddictCoreBuilder) null; + + // Act and assert + var exception = Assert.Throws(() => builder.UseMongoDb()); + + Assert.Equal("builder", exception.ParamName); + } + + [Fact] + public void UseMongoDb_ThrowsAnExceptionForNullConfiguration() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictCoreBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.UseMongoDb(configuration: null)); + + Assert.Equal("configuration", exception.ParamName); + } + + [Fact] + public void UseMongoDb_RegistersCachingServices() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictCoreBuilder(services); + + // Act + builder.UseMongoDb(); + + // Assert + Assert.Contains(services, service => service.ServiceType == typeof(IMemoryCache)); + } + + [Fact] + public void UseMongoDb_RegistersDefaultEntities() + { + // Arrange + var services = new ServiceCollection().AddOptions(); + var builder = new OpenIddictCoreBuilder(services); + + // Act + builder.UseMongoDb(); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().CurrentValue; + + Assert.Equal(typeof(OpenIddictApplication), options.DefaultApplicationType); + Assert.Equal(typeof(OpenIddictAuthorization), options.DefaultAuthorizationType); + Assert.Equal(typeof(OpenIddictScope), options.DefaultScopeType); + Assert.Equal(typeof(OpenIddictToken), options.DefaultTokenType); + } + + [Theory] + [InlineData(typeof(IOpenIddictApplicationStoreResolver), typeof(OpenIddictApplicationStoreResolver))] + [InlineData(typeof(IOpenIddictAuthorizationStoreResolver), typeof(OpenIddictAuthorizationStoreResolver))] + [InlineData(typeof(IOpenIddictScopeStoreResolver), typeof(OpenIddictScopeStoreResolver))] + [InlineData(typeof(IOpenIddictTokenStoreResolver), typeof(OpenIddictTokenStoreResolver))] + public void UseMongoDb_RegistersMongoDbStoreResolvers(Type serviceType, Type implementationType) + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictCoreBuilder(services); + + // Act + builder.UseMongoDb(); + + // Assert + Assert.Contains(services, service => service.ServiceType == serviceType && + service.ImplementationType == implementationType); + } + + [Theory] + [InlineData(typeof(OpenIddictApplicationStore<>))] + [InlineData(typeof(OpenIddictAuthorizationStore<>))] + [InlineData(typeof(OpenIddictScopeStore<>))] + [InlineData(typeof(OpenIddictTokenStore<>))] + public void UseMongoDb_RegistersMongoDbStore(Type type) + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictCoreBuilder(services); + + // Act + builder.UseMongoDb(); + + // Assert + Assert.Contains(services, service => service.ServiceType == type && service.ImplementationType == type); + } + + [Fact] + public void UseMongoDb_RegistersMongoDbContext() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictCoreBuilder(services); + + // Act + builder.UseMongoDb(); + + // Assert + Assert.Contains(services, service => service.Lifetime == ServiceLifetime.Singleton && + service.ServiceType == typeof(IOpenIddictMongoDbContext) && + service.ImplementationType == typeof(OpenIddictMongoDbContext)); + } + } +} diff --git a/test/OpenIddict.Mvc.Tests/OpenIddictMvcBuilderTests.cs b/test/OpenIddict.Mvc.Tests/OpenIddictMvcBuilderTests.cs index f8136342..dd579485 100644 --- a/test/OpenIddict.Mvc.Tests/OpenIddictMvcBuilderTests.cs +++ b/test/OpenIddict.Mvc.Tests/OpenIddictMvcBuilderTests.cs @@ -4,6 +4,7 @@ * the license and the contributors participating to this project. */ +using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Xunit; @@ -12,6 +13,18 @@ namespace OpenIddict.Mvc.Tests { public class OpenIddictMvcBuilderTests { + [Fact] + public void Constructor_ThrowsAnExceptionForNullServices() + { + // Arrange + var services = (IServiceCollection) null; + + // Act and assert + var exception = Assert.Throws(() => new OpenIddictMvcBuilder(services)); + + Assert.Equal("services", exception.ParamName); + } + [Fact] public void Configure_OptionsAreCorrectlyAmended() { diff --git a/test/OpenIddict.Mvc.Tests/OpenIddictMvcExtensionsTests.cs b/test/OpenIddict.Mvc.Tests/OpenIddictMvcExtensionsTests.cs index 233658f3..69ba0113 100644 --- a/test/OpenIddict.Mvc.Tests/OpenIddictMvcExtensionsTests.cs +++ b/test/OpenIddict.Mvc.Tests/OpenIddictMvcExtensionsTests.cs @@ -4,6 +4,7 @@ * the license and the contributors participating to this project. */ +using System; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -13,6 +14,31 @@ namespace OpenIddict.Mvc.Tests { public class OpenIddictMvcExtensionsTests { + [Fact] + public void UseMvc_ThrowsAnExceptionForNullBuilder() + { + // Arrange + var builder = (OpenIddictServerBuilder) null; + + // Act and assert + var exception = Assert.Throws(() => builder.UseMvc()); + + Assert.Equal("builder", exception.ParamName); + } + + [Fact] + public void UseMvc_ThrowsAnExceptionForNullConfiguration() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictServerBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.UseMvc(configuration: null)); + + Assert.Equal("configuration", exception.ParamName); + } + [Fact] public void UseMvc_RegistersModelBinderProvider() { diff --git a/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs b/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs index 752c4913..f30dbbbf 100644 --- a/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs +++ b/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs @@ -23,6 +23,18 @@ namespace OpenIddict.Server.Tests { public class OpenIddictServerBuilderTests { + [Fact] + public void Constructor_ThrowsAnExceptionForNullServices() + { + // Arrange + var services = (IServiceCollection) null; + + // Act and assert + var exception = Assert.Throws(() => new OpenIddictServerBuilder(services)); + + Assert.Equal("services", exception.ParamName); + } + [Fact] public void AddEventHandler_HandlerIsAttached() { diff --git a/test/OpenIddict.Server.Tests/OpenIddictServerExtensionsTests.cs b/test/OpenIddict.Server.Tests/OpenIddictServerExtensionsTests.cs new file mode 100644 index 00000000..7968897a --- /dev/null +++ b/test/OpenIddict.Server.Tests/OpenIddictServerExtensionsTests.cs @@ -0,0 +1,208 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using System.Text; +using AspNet.Security.OpenIdConnect.Server; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Xunit; + +namespace OpenIddict.Server.Tests +{ + public class OpenIddictServerExtensionsTests + { + [Fact] + public void AddServer_ThrowsAnExceptionForNullBuilder() + { + // Arrange + var builder = (OpenIddictBuilder) null; + + // Act and assert + var exception = Assert.Throws(() => builder.AddServer()); + + Assert.Equal("builder", exception.ParamName); + } + + [Fact] + public void AddServer_ThrowsAnExceptionForNullConfiguration() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.AddServer(configuration: null)); + + Assert.Equal("configuration", exception.ParamName); + } + + [Fact] + public void AddServer_RegistersAuthenticationServices() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddServer(); + + // Assert + Assert.Contains(services, service => service.ServiceType == typeof(IAuthenticationService)); + } + + [Fact] + public void AddServer_RegistersCachingServices() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddServer(); + + // Assert + Assert.Contains(services, service => service.ServiceType == typeof(IDistributedCache)); + Assert.Contains(services, service => service.ServiceType == typeof(IMemoryCache)); + } + + [Fact] + public void AddServer_RegistersLoggingServices() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddServer(); + + // Assert + Assert.Contains(services, service => service.ServiceType == typeof(ILogger<>)); + } + + [Fact] + public void AddServer_RegistersOptionsServices() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddServer(); + + // Assert + Assert.Contains(services, service => service.ServiceType == typeof(IOptions<>)); + } + + [Fact] + public void AddServer_RegistersEventService() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddServer(); + + // Assert + Assert.Contains(services, service => service.Lifetime == ServiceLifetime.Scoped && + service.ServiceType == typeof(IOpenIddictServerEventService) && + service.ImplementationType == typeof(OpenIddictServerEventService)); + } + + [Fact] + public void AddServer_RegistersHandler() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddServer(); + + // Assert + Assert.Contains(services, service => service.Lifetime == ServiceLifetime.Scoped && + service.ServiceType == typeof(OpenIddictServerHandler) && + service.ImplementationType == typeof(OpenIddictServerHandler)); + } + + [Fact] + public void AddServer_RegistersProvider() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddServer(); + + // Assert + Assert.Contains(services, service => service.Lifetime == ServiceLifetime.Scoped && + service.ServiceType == typeof(OpenIddictServerProvider) && + service.ImplementationFactory != null); + } + + [Fact] + public void AddServer_ResolvingProviderThrowsAnExceptionWhenCoreServicesAreNotRegistered() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddServer(); + + // Assert + var provider = services.BuildServiceProvider(); + + var exception = Assert.Throws(() => provider.GetRequiredService()); + + Assert.Equal(new StringBuilder() + .AppendLine("The core services must be registered when enabling the server handler.") + .Append("To register the OpenIddict core services, use 'services.AddOpenIddict().AddCore()'.") + .ToString(), exception.Message); + } + + [Theory] + [InlineData(typeof(IPostConfigureOptions), typeof(OpenIddictServerInitializer))] + [InlineData(typeof(IPostConfigureOptions), typeof(OpenIdConnectServerInitializer))] + public void AddServer_RegistersInitializers(Type serviceType, Type implementationType) + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddServer(); + + // Assert + Assert.Contains(services, service => service.ServiceType == serviceType && + service.ImplementationType == implementationType); + } + + [Fact] + public void AddServer_RegistersAuthenticationScheme() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddServer(); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().Value; + + Assert.Contains(options.Schemes, scheme => scheme.Name == OpenIddictServerDefaults.AuthenticationScheme && + scheme.HandlerType == typeof(OpenIddictServerHandler)); + } + } +} diff --git a/test/OpenIddict.Validation.Tests/OpenIddictValidationBuilderTests.cs b/test/OpenIddict.Validation.Tests/OpenIddictValidationBuilderTests.cs index 734d3151..e1738ff5 100644 --- a/test/OpenIddict.Validation.Tests/OpenIddictValidationBuilderTests.cs +++ b/test/OpenIddict.Validation.Tests/OpenIddictValidationBuilderTests.cs @@ -17,6 +17,18 @@ namespace OpenIddict.Validation.Tests { public class OpenIddictValidationBuilderTests { + [Fact] + public void Constructor_ThrowsAnExceptionForNullServices() + { + // Arrange + var services = (IServiceCollection) null; + + // Act and assert + var exception = Assert.Throws(() => new OpenIddictValidationBuilder(services)); + + Assert.Equal("services", exception.ParamName); + } + [Fact] public void AddEventHandler_HandlerIsAttached() { diff --git a/test/OpenIddict.Validation.Tests/OpenIddictValidationExtensionsTests.cs b/test/OpenIddict.Validation.Tests/OpenIddictValidationExtensionsTests.cs new file mode 100644 index 00000000..eb016079 --- /dev/null +++ b/test/OpenIddict.Validation.Tests/OpenIddictValidationExtensionsTests.cs @@ -0,0 +1,169 @@ +/* + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * See https://github.com/openiddict/openiddict-core for more information concerning + * the license and the contributors participating to this project. + */ + +using System; +using AspNet.Security.OAuth.Validation; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Xunit; + +namespace OpenIddict.Validation.Tests +{ + public class OpenIddictValidationExtensionsTests + { + [Fact] + public void AddValidation_ThrowsAnExceptionForNullBuilder() + { + // Arrange + var builder = (OpenIddictBuilder) null; + + // Act and assert + var exception = Assert.Throws(() => builder.AddValidation()); + + Assert.Equal("builder", exception.ParamName); + } + + [Fact] + public void AddValidation_ThrowsAnExceptionForNullConfiguration() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.AddValidation(configuration: null)); + + Assert.Equal("configuration", exception.ParamName); + } + + [Fact] + public void AddValidation_RegistersAuthenticationServices() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddValidation(); + + // Assert + Assert.Contains(services, service => service.ServiceType == typeof(IAuthenticationService)); + } + + [Fact] + public void AddValidation_RegistersLoggingServices() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddValidation(); + + // Assert + Assert.Contains(services, service => service.ServiceType == typeof(ILogger<>)); + } + + [Fact] + public void AddValidation_RegistersOptionsServices() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddValidation(); + + // Assert + Assert.Contains(services, service => service.ServiceType == typeof(IOptions<>)); + } + + [Fact] + public void AddValidation_RegistersEventService() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddValidation(); + + // Assert + Assert.Contains(services, service => service.Lifetime == ServiceLifetime.Scoped && + service.ServiceType == typeof(IOpenIddictValidationEventService) && + service.ImplementationType == typeof(OpenIddictValidationEventService)); + } + + [Fact] + public void AddValidation_RegistersHandler() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddValidation(); + + // Assert + Assert.Contains(services, service => service.Lifetime == ServiceLifetime.Scoped && + service.ServiceType == typeof(OpenIddictValidationHandler) && + service.ImplementationType == typeof(OpenIddictValidationHandler)); + } + + [Fact] + public void AddValidation_RegistersProvider() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddValidation(); + + // Assert + Assert.Contains(services, service => service.Lifetime == ServiceLifetime.Scoped && + service.ServiceType == typeof(OpenIddictValidationProvider) && + service.ImplementationType == typeof(OpenIddictValidationProvider)); + } + + [Theory] + [InlineData(typeof(IPostConfigureOptions), typeof(OpenIddictValidationInitializer))] + [InlineData(typeof(IPostConfigureOptions), typeof(OAuthValidationInitializer))] + public void AddValidation_RegistersInitializers(Type serviceType, Type implementationType) + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddValidation(); + + // Assert + Assert.Contains(services, service => service.ServiceType == serviceType && + service.ImplementationType == implementationType); + } + + [Fact] + public void AddValidation_RegistersAuthenticationScheme() + { + // Arrange + var services = new ServiceCollection(); + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddValidation(); + + // Assert + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>().Value; + + Assert.Contains(options.Schemes, scheme => scheme.Name == OpenIddictValidationDefaults.AuthenticationScheme && + scheme.HandlerType == typeof(OpenIddictValidationHandler)); + } + } +}