From 0166c69578a23537913e9063bafd2204d9ad7c7f Mon Sep 17 00:00:00 2001 From: remcolam Date: Fri, 26 Apr 2024 13:02:30 +0200 Subject: [PATCH] Allow filter instance reuse (#2839) - Add methods to support filter instance re-use. - Fix CI on macOS 14. Resolves #2765. --- .github/workflows/build.yml | 7 + Directory.Packages.props | 1 + .../ConfigureSchemaGeneratorOptions.cs | 10 +- .../ConfigureSwaggerGeneratorOptions.cs | 14 +- .../DependencyInjection/SwaggerGenOptions.cs | 2 + .../SwaggerGenOptionsExtensions.cs | 110 +++++++++- .../Properties/AssemblyInfo.cs | 3 - .../Swashbuckle.AspNetCore.SwaggerGen.csproj | 7 +- ...shbuckle.AspNetCore.ApiTesting.Test.csproj | 2 +- ...hbuckle.AspNetCore.IntegrationTests.csproj | 2 +- ...washbuckle.AspNetCore.IntegrationTests.snk | Bin 596 -> 0 bytes .../NewtonsoftSchemaGeneratorTests.cs | 4 +- .../ConfigureSchemaGeneratorOptionsTests.cs | 48 ++++- .../ConfigureSwaggerGeneratorOptionsTests.cs | 195 +++++++++++++++++- ...shbuckle.AspNetCore.SwaggerGen.Test.csproj | 3 + .../Swashbuckle.AspNetCore.TestSupport.csproj | 2 + 16 files changed, 383 insertions(+), 27 deletions(-) delete mode 100644 src/Swashbuckle.AspNetCore.SwaggerGen/Properties/AssemblyInfo.cs delete mode 100644 test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.snk diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 098d7ef25..e6f6ce731 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,6 +41,13 @@ jobs: - name: Checkout code uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - name: Setup .NET SDKs + uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0 + with: + dotnet-version: | + 6.0.x + 7.0.x + - name: Setup .NET SDK uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0 id: setup-dotnet diff --git a/Directory.Packages.props b/Directory.Packages.props index 75c6e8db9..99b2b5f33 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -22,6 +22,7 @@ + diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSchemaGeneratorOptions.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSchemaGeneratorOptions.cs index 565811584..723e1e12a 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSchemaGeneratorOptions.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSchemaGeneratorOptions.cs @@ -25,7 +25,7 @@ public void Configure(SchemaGeneratorOptions options) // Create and add any filters that were specified through the FilterDescriptor lists _swaggerGenOptions.SchemaFilterDescriptors.ForEach( - filterDescriptor => options.SchemaFilters.Add(CreateFilter(filterDescriptor))); + filterDescriptor => options.SchemaFilters.Add(GetOrCreateFilter(filterDescriptor))); } private void DeepCopy(SchemaGeneratorOptions source, SchemaGeneratorOptions target) @@ -44,10 +44,10 @@ private void DeepCopy(SchemaGeneratorOptions source, SchemaGeneratorOptions targ target.SchemaFilters = new List(source.SchemaFilters); } - private TFilter CreateFilter(FilterDescriptor filterDescriptor) + private TFilter GetOrCreateFilter(FilterDescriptor filterDescriptor) { - return (TFilter)ActivatorUtilities - .CreateInstance(_serviceProvider, filterDescriptor.Type, filterDescriptor.Arguments); + return (TFilter)(filterDescriptor.FilterInstance + ?? ActivatorUtilities.CreateInstance(_serviceProvider, filterDescriptor.Type, filterDescriptor.Arguments)); } } -} \ No newline at end of file +} diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSwaggerGeneratorOptions.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSwaggerGeneratorOptions.cs index 72744ed5c..fce2c752b 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSwaggerGeneratorOptions.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSwaggerGeneratorOptions.cs @@ -35,16 +35,16 @@ public void Configure(SwaggerGeneratorOptions options) // Create and add any filters that were specified through the FilterDescriptor lists ... _swaggerGenOptions.ParameterFilterDescriptors.ForEach( - filterDescriptor => options.ParameterFilters.Add(CreateFilter(filterDescriptor))); + filterDescriptor => options.ParameterFilters.Add(GetOrCreateFilter(filterDescriptor))); _swaggerGenOptions.RequestBodyFilterDescriptors.ForEach( - filterDescriptor => options.RequestBodyFilters.Add(CreateFilter(filterDescriptor))); + filterDescriptor => options.RequestBodyFilters.Add(GetOrCreateFilter(filterDescriptor))); _swaggerGenOptions.OperationFilterDescriptors.ForEach( - filterDescriptor => options.OperationFilters.Add(CreateFilter(filterDescriptor))); + filterDescriptor => options.OperationFilters.Add(GetOrCreateFilter(filterDescriptor))); _swaggerGenOptions.DocumentFilterDescriptors.ForEach( - filterDescriptor => options.DocumentFilters.Add(CreateFilter(filterDescriptor))); + filterDescriptor => options.DocumentFilters.Add(GetOrCreateFilter(filterDescriptor))); if (!options.SwaggerDocs.Any()) { @@ -74,10 +74,10 @@ public void DeepCopy(SwaggerGeneratorOptions source, SwaggerGeneratorOptions tar target.SecuritySchemesSelector = source.SecuritySchemesSelector; } - private TFilter CreateFilter(FilterDescriptor filterDescriptor) + private TFilter GetOrCreateFilter(FilterDescriptor filterDescriptor) { - return (TFilter)ActivatorUtilities - .CreateInstance(_serviceProvider, filterDescriptor.Type, filterDescriptor.Arguments); + return (TFilter)(filterDescriptor.FilterInstance + ?? ActivatorUtilities.CreateInstance(_serviceProvider, filterDescriptor.Type, filterDescriptor.Arguments)); } } } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptions.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptions.cs index af02a9201..edf5e9b32 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptions.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptions.cs @@ -30,5 +30,7 @@ public class FilterDescriptor public Type Type { get; set; } public object[] Arguments { get; set; } + + public object FilterInstance { get; set; } } } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptionsExtensions.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptionsExtensions.cs index e03819bea..92aa46629 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptionsExtensions.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptionsExtensions.cs @@ -328,7 +328,7 @@ public static void SupportNonNullableReferenceTypes(this SwaggerGenOptions swagg /// /// Extend the Swagger Generator with "filters" that can modify Schemas after they're initially generated /// - /// A type that derives from ISchemaFilter + /// A type that derives from /// /// Optionally inject parameters through filter constructors public static void SchemaFilter( @@ -336,6 +336,7 @@ public static void SupportNonNullableReferenceTypes(this SwaggerGenOptions swagg params object[] arguments) where TFilter : ISchemaFilter { + if (swaggerGenOptions == null) throw new ArgumentNullException(nameof(swaggerGenOptions)); swaggerGenOptions.SchemaFilterDescriptors.Add(new FilterDescriptor { Type = typeof(TFilter), @@ -343,10 +344,29 @@ public static void SupportNonNullableReferenceTypes(this SwaggerGenOptions swagg }); } + /// + /// Extend the Swagger Generator with "filters" that can modify Schemas after they're initially generated + /// + /// A type that derives from + /// + /// The filter instance to use. + public static void AddSchemaFilterInstance( + this SwaggerGenOptions swaggerGenOptions, + TFilter filterInstance) + where TFilter : ISchemaFilter + { + if (swaggerGenOptions == null) throw new ArgumentNullException(nameof(swaggerGenOptions)); + if (filterInstance == null) throw new ArgumentNullException(nameof(filterInstance)); + swaggerGenOptions.SchemaFilterDescriptors.Add(new FilterDescriptor + { + FilterInstance = filterInstance + }); + } + /// /// Extend the Swagger Generator with "filters" that can modify Parameters after they're initially generated /// - /// A type that derives from IParameterFilter + /// A type that derives from /// /// Optionally inject parameters through filter constructors public static void ParameterFilter( @@ -354,6 +374,7 @@ public static void SupportNonNullableReferenceTypes(this SwaggerGenOptions swagg params object[] arguments) where TFilter : IParameterFilter { + if (swaggerGenOptions == null) throw new ArgumentNullException(nameof(swaggerGenOptions)); swaggerGenOptions.ParameterFilterDescriptors.Add(new FilterDescriptor { Type = typeof(TFilter), @@ -361,10 +382,29 @@ public static void SupportNonNullableReferenceTypes(this SwaggerGenOptions swagg }); } + /// + /// Extend the Swagger Generator with "filters" that can modify Parameters after they're initially generated + /// + /// A type that derives from + /// + /// The filter instance to use. + public static void AddParameterFilterInstance( + this SwaggerGenOptions swaggerGenOptions, + TFilter filterInstance) + where TFilter : IParameterFilter + { + if (swaggerGenOptions == null) throw new ArgumentNullException(nameof(swaggerGenOptions)); + if (filterInstance == null) throw new ArgumentNullException(nameof(filterInstance)); + swaggerGenOptions.ParameterFilterDescriptors.Add(new FilterDescriptor + { + FilterInstance = filterInstance + }); + } + /// /// Extend the Swagger Generator with "filters" that can modify RequestBodys after they're initially generated /// - /// A type that derives from IRequestBodyFilter + /// A type that derives from /// /// Optionally inject parameters through filter constructors public static void RequestBodyFilter( @@ -372,6 +412,7 @@ public static void SupportNonNullableReferenceTypes(this SwaggerGenOptions swagg params object[] arguments) where TFilter : IRequestBodyFilter { + if (swaggerGenOptions == null) throw new ArgumentNullException(nameof(swaggerGenOptions)); swaggerGenOptions.RequestBodyFilterDescriptors.Add(new FilterDescriptor { Type = typeof(TFilter), @@ -379,10 +420,29 @@ public static void SupportNonNullableReferenceTypes(this SwaggerGenOptions swagg }); } + /// + /// Extend the Swagger Generator with "filters" that can modify RequestBodys after they're initially generated + /// + /// A type that derives from + /// + /// The filter instance to use. + public static void AddRequestBodyFilterInstance( + this SwaggerGenOptions swaggerGenOptions, + TFilter filterInstance) + where TFilter : IRequestBodyFilter + { + if (swaggerGenOptions == null) throw new ArgumentNullException(nameof(swaggerGenOptions)); + if (filterInstance == null) throw new ArgumentNullException(nameof(filterInstance)); + swaggerGenOptions.RequestBodyFilterDescriptors.Add(new FilterDescriptor + { + FilterInstance = filterInstance + }); + } + /// /// Extend the Swagger Generator with "filters" that can modify Operations after they're initially generated /// - /// A type that derives from IOperationFilter + /// A type that derives from /// /// Optionally inject parameters through filter constructors public static void OperationFilter( @@ -390,6 +450,7 @@ public static void SupportNonNullableReferenceTypes(this SwaggerGenOptions swagg params object[] arguments) where TFilter : IOperationFilter { + if (swaggerGenOptions == null) throw new ArgumentNullException(nameof(swaggerGenOptions)); swaggerGenOptions.OperationFilterDescriptors.Add(new FilterDescriptor { Type = typeof(TFilter), @@ -397,10 +458,29 @@ public static void SupportNonNullableReferenceTypes(this SwaggerGenOptions swagg }); } + /// + /// Extend the Swagger Generator with "filters" that can modify Operations after they're initially generated + /// + /// A type that derives from + /// + /// The filter instance to use. + public static void AddOperationFilterInstance( + this SwaggerGenOptions swaggerGenOptions, + TFilter filterInstance) + where TFilter : IOperationFilter + { + if (swaggerGenOptions == null) throw new ArgumentNullException(nameof(swaggerGenOptions)); + if (filterInstance == null) throw new ArgumentNullException(nameof(filterInstance)); + swaggerGenOptions.OperationFilterDescriptors.Add(new FilterDescriptor + { + FilterInstance = filterInstance + }); + } + /// /// Extend the Swagger Generator with "filters" that can modify SwaggerDocuments after they're initially generated /// - /// A type that derives from IDocumentFilter + /// A type that derives from /// /// Optionally inject parameters through filter constructors public static void DocumentFilter( @@ -408,6 +488,7 @@ public static void SupportNonNullableReferenceTypes(this SwaggerGenOptions swagg params object[] arguments) where TFilter : IDocumentFilter { + if (swaggerGenOptions == null) throw new ArgumentNullException(nameof(swaggerGenOptions)); swaggerGenOptions.DocumentFilterDescriptors.Add(new FilterDescriptor { Type = typeof(TFilter), @@ -415,6 +496,25 @@ public static void SupportNonNullableReferenceTypes(this SwaggerGenOptions swagg }); } + /// + /// Extend the Swagger Generator with "filters" that can modify SwaggerDocuments after they're initially generated + /// + /// A type that derives from + /// + /// The filter instance to use. + public static void AddDocumentFilterInstance( + this SwaggerGenOptions swaggerGenOptions, + TFilter filterInstance) + where TFilter : IDocumentFilter + { + if (swaggerGenOptions == null) throw new ArgumentNullException(nameof(swaggerGenOptions)); + if (filterInstance == null) throw new ArgumentNullException(nameof(filterInstance)); + swaggerGenOptions.DocumentFilterDescriptors.Add(new FilterDescriptor + { + FilterInstance = filterInstance + }); + } + /// /// Inject human-friendly descriptions for Operations, Parameters and Schemas based on XML Comment files /// diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/Properties/AssemblyInfo.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/Properties/AssemblyInfo.cs deleted file mode 100644 index 3469cd4c8..000000000 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,3 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("Swashbuckle.AspNetCore.IntegrationTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100795482b2b019ad690196ad34ca1d13abb1c3ed0e24fdaea1ca82ca11462a2d883e149864773aada8b40f41c1b1ea7824f23fb569cfc20e9fd03763896a2905fa23e1a62a940d40d14e3107e8cf90f6d705848e39fe25121a7f8c1cd5dcd6701aea982d13c4a42b3a0766dfc27fc02fa40194ed0a7841a8768d33f7aaabde87a7")] diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/Swashbuckle.AspNetCore.SwaggerGen.csproj b/src/Swashbuckle.AspNetCore.SwaggerGen/Swashbuckle.AspNetCore.SwaggerGen.csproj index 6ca886944..b1c83aec8 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/Swashbuckle.AspNetCore.SwaggerGen.csproj +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/Swashbuckle.AspNetCore.SwaggerGen.csproj @@ -10,12 +10,17 @@ netstandard2.0;netcoreapp3.0;net5.0;net6.0;net7.0 + + + + + - + diff --git a/test/Swashbuckle.AspNetCore.ApiTesting.Test/Swashbuckle.AspNetCore.ApiTesting.Test.csproj b/test/Swashbuckle.AspNetCore.ApiTesting.Test/Swashbuckle.AspNetCore.ApiTesting.Test.csproj index 8bd159a0b..8d7539a5a 100644 --- a/test/Swashbuckle.AspNetCore.ApiTesting.Test/Swashbuckle.AspNetCore.ApiTesting.Test.csproj +++ b/test/Swashbuckle.AspNetCore.ApiTesting.Test/Swashbuckle.AspNetCore.ApiTesting.Test.csproj @@ -5,7 +5,7 @@ - + diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.csproj b/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.csproj index 14cfb486f..e2012d92a 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.csproj +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.csproj @@ -1,7 +1,7 @@ - Swashbuckle.AspNetCore.IntegrationTests.snk + $(MSBuildThisFileDirectory)..\..\src\Swashbuckle.AspNetCore.Swagger\Swashbuckle.AspNetCore.Swagger.snk $(NoWarn);8002 true net6.0 diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.snk b/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.snk deleted file mode 100644 index bef10bbfca87a89cedad26a28517ddee53698e2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50097bRD!aw8LepnmaR0(9TTgu!|e_v{jQ

UbpbKecJk!VaI%H)DxvDFyl?;if8-4M5ROF$d_+ zkoMOFgpN7>B@!Bcj2zY6)^Hl?m@N~;q$@fHX5Yepz%Qf$lkaFUk}P;>XYcI!q)$N>WI2+i1~OgPSQ{F5OIhbe^buB%=1tc5tFk!u-7KE+76F z>rs|$0+a(l*1VUWjmnq1@RnYP1%BGlfwVKCrNnEbb@EK@_@E@t?rz;tfW~H_Wm>}# zx~>76M!P@PY#US`hs0~r%<_zbm%pbB8f)48A#~s=%frb8bjK{A-Sniq^-!|1ZAmlG ziqgz4>M;IF5GDA1=YDH6c8Nw!Z2~oR1Q+D)jIInFdg)Xhf1VcKT88`8+xd^V8+?m6 zz|JSp=1O_>LKKgfeqj?twrD8izSz_ahO$OFDi}mB3@whSTI|1BwvG~C>;k;-_=dM& zBm^n~WNsatUC_vP5Dv4>mTJ}|bYk6%y;-TVQjCpVIpK=YP{`nKM?9H6Ith(=wgR+M id?C`E$KLVH(); + webhostingEnvironment.ApplicationName.Returns("Swashbuckle.AspNetCore.SwaggerGen.Test"); + + var testSchemaFilter = new TestSchemaFilter(); + + var options = new SwaggerGenOptions(); + options.AddSchemaFilterInstance(testSchemaFilter); + options.AddSchemaFilterInstance(testSchemaFilter); + + var configureSchemaGeneratorOptions = new ConfigureSchemaGeneratorOptions(Options.Create(options), null); + var schemaGeneratorOptions = new SchemaGeneratorOptions(); + + configureSchemaGeneratorOptions.Configure(schemaGeneratorOptions); + + Assert.Equal(2, schemaGeneratorOptions.SchemaFilters.Count); + Assert.Same(testSchemaFilter, schemaGeneratorOptions.SchemaFilters.First()); + Assert.Same(testSchemaFilter, schemaGeneratorOptions.SchemaFilters.Last()); + } + + [Fact] + public static void AddingSchemaFilterTypes_WhenConfiguringOptions_DifferentInstancesAreAdded() + { + var webhostingEnvironment = Substitute.For(); + webhostingEnvironment.ApplicationName.Returns("Swashbuckle.AspNetCore.SwaggerGen.Test"); + + var options = new SwaggerGenOptions(); + options.SchemaFilter(); + options.SchemaFilter(); + + var configureSchemaGeneratorOptions = new ConfigureSchemaGeneratorOptions(Options.Create(options), null); + var schemaGeneratorOptions = new SchemaGeneratorOptions(); + + configureSchemaGeneratorOptions.Configure(schemaGeneratorOptions); + + Assert.Equal(2, schemaGeneratorOptions.SchemaFilters.Count); + Assert.NotSame(schemaGeneratorOptions.SchemaFilters.First(), schemaGeneratorOptions.SchemaFilters.Last()); + } } diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/ConfigureSwaggerGeneratorOptionsTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/ConfigureSwaggerGeneratorOptionsTests.cs index 39d3f4085..ca6a1c809 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/ConfigureSwaggerGeneratorOptionsTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/ConfigureSwaggerGeneratorOptionsTests.cs @@ -1,4 +1,9 @@ -using System.Reflection; +using System.Linq; +using System.Reflection; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using NSubstitute; using Xunit; namespace Swashbuckle.AspNetCore.SwaggerGen.Test; @@ -15,4 +20,192 @@ public static void DeepCopy_Copies_All_Properties() // to SwaggerGeneratorOptions and ConfigureSwaggerGeneratorOptions.DeepCopy() needs to be updated Assert.Equal(18, publicProperties.Length); } + + [Fact] + public static void AddingParameterFilterInstances_WhenConfiguringOptions_SameInstanceIsAdded() + { + var webhostingEnvironment = Substitute.For(); + webhostingEnvironment.ApplicationName.Returns("Swashbuckle.AspNetCore.SwaggerGen.Test"); + + var testParameterFilter = new TestParameterFilter(); + + var options = new SwaggerGenOptions(); + options.AddParameterFilterInstance(testParameterFilter); + options.AddParameterFilterInstance(testParameterFilter); + + var configureSwaggerGeneratorOptions = new ConfigureSwaggerGeneratorOptions( + Options.Create(options), + null, + webhostingEnvironment); + var swaggerGeneratorOptions = new SwaggerGeneratorOptions(); + + configureSwaggerGeneratorOptions.Configure(swaggerGeneratorOptions); + + Assert.Equal(2, swaggerGeneratorOptions.ParameterFilters.Count); + Assert.Same(testParameterFilter, swaggerGeneratorOptions.ParameterFilters.First()); + Assert.Same(testParameterFilter, swaggerGeneratorOptions.ParameterFilters.Last()); + } + + [Fact] + public static void AddingParameterFilterTypes_WhenConfiguringOptions_DifferentInstancesAreAdded() + { + var webhostingEnvironment = Substitute.For(); + webhostingEnvironment.ApplicationName.Returns("Swashbuckle.AspNetCore.SwaggerGen.Test"); + + var options = new SwaggerGenOptions(); + options.ParameterFilter(); + options.ParameterFilter(); + + var configureSwaggerGeneratorOptions = new ConfigureSwaggerGeneratorOptions( + Options.Create(options), + null, + webhostingEnvironment); + var swaggerGeneratorOptions = new SwaggerGeneratorOptions(); + + configureSwaggerGeneratorOptions.Configure(swaggerGeneratorOptions); + + Assert.Equal(2, swaggerGeneratorOptions.ParameterFilters.Count); + Assert.NotSame(swaggerGeneratorOptions.ParameterFilters.First(), swaggerGeneratorOptions.ParameterFilters.Last()); + } + + [Fact] + public static void AddingRequestBodyFilterInstances_WhenConfiguringOptions_SameInstanceIsAdded() + { + var webhostingEnvironment = Substitute.For(); + webhostingEnvironment.ApplicationName.Returns("Swashbuckle.AspNetCore.SwaggerGen.Test"); + + var testRequestBodyFilter = new TestRequestBodyFilter(); + + var options = new SwaggerGenOptions(); + options.AddRequestBodyFilterInstance(testRequestBodyFilter); + options.AddRequestBodyFilterInstance(testRequestBodyFilter); + + var configureSwaggerGeneratorOptions = new ConfigureSwaggerGeneratorOptions( + Options.Create(options), + null, + webhostingEnvironment); + var swaggerGeneratorOptions = new SwaggerGeneratorOptions(); + + configureSwaggerGeneratorOptions.Configure(swaggerGeneratorOptions); + + Assert.Equal(2, swaggerGeneratorOptions.RequestBodyFilters.Count); + Assert.Same(testRequestBodyFilter, swaggerGeneratorOptions.RequestBodyFilters.First()); + Assert.Same(testRequestBodyFilter, swaggerGeneratorOptions.RequestBodyFilters.Last()); + } + + [Fact] + public static void AddingRequestBodyFilterTypes_WhenConfiguringOptions_DifferentInstancesAreAdded() + { + var webhostingEnvironment = Substitute.For(); + webhostingEnvironment.ApplicationName.Returns("Swashbuckle.AspNetCore.SwaggerGen.Test"); + + var options = new SwaggerGenOptions(); + options.RequestBodyFilter(); + options.RequestBodyFilter(); + + var configureSwaggerGeneratorOptions = new ConfigureSwaggerGeneratorOptions( + Options.Create(options), + null, + webhostingEnvironment); + var swaggerGeneratorOptions = new SwaggerGeneratorOptions(); + + configureSwaggerGeneratorOptions.Configure(swaggerGeneratorOptions); + + Assert.Equal(2, swaggerGeneratorOptions.RequestBodyFilters.Count); + Assert.NotSame(swaggerGeneratorOptions.RequestBodyFilters.First(), swaggerGeneratorOptions.RequestBodyFilters.Last()); + } + + [Fact] + public static void AddingOperationFilterInstances_WhenConfiguringOptions_SameInstanceIsAdded() + { + var webhostingEnvironment = Substitute.For(); + webhostingEnvironment.ApplicationName.Returns("Swashbuckle.AspNetCore.SwaggerGen.Test"); + + var testOperationFilter = new TestOperationFilter(); + + var options = new SwaggerGenOptions(); + options.AddOperationFilterInstance(testOperationFilter); + options.AddOperationFilterInstance(testOperationFilter); + + var configureSwaggerGeneratorOptions = new ConfigureSwaggerGeneratorOptions( + Options.Create(options), + null, + webhostingEnvironment); + var swaggerGeneratorOptions = new SwaggerGeneratorOptions(); + + configureSwaggerGeneratorOptions.Configure(swaggerGeneratorOptions); + + Assert.Equal(2, swaggerGeneratorOptions.OperationFilters.Count); + Assert.Same(testOperationFilter, swaggerGeneratorOptions.OperationFilters.First()); + Assert.Same(testOperationFilter, swaggerGeneratorOptions.OperationFilters.Last()); + } + + [Fact] + public static void AddingOperationFilterTypes_WhenConfiguringOptions_DifferentInstancesAreAdded() + { + var webhostingEnvironment = Substitute.For(); + webhostingEnvironment.ApplicationName.Returns("Swashbuckle.AspNetCore.SwaggerGen.Test"); + + var options = new SwaggerGenOptions(); + options.OperationFilter(); + options.OperationFilter(); + + var configureSwaggerGeneratorOptions = new ConfigureSwaggerGeneratorOptions( + Options.Create(options), + null, + webhostingEnvironment); + var swaggerGeneratorOptions = new SwaggerGeneratorOptions(); + + configureSwaggerGeneratorOptions.Configure(swaggerGeneratorOptions); + + Assert.Equal(2, swaggerGeneratorOptions.OperationFilters.Count); + Assert.NotSame(swaggerGeneratorOptions.OperationFilters.First(), swaggerGeneratorOptions.OperationFilters.Last()); + } + + [Fact] + public static void AddingDocumentFilterInstances_WhenConfiguringOptions_SameInstanceIsAdded() + { + var webhostingEnvironment = Substitute.For(); + webhostingEnvironment.ApplicationName.Returns("Swashbuckle.AspNetCore.SwaggerGen.Test"); + + var testDocumentFilter = new TestDocumentFilter(); + + var options = new SwaggerGenOptions(); + options.AddDocumentFilterInstance(testDocumentFilter); + options.AddDocumentFilterInstance(testDocumentFilter); + + var configureSwaggerGeneratorOptions = new ConfigureSwaggerGeneratorOptions( + Options.Create(options), + null, + webhostingEnvironment); + var swaggerGeneratorOptions = new SwaggerGeneratorOptions(); + + configureSwaggerGeneratorOptions.Configure(swaggerGeneratorOptions); + + Assert.Equal(2, swaggerGeneratorOptions.DocumentFilters.Count); + Assert.Same(testDocumentFilter, swaggerGeneratorOptions.DocumentFilters.First()); + Assert.Same(testDocumentFilter, swaggerGeneratorOptions.DocumentFilters.Last()); + } + + [Fact] + public static void AddingDocumentFilterTypes_WhenConfiguringOptions_DifferentInstancesAreAdded() + { + var webhostingEnvironment = Substitute.For(); + webhostingEnvironment.ApplicationName.Returns("Swashbuckle.AspNetCore.SwaggerGen.Test"); + + var options = new SwaggerGenOptions(); + options.DocumentFilter(); + options.DocumentFilter(); + + var configureSwaggerGeneratorOptions = new ConfigureSwaggerGeneratorOptions( + Options.Create(options), + null, + webhostingEnvironment); + var swaggerGeneratorOptions = new SwaggerGeneratorOptions(); + + configureSwaggerGeneratorOptions.Configure(swaggerGeneratorOptions); + + Assert.Equal(2, swaggerGeneratorOptions.DocumentFilters.Count); + Assert.NotSame(swaggerGeneratorOptions.DocumentFilters.First(), swaggerGeneratorOptions.DocumentFilters.Last()); + } } diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.csproj b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.csproj index 0cb9c4236..6380c5ae5 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.csproj +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.csproj @@ -4,6 +4,8 @@ true 1701;1702;1591 net6.0;net7.0 + True + $(MSBuildThisFileDirectory)..\..\src\Swashbuckle.AspNetCore.Swagger\Swashbuckle.AspNetCore.Swagger.snk @@ -14,6 +16,7 @@ + diff --git a/test/Swashbuckle.AspNetCore.TestSupport/Swashbuckle.AspNetCore.TestSupport.csproj b/test/Swashbuckle.AspNetCore.TestSupport/Swashbuckle.AspNetCore.TestSupport.csproj index befe7167b..f29366bf0 100644 --- a/test/Swashbuckle.AspNetCore.TestSupport/Swashbuckle.AspNetCore.TestSupport.csproj +++ b/test/Swashbuckle.AspNetCore.TestSupport/Swashbuckle.AspNetCore.TestSupport.csproj @@ -6,6 +6,8 @@ false 1.0.0 + True + $(MSBuildThisFileDirectory)..\..\src\Swashbuckle.AspNetCore.Swagger\Swashbuckle.AspNetCore.Swagger.snk